X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;ds=sidebyside;f=src%2Fmain%2Fjava%2Fnet%2Fpterodactylus%2Fsone%2Fcore%2FCore.java;h=ea36aad76bf88c22ff6376495271d050c5133f61;hb=bb2c8cb2d47a77bcef2d299ad4bf8e16f22a6198;hp=005524e5c59c439d84460e3469e1aa18368f3475;hpb=b12d6fde532f888d166ad1598d448b88530051b4;p=Sone.git
diff --git a/src/main/java/net/pterodactylus/sone/core/Core.java b/src/main/java/net/pterodactylus/sone/core/Core.java
index 005524e..ea36aad 100644
--- a/src/main/java/net/pterodactylus/sone/core/Core.java
+++ b/src/main/java/net/pterodactylus/sone/core/Core.java
@@ -25,6 +25,9 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.Map.Entry;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -37,6 +40,8 @@ import net.pterodactylus.sone.data.Profile;
import net.pterodactylus.sone.data.Profile.Field;
import net.pterodactylus.sone.data.Reply;
import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.sone.fcp.FcpInterface;
+import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired;
import net.pterodactylus.sone.freenet.wot.Identity;
import net.pterodactylus.sone.freenet.wot.IdentityListener;
import net.pterodactylus.sone.freenet.wot.IdentityManager;
@@ -48,6 +53,10 @@ import net.pterodactylus.util.config.Configuration;
import net.pterodactylus.util.config.ConfigurationException;
import net.pterodactylus.util.logging.Logging;
import net.pterodactylus.util.number.Numbers;
+import net.pterodactylus.util.thread.Ticker;
+import net.pterodactylus.util.validation.EqualityValidator;
+import net.pterodactylus.util.validation.IntegerRangeValidator;
+import net.pterodactylus.util.validation.OrValidator;
import net.pterodactylus.util.validation.Validation;
import net.pterodactylus.util.version.Version;
import freenet.keys.FreenetURI;
@@ -57,7 +66,7 @@ import freenet.keys.FreenetURI;
*
* @author David âBombeâ Roden
*/
-public class Core implements IdentityListener, UpdateListener {
+public class Core implements IdentityListener, UpdateListener, SoneProvider, PostProvider {
/**
* Enumeration for the possible states of a {@link Sone}.
@@ -106,10 +115,17 @@ public class Core implements IdentityListener, UpdateListener {
/** The Sone downloader. */
private final SoneDownloader soneDownloader;
+ /** Sone downloader thread-pool. */
+ private final ExecutorService soneDownloaders = Executors.newFixedThreadPool(10);
+
/** The update checker. */
private final UpdateChecker updateChecker;
+ /** The FCP interface. */
+ private volatile FcpInterface fcpInterface;
+
/** Whether the core has been stopped. */
+ @SuppressWarnings("unused")
private volatile boolean stopped;
/** The Sonesâ statuses. */
@@ -124,6 +140,10 @@ public class Core implements IdentityListener, UpdateListener {
/* synchronize access on this on localSones. */
private final Map soneInserters = new HashMap();
+ /** Sone rescuers. */
+ /* synchronize access on this on localSones. */
+ private final Map soneRescuers = new HashMap();
+
/** All local Sones. */
/* synchronize access on this on itself. */
private Map localSones = new HashMap();
@@ -165,6 +185,9 @@ public class Core implements IdentityListener, UpdateListener {
/** Trusted identities, sorted by own identities. */
private Map> trustedIdentities = Collections.synchronizedMap(new HashMap>());
+ /** Ticker for threads that mark own elements as known. */
+ private Ticker localElementTicker = new Ticker();
+
/**
* Creates a new core.
*
@@ -251,6 +274,16 @@ public class Core implements IdentityListener, UpdateListener {
}
/**
+ * Sets the FCP interface to use.
+ *
+ * @param fcpInterface
+ * The FCP interface to use
+ */
+ public void setFcpInterface(FcpInterface fcpInterface) {
+ this.fcpInterface = fcpInterface;
+ }
+
+ /**
* Returns the status of the given Sone.
*
* @param sone
@@ -278,6 +311,26 @@ public class Core implements IdentityListener, UpdateListener {
}
/**
+ * Returns the Sone rescuer for the given local Sone.
+ *
+ * @param sone
+ * The local Sone to get the rescuer for
+ * @return The Sone rescuer for the given Sone
+ */
+ public SoneRescuer getSoneRescuer(Sone sone) {
+ Validation.begin().isNotNull("Sone", sone).check().is("Local Sone", isLocalSone(sone)).check();
+ synchronized (localSones) {
+ SoneRescuer soneRescuer = soneRescuers.get(sone);
+ if (soneRescuer == null) {
+ soneRescuer = new SoneRescuer(this, soneDownloader, sone);
+ soneRescuers.put(sone, soneRescuer);
+ soneRescuer.start();
+ }
+ return soneRescuer;
+ }
+ }
+
+ /**
* Returns whether the given Sone is currently locked.
*
* @param sone
@@ -328,6 +381,7 @@ public class Core implements IdentityListener, UpdateListener {
* @return The Sone with the given ID, or {@code null} if there is no such
* Sone
*/
+ @Override
public Sone getSone(String id, boolean create) {
if (isLocalSone(id)) {
return getLocalSone(id);
@@ -550,6 +604,7 @@ public class Core implements IdentityListener, UpdateListener {
* exists, {@code false} to return {@code null}
* @return The post, or {@code null} if there is no such post
*/
+ @Override
public Post getPost(String postId, boolean create) {
synchronized (posts) {
Post post = posts.get(postId);
@@ -576,6 +631,27 @@ public class Core implements IdentityListener, UpdateListener {
}
/**
+ * Returns all posts that have the given Sone as recipient.
+ *
+ * @see Post#getRecipient()
+ * @param recipient
+ * The recipient of the posts
+ * @return All posts that have the given Sone as recipient
+ */
+ public Set getDirectedPosts(Sone recipient) {
+ Validation.begin().isNotNull("Recipient", recipient).check();
+ Set directedPosts = new HashSet();
+ synchronized (posts) {
+ for (Post post : posts.values()) {
+ if (recipient.equals(post.getRecipient())) {
+ directedPosts.add(post);
+ }
+ }
+ }
+ return directedPosts;
+ }
+
+ /**
* Returns the reply with the given ID. If there is no reply with the given
* ID yet, a new one is created.
*
@@ -809,33 +885,7 @@ public class Core implements IdentityListener, UpdateListener {
soneInserters.put(sone, soneInserter);
setSoneStatus(sone, SoneStatus.idle);
loadSone(sone);
- if (!preferences.isSoneRescueMode()) {
- soneInserter.start();
- }
- new Thread(new Runnable() {
-
- @Override
- @SuppressWarnings("synthetic-access")
- public void run() {
- if (!preferences.isSoneRescueMode()) {
- return;
- }
- logger.log(Level.INFO, "Trying to restore Sone from Freenetâ¦");
- coreListenerManager.fireRescuingSone(sone);
- lockSone(sone);
- long edition = sone.getLatestEdition();
- while (!stopped && (edition >= 0) && preferences.isSoneRescueMode()) {
- logger.log(Level.FINE, "Downloading edition " + edition + "â¦");
- soneDownloader.fetchSone(sone, sone.getRequestUri().setKeyType("SSK").setDocName("Sone-" + edition));
- --edition;
- }
- logger.log(Level.INFO, "Finished restoring Sone from Freenet, starting Inserterâ¦");
- saveSone(sone);
- coreListenerManager.fireRescuedSone(sone);
- soneInserter.start();
- }
-
- }, "Sone Downloader").start();
+ soneInserter.start();
return sone;
}
}
@@ -855,6 +905,9 @@ public class Core implements IdentityListener, UpdateListener {
return null;
}
Sone sone = addLocalSone(ownIdentity);
+ sone.getOptions().addBooleanOption("AutoFollow", new DefaultOption(false));
+ sone.addFriend("nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI");
+ saveSone(sone);
return sone;
}
@@ -884,20 +937,26 @@ public class Core implements IdentityListener, UpdateListener {
}
if (newSone) {
coreListenerManager.fireNewSoneFound(sone);
+ for (Sone localSone : getLocalSones()) {
+ if (localSone.getOptions().getBooleanOption("AutoFollow").get()) {
+ localSone.addFriend(sone.getId());
+ saveSone(localSone);
+ }
+ }
}
}
remoteSones.put(identity.getId(), sone);
soneDownloader.addSone(sone);
setSoneStatus(sone, SoneStatus.unknown);
- new Thread(new Runnable() {
+ soneDownloaders.execute(new Runnable() {
@Override
@SuppressWarnings("synthetic-access")
public void run() {
- soneDownloader.fetchSone(sone);
+ soneDownloader.fetchSone(sone, sone.getRequestUri());
}
- }, "Sone Downloader").start();
+ });
return sone;
}
}
@@ -994,14 +1053,28 @@ public class Core implements IdentityListener, UpdateListener {
}
/**
- * Updates the stores Sone with the given Sone.
+ * Updates the stored Sone with the given Sone.
*
* @param sone
* The updated Sone
*/
public void updateSone(Sone sone) {
+ updateSone(sone, false);
+ }
+
+ /**
+ * Updates the stored Sone with the given Sone. If {@code soneRescueMode} is
+ * {@code true}, an older Sone than the current Sone can be given to restore
+ * an old state.
+ *
+ * @param sone
+ * The Sone to update
+ * @param soneRescueMode
+ * {@code true} if the stored Sone should be updated regardless
+ * of the age of the given Sone
+ */
+ public void updateSone(Sone sone, boolean soneRescueMode) {
if (hasSone(sone.getId())) {
- boolean soneRescueMode = isLocalSone(sone) && preferences.isSoneRescueMode();
Sone storedSone = getSone(sone.getId());
if (!soneRescueMode && !(sone.getTime() > storedSone.getTime())) {
logger.log(Level.FINE, "Downloaded Sone %s is not newer than stored Sone %s.", new Object[] { sone, storedSone });
@@ -1143,6 +1216,9 @@ public class Core implements IdentityListener, UpdateListener {
return;
}
+ /* initialize options. */
+ sone.getOptions().addBooleanOption("AutoFollow", new DefaultOption(false));
+
/* load Sone. */
String sonePrefix = "Sone/" + sone.getId();
Long soneTime = configuration.getLongValue(sonePrefix + "/Time").getValue(null);
@@ -1242,6 +1318,9 @@ public class Core implements IdentityListener, UpdateListener {
friends.add(friendId);
}
+ /* load options. */
+ sone.getOptions().getBooleanOption("AutoFollow").set(configuration.getBooleanValue(sonePrefix + "/Options/AutoFollow").getValue(null));
+
/* if weâre still here, Sone was loaded successfully. */
synchronized (sone) {
sone.setTime(soneTime);
@@ -1357,6 +1436,9 @@ public class Core implements IdentityListener, UpdateListener {
}
configuration.getStringValue(sonePrefix + "/Friends/" + friendCounter + "/ID").setValue(null);
+ /* save options. */
+ configuration.getBooleanValue(sonePrefix + "/Options/AutoFollow").setValue(sone.getOptions().getBooleanOption("AutoFollow").getReal());
+
configuration.save();
logger.log(Level.INFO, "Sone %s saved.", sone);
} catch (ConfigurationException ce1) {
@@ -1429,7 +1511,7 @@ public class Core implements IdentityListener, UpdateListener {
logger.log(Level.FINE, "Tried to create post for non-local Sone: %s", sone);
return null;
}
- Post post = new Post(sone, time, text);
+ final Post post = new Post(sone, time, text);
if (recipient != null) {
post.setRecipient(recipient);
}
@@ -1437,10 +1519,21 @@ public class Core implements IdentityListener, UpdateListener {
posts.put(post.getId(), post);
}
synchronized (newPosts) {
- knownPosts.add(post.getId());
+ newPosts.add(post.getId());
+ coreListenerManager.fireNewPostFound(post);
}
sone.addPost(post);
saveSone(sone);
+ localElementTicker.registerEvent(System.currentTimeMillis() + 10 * 1000, new Runnable() {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void run() {
+ markPostKnown(post);
+ }
+ }, "Mark " + post + " read.");
return post;
}
@@ -1459,6 +1552,11 @@ public class Core implements IdentityListener, UpdateListener {
synchronized (posts) {
posts.remove(post.getId());
}
+ coreListenerManager.firePostRemoved(post);
+ synchronized (newPosts) {
+ markPostKnown(post);
+ knownPosts.remove(post.getId());
+ }
saveSone(post.getSone());
}
@@ -1556,15 +1654,26 @@ public class Core implements IdentityListener, UpdateListener {
logger.log(Level.FINE, "Tried to create reply for non-local Sone: %s", sone);
return null;
}
- Reply reply = new Reply(sone, post, System.currentTimeMillis(), text);
+ final Reply reply = new Reply(sone, post, System.currentTimeMillis(), text);
synchronized (replies) {
replies.put(reply.getId(), reply);
}
synchronized (newReplies) {
- knownReplies.add(reply.getId());
+ newReplies.add(reply.getId());
+ coreListenerManager.fireNewReplyFound(reply);
}
sone.addReply(reply);
saveSone(sone);
+ localElementTicker.registerEvent(System.currentTimeMillis() + 10 * 1000, new Runnable() {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void run() {
+ markReplyKnown(reply);
+ }
+ }, "Mark " + reply + " read.");
return reply;
}
@@ -1583,6 +1692,10 @@ public class Core implements IdentityListener, UpdateListener {
synchronized (replies) {
replies.remove(reply.getId());
}
+ synchronized (newReplies) {
+ markReplyKnown(reply);
+ knownReplies.remove(reply.getId());
+ }
sone.removeReply(reply);
saveSone(sone);
}
@@ -1621,6 +1734,9 @@ public class Core implements IdentityListener, UpdateListener {
for (SoneInserter soneInserter : soneInserters.values()) {
soneInserter.stop();
}
+ for (Sone localSone : localSones.values()) {
+ saveSone(localSone);
+ }
}
updateChecker.stop();
updateChecker.removeUpdateListener(this);
@@ -1645,9 +1761,14 @@ public class Core implements IdentityListener, UpdateListener {
try {
configuration.getIntValue("Option/ConfigurationVersion").setValue(0);
configuration.getIntValue("Option/InsertionDelay").setValue(options.getIntegerOption("InsertionDelay").getReal());
+ configuration.getIntValue("Option/PostsPerPage").setValue(options.getIntegerOption("PostsPerPage").getReal());
+ configuration.getIntValue("Option/CharactersPerPost").setValue(options.getIntegerOption("CharactersPerPost").getReal());
+ configuration.getBooleanValue("Option/RequireFullAccess").setValue(options.getBooleanOption("RequireFullAccess").getReal());
configuration.getIntValue("Option/PositiveTrust").setValue(options.getIntegerOption("PositiveTrust").getReal());
configuration.getIntValue("Option/NegativeTrust").setValue(options.getIntegerOption("NegativeTrust").getReal());
configuration.getStringValue("Option/TrustComment").setValue(options.getStringOption("TrustComment").getReal());
+ configuration.getBooleanValue("Option/ActivateFcpInterface").setValue(options.getBooleanOption("ActivateFcpInterface").getReal());
+ configuration.getIntValue("Option/FcpFullAccessRequired").setValue(options.getIntegerOption("FcpFullAccessRequired").getReal());
configuration.getBooleanValue("Option/SoneRescueMode").setValue(options.getBooleanOption("SoneRescueMode").getReal());
configuration.getBooleanValue("Option/ClearOnNextRestart").setValue(options.getBooleanOption("ClearOnNextRestart").getReal());
configuration.getBooleanValue("Option/ReallyClearOnNextRestart").setValue(options.getBooleanOption("ReallyClearOnNextRestart").getReal());
@@ -1710,7 +1831,7 @@ public class Core implements IdentityListener, UpdateListener {
@SuppressWarnings("unchecked")
private void loadConfiguration() {
/* create options. */
- options.addIntegerOption("InsertionDelay", new DefaultOption(60, new OptionWatcher() {
+ options.addIntegerOption("InsertionDelay", new DefaultOption(60, new IntegerRangeValidator(0, Integer.MAX_VALUE), new OptionWatcher() {
@Override
public void optionChanged(Option option, Integer oldValue, Integer newValue) {
@@ -1718,9 +1839,29 @@ public class Core implements IdentityListener, UpdateListener {
}
}));
- options.addIntegerOption("PositiveTrust", new DefaultOption(75));
- options.addIntegerOption("NegativeTrust", new DefaultOption(-25));
+ options.addIntegerOption("PostsPerPage", new DefaultOption(10, new IntegerRangeValidator(1, Integer.MAX_VALUE)));
+ options.addIntegerOption("CharactersPerPost", new DefaultOption(200, new OrValidator(new IntegerRangeValidator(50, Integer.MAX_VALUE), new EqualityValidator(-1))));
+ options.addBooleanOption("RequireFullAccess", new DefaultOption(false));
+ options.addIntegerOption("PositiveTrust", new DefaultOption(75, new IntegerRangeValidator(0, 100)));
+ options.addIntegerOption("NegativeTrust", new DefaultOption(-25, new IntegerRangeValidator(-100, 100)));
options.addStringOption("TrustComment", new DefaultOption("Set from Sone Web Interface"));
+ options.addBooleanOption("ActivateFcpInterface", new DefaultOption(false, new OptionWatcher() {
+
+ @Override
+ @SuppressWarnings("synthetic-access")
+ public void optionChanged(Option option, Boolean oldValue, Boolean newValue) {
+ fcpInterface.setActive(newValue);
+ }
+ }));
+ options.addIntegerOption("FcpFullAccessRequired", new DefaultOption(2, new OptionWatcher() {
+
+ @Override
+ @SuppressWarnings("synthetic-access")
+ public void optionChanged(Option option, Integer oldValue, Integer newValue) {
+ fcpInterface.setFullAccessRequired(FullAccessRequired.values()[newValue]);
+ }
+
+ }));
options.addBooleanOption("SoneRescueMode", new DefaultOption(false));
options.addBooleanOption("ClearOnNextRestart", new DefaultOption(false));
options.addBooleanOption("ReallyClearOnNextRestart", new DefaultOption(false));
@@ -1736,10 +1877,15 @@ public class Core implements IdentityListener, UpdateListener {
return;
}
- options.getIntegerOption("InsertionDelay").set(configuration.getIntValue("Option/InsertionDelay").getValue(null));
- options.getIntegerOption("PositiveTrust").set(configuration.getIntValue("Option/PositiveTrust").getValue(null));
- options.getIntegerOption("NegativeTrust").set(configuration.getIntValue("Option/NegativeTrust").getValue(null));
+ loadConfigurationValue("InsertionDelay");
+ loadConfigurationValue("PostsPerPage");
+ loadConfigurationValue("CharactersPerPost");
+ options.getBooleanOption("RequireFullAccess").set(configuration.getBooleanValue("Option/RequireFullAccess").getValue(null));
+ loadConfigurationValue("PositiveTrust");
+ loadConfigurationValue("NegativeTrust");
options.getStringOption("TrustComment").set(configuration.getStringValue("Option/TrustComment").getValue(null));
+ options.getBooleanOption("ActivateFcpInterface").set(configuration.getBooleanValue("Option/ActivateFcpInterface").getValue(null));
+ options.getIntegerOption("FcpFullAccessRequired").set(configuration.getIntValue("Option/FcpFullAccessRequired").getValue(null));
options.getBooleanOption("SoneRescueMode").set(configuration.getBooleanValue("Option/SoneRescueMode").getValue(null));
/* load known Sones. */
@@ -1793,6 +1939,21 @@ public class Core implements IdentityListener, UpdateListener {
}
/**
+ * Loads an {@link Integer} configuration value for the option with the
+ * given name, logging validation failures.
+ *
+ * @param optionName
+ * The name of the option to load
+ */
+ private void loadConfigurationValue(String optionName) {
+ try {
+ options.getIntegerOption(optionName).set(configuration.getIntValue("Option/" + optionName).getValue(null));
+ } catch (IllegalArgumentException iae1) {
+ logger.log(Level.WARNING, "Invalid value for " + optionName + " in configuration, using default.");
+ }
+ }
+
+ /**
* Generate a Sone URI from the given URI and latest edition.
*
* @param uriString
@@ -1856,6 +2017,7 @@ public class Core implements IdentityListener, UpdateListener {
public void run() {
Sone sone = getRemoteSone(identity.getId());
sone.setIdentity(identity);
+ sone.setLatestEdition(Numbers.safeParseLong(identity.getProperty("Sone.LatestEdition"), sone.getLatestEdition()));
soneDownloader.addSone(sone);
soneDownloader.fetchSone(sone);
}
@@ -1868,6 +2030,49 @@ public class Core implements IdentityListener, UpdateListener {
@Override
public void identityRemoved(OwnIdentity ownIdentity, Identity identity) {
trustedIdentities.get(ownIdentity).remove(identity);
+ boolean foundIdentity = false;
+ for (Entry> trustedIdentity : trustedIdentities.entrySet()) {
+ if (trustedIdentity.getKey().equals(ownIdentity)) {
+ continue;
+ }
+ if (trustedIdentity.getValue().contains(identity)) {
+ foundIdentity = true;
+ }
+ }
+ if (foundIdentity) {
+ /* some local identity still trusts this identity, donât remove. */
+ return;
+ }
+ Sone sone = getSone(identity.getId(), false);
+ if (sone == null) {
+ /* TODO - we donât have the Sone anymore. should this happen? */
+ return;
+ }
+ synchronized (posts) {
+ synchronized (newPosts) {
+ for (Post post : sone.getPosts()) {
+ posts.remove(post.getId());
+ newPosts.remove(post.getId());
+ coreListenerManager.firePostRemoved(post);
+ }
+ }
+ }
+ synchronized (replies) {
+ synchronized (newReplies) {
+ for (Reply reply : sone.getReplies()) {
+ replies.remove(reply.getId());
+ newReplies.remove(reply.getId());
+ coreListenerManager.fireReplyRemoved(reply);
+ }
+ }
+ }
+ synchronized (remoteSones) {
+ remoteSones.remove(identity.getId());
+ }
+ synchronized (newSones) {
+ newSones.remove(identity.getId());
+ coreListenerManager.fireSoneRemoved(sone);
+ }
}
//
@@ -1913,6 +2118,18 @@ public class Core implements IdentityListener, UpdateListener {
}
/**
+ * Validates the given insertion delay.
+ *
+ * @param insertionDelay
+ * The insertion delay to validate
+ * @return {@code true} if the given insertion delay was valid, {@code
+ * false} otherwise
+ */
+ public boolean validateInsertionDelay(Integer insertionDelay) {
+ return options.getIntegerOption("InsertionDelay").validate(insertionDelay);
+ }
+
+ /**
* Sets the insertion delay
*
* @param insertionDelay
@@ -1926,6 +2143,95 @@ public class Core implements IdentityListener, UpdateListener {
}
/**
+ * Returns the number of posts to show per page.
+ *
+ * @return The number of posts to show per page
+ */
+ public int getPostsPerPage() {
+ return options.getIntegerOption("PostsPerPage").get();
+ }
+
+ /**
+ * Validates the number of posts per page.
+ *
+ * @param postsPerPage
+ * The number of posts per page
+ * @return {@code true} if the number of posts per page was valid,
+ * {@code false} otherwise
+ */
+ public boolean validatePostsPerPage(Integer postsPerPage) {
+ return options.getIntegerOption("PostsPerPage").validate(postsPerPage);
+ }
+
+ /**
+ * Sets the number of posts to show per page.
+ *
+ * @param postsPerPage
+ * The number of posts to show per page
+ * @return This preferences object
+ */
+ public Preferences setPostsPerPage(Integer postsPerPage) {
+ options.getIntegerOption("PostsPerPage").set(postsPerPage);
+ return this;
+ }
+
+ /**
+ * Returns the number of characters per post, or -1
if the
+ * posts should not be cut off.
+ *
+ * @return The numbers of characters per post
+ */
+ public int getCharactersPerPost() {
+ return options.getIntegerOption("CharactersPerPost").get();
+ }
+
+ /**
+ * Validates the number of characters per post.
+ *
+ * @param charactersPerPost
+ * The number of characters per post
+ * @return {@code true} if the number of characters per post was valid,
+ * {@code false} otherwise
+ */
+ public boolean validateCharactersPerPost(Integer charactersPerPost) {
+ return options.getIntegerOption("CharactersPerPost").validate(charactersPerPost);
+ }
+
+ /**
+ * Sets the number of characters per post.
+ *
+ * @param charactersPerPost
+ * The number of characters per post, or -1
to
+ * not cut off the posts
+ * @return This preferences objects
+ */
+ public Preferences setCharactersPerPost(Integer charactersPerPost) {
+ options.getIntegerOption("CharactersPerPost").set(charactersPerPost);
+ return this;
+ }
+
+ /**
+ * Returns whether Sone requires full access to be even visible.
+ *
+ * @return {@code true} if Sone requires full access, {@code false}
+ * otherwise
+ */
+ public boolean isRequireFullAccess() {
+ return options.getBooleanOption("RequireFullAccess").get();
+ }
+
+ /**
+ * Sets whether Sone requires full access to be even visible.
+ *
+ * @param requireFullAccess
+ * {@code true} if Sone requires full access, {@code false}
+ * otherwise
+ */
+ public void setRequireFullAccess(Boolean requireFullAccess) {
+ options.getBooleanOption("RequireFullAccess").set(requireFullAccess);
+ }
+
+ /**
* Returns the positive trust.
*
* @return The positive trust
@@ -1935,6 +2241,18 @@ public class Core implements IdentityListener, UpdateListener {
}
/**
+ * Validates the positive trust.
+ *
+ * @param positiveTrust
+ * The positive trust to validate
+ * @return {@code true} if the positive trust was valid, {@code false}
+ * otherwise
+ */
+ public boolean validatePositiveTrust(Integer positiveTrust) {
+ return options.getIntegerOption("PositiveTrust").validate(positiveTrust);
+ }
+
+ /**
* Sets the positive trust.
*
* @param positiveTrust
@@ -1957,6 +2275,18 @@ public class Core implements IdentityListener, UpdateListener {
}
/**
+ * Validates the negative trust.
+ *
+ * @param negativeTrust
+ * The negative trust to validate
+ * @return {@code true} if the negative trust was valid, {@code false}
+ * otherwise
+ */
+ public boolean validateNegativeTrust(Integer negativeTrust) {
+ return options.getIntegerOption("NegativeTrust").validate(negativeTrust);
+ }
+
+ /**
* Sets the negative trust.
*
* @param negativeTrust
@@ -1993,25 +2323,53 @@ public class Core implements IdentityListener, UpdateListener {
}
/**
- * Returns whether the rescue mode is active.
+ * Returns whether the {@link FcpInterface FCP interface} is currently
+ * active.
*
- * @return {@code true} if the rescue mode is active, {@code false}
- * otherwise
+ * @see FcpInterface#setActive(boolean)
+ * @return {@code true} if the FCP interface is currently active,
+ * {@code false} otherwise
*/
- public boolean isSoneRescueMode() {
- return options.getBooleanOption("SoneRescueMode").get();
+ public boolean isFcpInterfaceActive() {
+ return options.getBooleanOption("ActivateFcpInterface").get();
}
/**
- * Sets whether the rescue mode is active.
+ * Sets whether the {@link FcpInterface FCP interface} is currently
+ * active.
*
- * @param soneRescueMode
- * {@code true} if the rescue mode is active, {@code false}
- * otherwise
+ * @see FcpInterface#setActive(boolean)
+ * @param fcpInterfaceActive
+ * {@code true} to activate the FCP interface, {@code false}
+ * to deactivate the FCP interface
+ * @return This preferences object
+ */
+ public Preferences setFcpInterfaceActive(boolean fcpInterfaceActive) {
+ options.getBooleanOption("ActivateFcpInterface").set(fcpInterfaceActive);
+ return this;
+ }
+
+ /**
+ * Returns the action level for which full access to the FCP interface
+ * is required.
+ *
+ * @return The action level for which full access to the FCP interface
+ * is required
+ */
+ public FullAccessRequired getFcpFullAccessRequired() {
+ return FullAccessRequired.values()[options.getIntegerOption("FcpFullAccessRequired").get()];
+ }
+
+ /**
+ * Sets the action level for which full access to the FCP interface is
+ * required
+ *
+ * @param fcpFullAccessRequired
+ * The action level
* @return This preferences
*/
- public Preferences setSoneRescueMode(Boolean soneRescueMode) {
- options.getBooleanOption("SoneRescueMode").set(soneRescueMode);
+ public Preferences setFcpFullAccessRequired(FullAccessRequired fcpFullAccessRequired) {
+ options.getIntegerOption("FcpFullAccessRequired").set((fcpFullAccessRequired != null) ? fcpFullAccessRequired.ordinal() : null);
return this;
}