<modelVersion>4.0.0</modelVersion>
<groupId>net.pterodactylus</groupId>
<artifactId>sone</artifactId>
- <version>0.8.2</version>
+ <version>0.8.3</version>
<dependencies>
<dependency>
<groupId>net.pterodactylus</groupId>
<artifactId>utils</artifactId>
- <version>0.12</version>
+ <version>0.12.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
import net.pterodactylus.sone.freenet.wot.IdentityListener;
import net.pterodactylus.sone.freenet.wot.IdentityManager;
import net.pterodactylus.sone.freenet.wot.OwnIdentity;
-import net.pterodactylus.sone.freenet.wot.Trust;
-import net.pterodactylus.sone.freenet.wot.WebOfTrustException;
import net.pterodactylus.sone.main.SonePlugin;
import net.pterodactylus.util.config.Configuration;
import net.pterodactylus.util.config.ConfigurationException;
/** The logger. */
private static final Logger logger = Logging.getLogger(Core.class);
+ /** The start time. */
+ private final long startupTime = System.currentTimeMillis();
+
/** The options. */
private final Options options = new Options();
/** The update checker. */
private final UpdateChecker updateChecker;
+ /** The trust updater. */
+ private final WebOfTrustUpdater webOfTrustUpdater;
+
/** The FCP interface. */
private volatile FcpInterface fcpInterface;
* The freenet interface
* @param identityManager
* The identity manager
+ * @param webOfTrustUpdater
+ * The WebOfTrust updater
*/
- public Core(Configuration configuration, FreenetInterface freenetInterface, IdentityManager identityManager) {
+ public Core(Configuration configuration, FreenetInterface freenetInterface, IdentityManager identityManager, WebOfTrustUpdater webOfTrustUpdater) {
super("Sone Core");
this.configuration = configuration;
this.freenetInterface = freenetInterface;
this.soneDownloader = new SoneDownloader(this, freenetInterface);
this.imageInserter = new ImageInserter(this, freenetInterface);
this.updateChecker = new UpdateChecker(freenetInterface);
+ this.webOfTrustUpdater = webOfTrustUpdater;
}
//
//
/**
+ * Returns the time Sone was started.
+ *
+ * @return The startup time (in milliseconds since Jan 1, 1970 UTC)
+ */
+ public long getStartupTime() {
+ return startupTime;
+ }
+
+ /**
* Sets the configuration to use. This will automatically save the current
* configuration to the given configuration.
*
* @return The created Sone
*/
public Sone createSone(OwnIdentity ownIdentity) {
- try {
- ownIdentity.addContext("Sone");
- } catch (WebOfTrustException wote1) {
- logger.log(Level.SEVERE, String.format("Could not add “Sone” context to own identity: %s", ownIdentity), wote1);
+ if (!webOfTrustUpdater.addContextWait(ownIdentity, "Sone")) {
+ logger.log(Level.SEVERE, String.format("Could not add “Sone” context to own identity: %s", ownIdentity));
return null;
}
Sone sone = addLocalSone(ownIdentity);
}
/**
- * Retrieves the trust relationship from the origin to the target. If the
- * trust relationship can not be retrieved, {@code null} is returned.
- *
- * @see Identity#getTrust(OwnIdentity)
- * @param origin
- * The origin of the trust tree
- * @param target
- * The target of the trust
- * @return The trust relationship
- */
- public Trust getTrust(Sone origin, Sone target) {
- if (!isLocalSone(origin)) {
- logger.log(Level.WARNING, String.format("Tried to get trust from remote Sone: %s", origin));
- return null;
- }
- return target.getIdentity().getTrust((OwnIdentity) origin.getIdentity());
- }
-
- /**
* Sets the trust value of the given origin Sone for the target Sone.
*
* @param origin
*/
public void setTrust(Sone origin, Sone target, int trustValue) {
Validation.begin().isNotNull("Trust Origin", origin).check().isInstanceOf("Trust Origin", origin.getIdentity(), OwnIdentity.class).isNotNull("Trust Target", target).isLessOrEqual("Trust Value", trustValue, 100).isGreaterOrEqual("Trust Value", trustValue, -100).check();
- try {
- ((OwnIdentity) origin.getIdentity()).setTrust(target.getIdentity(), trustValue, preferences.getTrustComment());
- } catch (WebOfTrustException wote1) {
- logger.log(Level.WARNING, String.format("Could not set trust for Sone: %s", target), wote1);
- }
+ webOfTrustUpdater.setTrust((OwnIdentity) origin.getIdentity(), target.getIdentity(), trustValue, preferences.getTrustComment());
}
/**
*/
public void removeTrust(Sone origin, Sone target) {
Validation.begin().isNotNull("Trust Origin", origin).isNotNull("Trust Target", target).check().isInstanceOf("Trust Origin Identity", origin.getIdentity(), OwnIdentity.class).check();
- try {
- ((OwnIdentity) origin.getIdentity()).removeTrust(target.getIdentity());
- } catch (WebOfTrustException wote1) {
- logger.log(Level.WARNING, String.format("Could not remove trust for Sone: %s", target), wote1);
- }
+ webOfTrustUpdater.setTrust((OwnIdentity) origin.getIdentity(), target.getIdentity(), null, null);
}
/**
soneInserter.removeSoneInsertListener(this);
soneInserter.stop();
}
- try {
- ((OwnIdentity) sone.getIdentity()).removeContext("Sone");
- ((OwnIdentity) sone.getIdentity()).removeProperty("Sone.LatestEdition");
- } catch (WebOfTrustException wote1) {
- logger.log(Level.WARNING, String.format("Could not remove context and properties from Sone: %s", sone), wote1);
- }
+ webOfTrustUpdater.removeContext((OwnIdentity) sone.getIdentity(), "Sone");
+ webOfTrustUpdater.removeProperty((OwnIdentity) sone.getIdentity(), "Sone.LatestEdition");
try {
configuration.getLongValue("Sone/" + sone.getId() + "/Time").setValue(null);
} catch (ConfigurationException ce1) {
synchronized (albums) {
albums.remove(album.getId());
}
- saveSone(album.getSone());
+ touchConfiguration();
}
/**
synchronized (images) {
images.remove(image.getId());
}
- saveSone(image.getSone());
+ touchConfiguration();
}
/**
loadConfiguration();
updateChecker.addUpdateListener(this);
updateChecker.start();
+ webOfTrustUpdater.start();
}
/**
@Override
public void serviceStop() {
synchronized (localSones) {
- for (SoneInserter soneInserter : soneInserters.values()) {
- soneInserter.removeSoneInsertListener(this);
- soneInserter.stop();
+ for (Entry<Sone, SoneInserter> soneInserter : soneInserters.entrySet()) {
+ soneInserter.getValue().removeSoneInsertListener(this);
+ soneInserter.getValue().stop();
+ saveSone(soneInserter.getKey());
}
}
+ saveConfiguration();
+ webOfTrustUpdater.stop();
updateChecker.stop();
updateChecker.removeUpdateListener(this);
soneDownloader.stop();
configuration.save();
- ((OwnIdentity) sone.getIdentity()).setProperty("Sone.LatestEdition", String.valueOf(sone.getLatestEdition()));
+ webOfTrustUpdater.setProperty((OwnIdentity) sone.getIdentity(), "Sone.LatestEdition", String.valueOf(sone.getLatestEdition()));
logger.log(Level.INFO, String.format("Sone %s saved.", sone));
} catch (ConfigurationException ce1) {
logger.log(Level.WARNING, String.format("Could not save Sone: %s", sone), ce1);
- } catch (WebOfTrustException wote1) {
- logger.log(Level.WARNING, String.format("Could not set WoT property for Sone: %s", sone), wote1);
}
}
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());
/* save known Sones. */
int soneCounter = 0;
}
}));
- options.addBooleanOption("SoneRescueMode", new DefaultOption<Boolean>(false));
- options.addBooleanOption("ClearOnNextRestart", new DefaultOption<Boolean>(false));
- options.addBooleanOption("ReallyClearOnNextRestart", new DefaultOption<Boolean>(false));
-
- /* read options from configuration. */
- options.getBooleanOption("ClearOnNextRestart").set(configuration.getBooleanValue("Option/ClearOnNextRestart").getValue(null));
- options.getBooleanOption("ReallyClearOnNextRestart").set(configuration.getBooleanValue("Option/ReallyClearOnNextRestart").getValue(null));
- boolean clearConfiguration = options.getBooleanOption("ClearOnNextRestart").get() && options.getBooleanOption("ReallyClearOnNextRestart").get();
- options.getBooleanOption("ClearOnNextRestart").set(null);
- options.getBooleanOption("ReallyClearOnNextRestart").set(null);
- if (clearConfiguration) {
- /* stop loading the configuration. */
- return;
- }
loadConfigurationValue("InsertionDelay");
loadConfigurationValue("PostsPerPage");
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. */
int soneCounter = 0;
* The URI to derive the Sone URI from
* @return The derived URI
*/
- private FreenetURI getSoneUri(String uriString) {
+ private static FreenetURI getSoneUri(String uriString) {
try {
FreenetURI uri = new FreenetURI(uriString).setDocName("Sone").setMetaString(new String[0]);
return uri;
} catch (MalformedURLException mue1) {
- logger.log(Level.WARNING, String.format("Could not create Sone URI from URI: %s", uriString, mue1));
+ logger.log(Level.WARNING, String.format("Could not create Sone URI from URI: %s", uriString), mue1);
return null;
}
}
logger.log(Level.WARNING, String.format("Image insert finished for %s: %s", image, key));
image.setKey(key.toString());
deleteTemporaryImage(image.getId());
- saveSone(image.getSone());
+ touchConfiguration();
coreListenerManager.fireImageInsertFinished(image);
}
return this;
}
- /**
- * Returns whether Sone should clear its settings on the next restart.
- * In order to be effective, {@link #isReallyClearOnNextRestart()} needs
- * to return {@code true} as well!
- *
- * @return {@code true} if Sone should clear its settings on the next
- * restart, {@code false} otherwise
- */
- public boolean isClearOnNextRestart() {
- return options.getBooleanOption("ClearOnNextRestart").get();
- }
-
- /**
- * Sets whether Sone will clear its settings on the next restart.
- *
- * @param clearOnNextRestart
- * {@code true} if Sone should clear its settings on the next
- * restart, {@code false} otherwise
- * @return This preferences
- */
- public Preferences setClearOnNextRestart(Boolean clearOnNextRestart) {
- options.getBooleanOption("ClearOnNextRestart").set(clearOnNextRestart);
- return this;
- }
-
- /**
- * Returns whether Sone should really clear its settings on next
- * restart. This is a confirmation option that needs to be set in
- * addition to {@link #isClearOnNextRestart()} in order to clear Sone’s
- * settings on the next restart.
- *
- * @return {@code true} if Sone should really clear its settings on the
- * next restart, {@code false} otherwise
- */
- public boolean isReallyClearOnNextRestart() {
- return options.getBooleanOption("ReallyClearOnNextRestart").get();
- }
-
- /**
- * Sets whether Sone should really clear its settings on the next
- * restart.
- *
- * @param reallyClearOnNextRestart
- * {@code true} if Sone should really clear its settings on
- * the next restart, {@code false} otherwise
- * @return This preferences
- */
- public Preferences setReallyClearOnNextRestart(Boolean reallyClearOnNextRestart) {
- options.getBooleanOption("ReallyClearOnNextRestart").set(reallyClearOnNextRestart);
- return this;
- }
-
}
}
/**
* Adds an {@link Enum} {@link Option}.
*
+ * @param <T>
+ * The enum type
* @param name
* The name of the option
* @param enumOption
* options.<SomeEnum> getEnumOption("SomeEnumOption").get();
* </pre>
*
+ * @param <T>
+ * The enum type
* @param name
* The name of the option
* @return The enum option, or {@code null} if there is no enum option with
private static final String SONE_HOMEPAGE = "USK@nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI,DuQSUZiI~agF8c-6tjsFFGuZ8eICrzWCILB60nT8KKo,AQACAAE/sone/";
/** The current latest known edition. */
- private static final int LATEST_EDITION = 49;
+ private static final int LATEST_EDITION = 54;
/** The Freenet interface. */
private final FreenetInterface freenetInterface;
--- /dev/null
+/*
+ * Sone - WebOfTrustUpdater.java - Copyright © 2012 David Roden
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.core;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import net.pterodactylus.sone.freenet.plugin.PluginException;
+import net.pterodactylus.sone.freenet.wot.DefaultIdentity;
+import net.pterodactylus.sone.freenet.wot.Identity;
+import net.pterodactylus.sone.freenet.wot.OwnIdentity;
+import net.pterodactylus.sone.freenet.wot.Trust;
+import net.pterodactylus.sone.freenet.wot.WebOfTrustConnector;
+import net.pterodactylus.sone.freenet.wot.WebOfTrustException;
+import net.pterodactylus.util.logging.Logging;
+import net.pterodactylus.util.service.AbstractService;
+import net.pterodactylus.util.validation.Validation;
+
+/**
+ * Updates WebOfTrust identity data in a background thread because communicating
+ * with the WebOfTrust plugin can potentially last quite long.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class WebOfTrustUpdater extends AbstractService {
+
+ /** The logger. */
+ private static final Logger logger = Logging.getLogger(WebOfTrustUpdater.class);
+
+ /** Stop job. */
+ @SuppressWarnings("synthetic-access")
+ private final WebOfTrustUpdateJob stopJob = new WebOfTrustUpdateJob();
+
+ /** The web of trust connector. */
+ private final WebOfTrustConnector webOfTrustConnector;
+
+ /** The queue for jobs. */
+ private final BlockingQueue<WebOfTrustUpdateJob> updateJobs = new LinkedBlockingQueue<WebOfTrustUpdateJob>();
+
+ /**
+ * Creates a new trust updater.
+ *
+ * @param webOfTrustConnector
+ * The web of trust connector
+ */
+ public WebOfTrustUpdater(WebOfTrustConnector webOfTrustConnector) {
+ super("Trust Updater");
+ this.webOfTrustConnector = webOfTrustConnector;
+ }
+
+ //
+ // ACTIONS
+ //
+
+ /**
+ * Updates the trust relation between the truster and the trustee. This
+ * method will return immediately and perform a trust update in the
+ * background.
+ *
+ * @param truster
+ * The identity giving the trust
+ * @param trustee
+ * The identity receiving the trust
+ * @param score
+ * The new level of trust (from -100 to 100, may be {@code null}
+ * to remove the trust completely)
+ * @param comment
+ * The comment of the trust relation
+ */
+ public void setTrust(OwnIdentity truster, Identity trustee, Integer score, String comment) {
+ SetTrustJob setTrustJob = new SetTrustJob(truster, trustee, score, comment);
+ if (updateJobs.contains(setTrustJob)) {
+ updateJobs.remove(setTrustJob);
+ }
+ logger.log(Level.FINER, "Adding Trust Update Job: " + setTrustJob);
+ try {
+ updateJobs.put(setTrustJob);
+ } catch (InterruptedException e) {
+ /* the queue is unbounded so it should never block. */
+ }
+ }
+
+ /**
+ * Adds the given context to the given own identity.
+ *
+ * @param ownIdentity
+ * The own identity to add the context to
+ * @param context
+ * The context to add
+ */
+ public void addContext(OwnIdentity ownIdentity, String context) {
+ addContextWait(ownIdentity, context, false);
+ }
+
+ /**
+ * Adds the given context to the given own identity, waiting for completion
+ * of the operation.
+ *
+ * @param ownIdentity
+ * The own identity to add the context to
+ * @param context
+ * The context to add
+ * @return {@code true} if the context was added successfully, {@code false}
+ * otherwise
+ */
+ public boolean addContextWait(OwnIdentity ownIdentity, String context) {
+ return addContextWait(ownIdentity, context, true);
+ }
+
+ /**
+ * Adds the given context to the given own identity, waiting for completion
+ * of the operation.
+ *
+ * @param ownIdentity
+ * The own identity to add the context to
+ * @param context
+ * The context to add
+ * @param wait
+ * {@code true} to wait for the end of the operation,
+ * {@code false} to return immediately
+ * @return {@code true} if the context was added successfully, {@code false}
+ * if the context was not added successfully, or if the job should
+ * not wait for completion
+ */
+ private boolean addContextWait(OwnIdentity ownIdentity, String context, boolean wait) {
+ AddContextJob addContextJob = new AddContextJob(ownIdentity, context);
+ if (!updateJobs.contains(addContextJob)) {
+ logger.log(Level.FINER, "Adding Context Job: " + addContextJob);
+ try {
+ updateJobs.put(addContextJob);
+ } catch (InterruptedException ie1) {
+ /* the queue is unbounded so it should never block. */
+ }
+ if (wait) {
+ return addContextJob.waitForCompletion();
+ }
+ } else if (wait) {
+ for (WebOfTrustUpdateJob updateJob : updateJobs) {
+ if (updateJob.equals(addContextJob)) {
+ return updateJob.waitForCompletion();
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Removes the given context from the given own identity.
+ *
+ * @param ownIdentity
+ * The own identity to remove the context from
+ * @param context
+ * The context to remove
+ */
+ public void removeContext(OwnIdentity ownIdentity, String context) {
+ RemoveContextJob removeContextJob = new RemoveContextJob(ownIdentity, context);
+ if (!updateJobs.contains(removeContextJob)) {
+ logger.log(Level.FINER, "Adding Context Job: " + removeContextJob);
+ try {
+ updateJobs.put(removeContextJob);
+ } catch (InterruptedException ie1) {
+ /* the queue is unbounded so it should never block. */
+ }
+ }
+ }
+
+ /**
+ * Sets a property on the given own identity.
+ *
+ * @param ownIdentity
+ * The own identity to set the property on
+ * @param propertyName
+ * The name of the property to set
+ * @param propertyValue
+ * The value of the property to set
+ */
+ public void setProperty(OwnIdentity ownIdentity, String propertyName, String propertyValue) {
+ SetPropertyJob setPropertyJob = new SetPropertyJob(ownIdentity, propertyName, propertyValue);
+ if (updateJobs.contains(setPropertyJob)) {
+ updateJobs.remove(setPropertyJob);
+ }
+ logger.log(Level.FINER, "Adding Property Job: " + setPropertyJob);
+ try {
+ updateJobs.put(setPropertyJob);
+ } catch (InterruptedException e) {
+ /* the queue is unbounded so it should never block. */
+ }
+ }
+
+ /**
+ * Removes a property from the given own identity.
+ *
+ * @param ownIdentity
+ * The own identity to remove the property from
+ * @param propertyName
+ * The name of the property to remove
+ */
+ public void removeProperty(OwnIdentity ownIdentity, String propertyName) {
+ setProperty(ownIdentity, propertyName, null);
+ }
+
+ //
+ // SERVICE METHODS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void serviceRun() {
+ while (!shouldStop()) {
+ try {
+ WebOfTrustUpdateJob updateJob = updateJobs.take();
+ if (shouldStop() || (updateJob == stopJob)) {
+ break;
+ }
+ logger.log(Level.FINE, "Running Trust Update Job: " + updateJob);
+ long startTime = System.currentTimeMillis();
+ updateJob.run();
+ long endTime = System.currentTimeMillis();
+ logger.log(Level.FINE, "Trust Update Job finished, took " + (endTime - startTime) + " ms.");
+ } catch (InterruptedException ie1) {
+ /* happens, ignore, loop. */
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void serviceStop() {
+ try {
+ updateJobs.put(stopJob);
+ } catch (InterruptedException ie1) {
+ /* the queue is unbounded so it should never block. */
+ }
+ }
+
+ /**
+ * Base class for WebOfTrust update jobs.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+ private class WebOfTrustUpdateJob {
+
+ /** Object for synchronization. */
+ @SuppressWarnings("hiding")
+ private final Object syncObject = new Object();
+
+ /** Whether the job has finished. */
+ private boolean finished;
+
+ /** Whether the job was successful. */
+ private boolean success;
+
+ //
+ // ACTIONS
+ //
+
+ /**
+ * Performs the actual update operation.
+ * <p>
+ * The implementation of this class does nothing.
+ */
+ public void run() {
+ /* does nothing. */
+ }
+
+ /**
+ * Waits for completion of this job or stopping of the WebOfTrust
+ * updater.
+ *
+ * @return {@code true} if this job finished successfully, {@code false}
+ * otherwise
+ *
+ * @see WebOfTrustUpdater#stop()
+ */
+ @SuppressWarnings("synthetic-access")
+ public boolean waitForCompletion() {
+ synchronized (syncObject) {
+ while (!finished && !shouldStop()) {
+ try {
+ syncObject.wait();
+ } catch (InterruptedException ie1) {
+ /* we’re looping, ignore. */
+ }
+ }
+ return success;
+ }
+ }
+
+ //
+ // PROTECTED METHODS
+ //
+
+ /**
+ * Signals that this job has finished.
+ *
+ * @param success
+ * {@code true} if this job finished successfully,
+ * {@code false} otherwise
+ */
+ protected void finish(boolean success) {
+ synchronized (syncObject) {
+ finished = true;
+ this.success = success;
+ syncObject.notifyAll();
+ }
+ }
+
+ }
+
+ /**
+ * Base class for WebOfTrust trust update jobs.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+ private class WebOfTrustTrustUpdateJob extends WebOfTrustUpdateJob {
+
+ /** The identity giving the trust. */
+ protected final OwnIdentity truster;
+
+ /** The identity receiving the trust. */
+ protected final Identity trustee;
+
+ /**
+ * Creates a new trust update job.
+ *
+ * @param truster
+ * The identity giving the trust
+ * @param trustee
+ * The identity receiving the trust
+ */
+ @SuppressWarnings("synthetic-access")
+ public WebOfTrustTrustUpdateJob(OwnIdentity truster, Identity trustee) {
+ this.truster = truster;
+ this.trustee = trustee;
+ }
+
+ //
+ // OBJECT METHODS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(Object object) {
+ if ((object == null) || !object.getClass().equals(getClass())) {
+ return false;
+ }
+ WebOfTrustTrustUpdateJob updateJob = (WebOfTrustTrustUpdateJob) object;
+ return ((truster == null) ? (updateJob.truster == null) : updateJob.truster.equals(truster)) && ((trustee == null) ? (updateJob.trustee == null) : updateJob.trustee.equals(trustee));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return getClass().hashCode() ^ ((truster == null) ? 0 : truster.hashCode()) ^ ((trustee == null) ? 0 : trustee.hashCode());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return String.format("%s[truster=%s,trustee=%s]", getClass().getSimpleName(), (truster == null) ? null : truster.getId(), (trustee == null) ? null : trustee.getId());
+ }
+
+ }
+
+ /**
+ * Update job that sets the trust relation between two identities.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+ private class SetTrustJob extends WebOfTrustTrustUpdateJob {
+
+ /** The score of the relation. */
+ private final Integer score;
+
+ /** The comment of the relation. */
+ private final String comment;
+
+ /**
+ * Creates a new set trust job.
+ *
+ * @param truster
+ * The identity giving the trust
+ * @param trustee
+ * The identity receiving the trust
+ * @param score
+ * The score of the trust (from -100 to 100, may be
+ * {@code null} to remote the trust relation completely)
+ * @param comment
+ * The comment of the trust relation
+ */
+ public SetTrustJob(OwnIdentity truster, Identity trustee, Integer score, String comment) {
+ super(truster, trustee);
+ this.score = score;
+ this.comment = comment;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ @SuppressWarnings("synthetic-access")
+ public void run() {
+ try {
+ if (score != null) {
+ if (trustee instanceof DefaultIdentity) {
+ ((DefaultIdentity) trustee).setTrust(truster, new Trust(score, null, 0));
+ }
+ webOfTrustConnector.setTrust(truster, trustee, score, comment);
+ } else {
+ if (trustee instanceof DefaultIdentity) {
+ ((DefaultIdentity) trustee).setTrust(truster, null);
+ }
+ webOfTrustConnector.removeTrust(truster, trustee);
+ }
+ finish(true);
+ } catch (WebOfTrustException wote1) {
+ logger.log(Level.WARNING, "Could not set Trust value for " + truster + " -> " + trustee + " to " + score + " (" + comment + ")!", wote1);
+ finish(false);
+ }
+ }
+
+ }
+
+ /**
+ * Base class for context updates of an {@link OwnIdentity}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+ private class WebOfTrustContextUpdateJob extends WebOfTrustUpdateJob {
+
+ /** The own identity whose contexts to manage. */
+ protected final OwnIdentity ownIdentity;
+
+ /** The context to update. */
+ protected final String context;
+
+ /**
+ * Creates a new context update job.
+ *
+ * @param ownIdentity
+ * The own identity to update
+ * @param context
+ * The context to update
+ */
+ @SuppressWarnings("synthetic-access")
+ public WebOfTrustContextUpdateJob(OwnIdentity ownIdentity, String context) {
+ Validation.begin().isNotNull("OwnIdentity", ownIdentity).isNotNull("Context", context).check();
+ this.ownIdentity = ownIdentity;
+ this.context = context;
+ }
+
+ //
+ // OBJECT METHODS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(Object object) {
+ if ((object == null) || !object.getClass().equals(getClass())) {
+ return false;
+ }
+ WebOfTrustContextUpdateJob updateJob = (WebOfTrustContextUpdateJob) object;
+ return updateJob.ownIdentity.equals(ownIdentity) && updateJob.context.equals(context);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return getClass().hashCode() ^ ownIdentity.hashCode() ^ context.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return String.format("%s[ownIdentity=%s,context=%s]", getClass().getSimpleName(), ownIdentity, context);
+ }
+
+ }
+
+ /**
+ * Job that adds a context to an {@link OwnIdentity}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+ private class AddContextJob extends WebOfTrustContextUpdateJob {
+
+ /**
+ * Creates a new add-context job.
+ *
+ * @param ownIdentity
+ * The own identity whose contexts to manage
+ * @param context
+ * The context to add
+ */
+ public AddContextJob(OwnIdentity ownIdentity, String context) {
+ super(ownIdentity, context);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ @SuppressWarnings("synthetic-access")
+ public void run() {
+ try {
+ webOfTrustConnector.addContext(ownIdentity, context);
+ ownIdentity.addContext(context);
+ finish(true);
+ } catch (PluginException pe1) {
+ logger.log(Level.WARNING, String.format("Could not add Context “%2$s” to Own Identity %1$s!", ownIdentity, context), pe1);
+ finish(false);
+ }
+ }
+
+ }
+
+ /**
+ * Job that removes a context from an {@link OwnIdentity}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+ private class RemoveContextJob extends WebOfTrustContextUpdateJob {
+
+ /**
+ * Creates a new remove-context job.
+ *
+ * @param ownIdentity
+ * The own identity whose contexts to manage
+ * @param context
+ * The context to remove
+ */
+ public RemoveContextJob(OwnIdentity ownIdentity, String context) {
+ super(ownIdentity, context);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ @SuppressWarnings("synthetic-access")
+ public void run() {
+ try {
+ webOfTrustConnector.removeContext(ownIdentity, context);
+ ownIdentity.removeContext(context);
+ finish(true);
+ } catch (PluginException pe1) {
+ logger.log(Level.WARNING, String.format("Could not remove Context “%2$s” to Own Identity %1$s!", ownIdentity, context), pe1);
+ finish(false);
+ }
+ }
+
+ }
+
+ /**
+ * Base class for update jobs that deal with properties.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+ private class WebOfTrustPropertyUpdateJob extends WebOfTrustUpdateJob {
+
+ /** The own identity to update properties on. */
+ protected final OwnIdentity ownIdentity;
+
+ /** The name of the property to update. */
+ protected final String propertyName;
+
+ /**
+ * Creates a new property update job.
+ *
+ * @param ownIdentity
+ * The own identity to update the property on
+ * @param propertyName
+ * The name of the property to update
+ */
+ @SuppressWarnings("synthetic-access")
+ public WebOfTrustPropertyUpdateJob(OwnIdentity ownIdentity, String propertyName) {
+ this.ownIdentity = ownIdentity;
+ this.propertyName = propertyName;
+ }
+
+ //
+ // OBJECT METHODS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(Object object) {
+ if ((object == null) || !object.getClass().equals(getClass())) {
+ return false;
+ }
+ WebOfTrustPropertyUpdateJob updateJob = (WebOfTrustPropertyUpdateJob) object;
+ return updateJob.ownIdentity.equals(ownIdentity) && updateJob.propertyName.equals(propertyName);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return getClass().hashCode() ^ ownIdentity.hashCode() ^ propertyName.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return String.format("%s[ownIdentity=%s,propertyName=%s]", getClass().getSimpleName(), ownIdentity, propertyName);
+ }
+
+ }
+
+ /**
+ * WebOfTrust update job that sets a property on an {@link OwnIdentity}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+ private class SetPropertyJob extends WebOfTrustPropertyUpdateJob {
+
+ /** The value of the property to set. */
+ private final String propertyValue;
+
+ /**
+ * Creates a new set-property job.
+ *
+ * @param ownIdentity
+ * The own identity to set the property on
+ * @param propertyName
+ * The name of the property to set
+ * @param propertyValue
+ * The value of the property to set
+ */
+ public SetPropertyJob(OwnIdentity ownIdentity, String propertyName, String propertyValue) {
+ super(ownIdentity, propertyName);
+ this.propertyValue = propertyValue;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ @SuppressWarnings("synthetic-access")
+ public void run() {
+ try {
+ if (propertyValue == null) {
+ webOfTrustConnector.removeProperty(ownIdentity, propertyName);
+ ownIdentity.removeProperty(propertyName);
+ } else {
+ webOfTrustConnector.setProperty(ownIdentity, propertyName, propertyValue);
+ ownIdentity.setProperty(propertyName, propertyValue);
+ }
+ finish(true);
+ } catch (PluginException pe1) {
+ logger.log(Level.WARNING, String.format("Could not set Property “%2$s” to “%3$s” on Own Identity %1$s!", ownIdentity, propertyName, propertyValue), pe1);
+ finish(false);
+ }
+ }
+
+ }
+
+}
*/
public void addAlbum(Album album) {
Validation.begin().isNotNull("Album", album).check().isEqual("Album Owner", album.getSone(), this).check();
- albums.add(album);
+ if (!albums.contains(album)) {
+ albums.add(album);
+ }
}
/**
* The text to encode
* @return The encoded text
*/
- protected String encodeString(String text) {
+ protected static String encodeString(String text) {
return text.replaceAll("\\\\", "\\\\").replaceAll("\n", "\\\\n").replaceAll("\r", "\\\\r");
}
* such as if the Sone is followed by the local Sone
* @return The simple field set containing the given Sone
*/
- protected SimpleFieldSet encodeSone(Sone sone, String prefix, Sone localSone) {
+ protected static SimpleFieldSet encodeSone(Sone sone, String prefix, Sone localSone) {
SimpleFieldSetBuilder soneBuilder = new SimpleFieldSetBuilder();
soneBuilder.put(prefix + "Name", sone.getName());
* {@code null})
* @return The simple field set containing the given Sones
*/
- protected SimpleFieldSet encodeSones(Collection<? extends Sone> sones, String prefix) {
+ protected static SimpleFieldSet encodeSones(Collection<? extends Sone> sones, String prefix) {
SimpleFieldSetBuilder soneBuilder = new SimpleFieldSetBuilder();
int soneIndex = 0;
* {@code null})
* @return The simple field set containing the replies
*/
- protected SimpleFieldSet encodeReplies(Collection<? extends PostReply> replies, String prefix) {
+ protected static SimpleFieldSet encodeReplies(Collection<? extends PostReply> replies, String prefix) {
SimpleFieldSetBuilder replyBuilder = new SimpleFieldSetBuilder();
int replyIndex = 0;
* {@code null})
* @return The simple field set containing the likes
*/
- protected SimpleFieldSet encodeLikes(Collection<? extends Sone> likes, String prefix) {
+ protected static SimpleFieldSet encodeLikes(Collection<? extends Sone> likes, String prefix) {
SimpleFieldSetBuilder likesBuilder = new SimpleFieldSetBuilder();
int likeIndex = 0;
* @throws PluginNotFoundException
* if the plugin can not be found
*/
- private void sendReply(PluginReplySender pluginReplySender, String identifier, Response response) throws PluginNotFoundException {
+ private static void sendReply(PluginReplySender pluginReplySender, String identifier, Response response) throws PluginNotFoundException {
SimpleFieldSet replyParameters = response.getReplyParameters();
if (identifier != null) {
replyParameters.putOverwrite("Identifier", identifier);
* if there is no value for the given key in the simple field
* set, or the value can not be converted to a String
*/
- protected String getString(SimpleFieldSet simpleFieldSet, String key) throws FcpException {
+ protected static String getString(SimpleFieldSet simpleFieldSet, String key) throws FcpException {
try {
return simpleFieldSet.getString(key);
} catch (FSParseException fspe1) {
* if there is no value for the given key in the simple field
* set, or the value can not be converted to an int
*/
- protected int getInt(SimpleFieldSet simpleFieldSet, String key) throws FcpException {
+ protected static int getInt(SimpleFieldSet simpleFieldSet, String key) throws FcpException {
try {
return simpleFieldSet.getInt(key);
} catch (FSParseException fspe1) {
* The default value
* @return The int value
*/
- protected int getInt(SimpleFieldSet simpleFieldSet, String key, int defaultValue) {
+ protected static int getInt(SimpleFieldSet simpleFieldSet, String key, int defaultValue) {
return simpleFieldSet.getInt(key, defaultValue);
}
* if there is no value for the given key in the simple field
* set, or the value can not be converted to a boolean
*/
- protected boolean getBoolean(SimpleFieldSet simpleFieldSet, String key) throws FcpException {
+ protected static boolean getBoolean(SimpleFieldSet simpleFieldSet, String key) throws FcpException {
try {
return simpleFieldSet.getBoolean(key);
} catch (FSParseException fspe1) {
* The default value
* @return The boolean value
*/
- protected boolean getBoolean(SimpleFieldSet simpleFieldSet, String key, boolean defaultValue) {
+ protected static boolean getBoolean(SimpleFieldSet simpleFieldSet, String key, boolean defaultValue) {
return simpleFieldSet.getBoolean(key, defaultValue);
}
package net.pterodactylus.sone.freenet.wot;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import net.pterodactylus.sone.freenet.plugin.PluginException;
-import net.pterodactylus.util.cache.CacheException;
-import net.pterodactylus.util.cache.CacheItem;
-import net.pterodactylus.util.cache.DefaultCacheItem;
-import net.pterodactylus.util.cache.MemoryCache;
-import net.pterodactylus.util.cache.ValueRetriever;
-import net.pterodactylus.util.cache.WritableCache;
-import net.pterodactylus.util.collection.TimedMap;
-import net.pterodactylus.util.logging.Logging;
/**
* A Web of Trust identity.
*/
public class DefaultIdentity implements Identity {
- /** The logger. */
- private static final Logger logger = Logging.getLogger(DefaultIdentity.class);
-
- /** The web of trust connector. */
- private final WebOfTrustConnector webOfTrustConnector;
-
/** The ID of the identity. */
private final String id;
private final Map<String, String> properties = Collections.synchronizedMap(new HashMap<String, String>());
/** Cached trust. */
- /* synchronize on itself. */
- private final WritableCache<OwnIdentity, Trust> trustCache = new MemoryCache<OwnIdentity, Trust>(new ValueRetriever<OwnIdentity, Trust>() {
-
- @Override
- @SuppressWarnings("synthetic-access")
- public CacheItem<Trust> retrieve(OwnIdentity ownIdentity) throws CacheException {
- try {
- return new DefaultCacheItem<Trust>(webOfTrustConnector.getTrust(ownIdentity, DefaultIdentity.this));
- } catch (PluginException pe1) {
- throw new CacheException("Could not retrieve trust for OwnIdentity: " + ownIdentity, pe1);
- }
- }
-
- }, new TimedMap<OwnIdentity, CacheItem<Trust>>(60 * 60 * 1000));
+ private final Map<OwnIdentity, Trust> trustCache = Collections.synchronizedMap(new HashMap<OwnIdentity, Trust>());
/**
* Creates a new identity.
*
- * @param webOfTrustConnector
- * The web of trust connector
* @param id
* The ID of the identity
* @param nickname
* @param requestUri
* The request URI of the identity
*/
- public DefaultIdentity(WebOfTrustConnector webOfTrustConnector, String id, String nickname, String requestUri) {
- this.webOfTrustConnector = webOfTrustConnector;
+ public DefaultIdentity(String id, String nickname, String requestUri) {
this.id = id;
this.nickname = nickname;
this.requestUri = requestUri;
}
/**
- * Sets the contexts of this identity.
- * <p>
- * This method is only called by the {@link IdentityManager}.
- *
- * @param contexts
- * The contexts to set
+ * {@inheritDoc}
*/
- void setContextsPrivate(Set<String> contexts) {
- this.contexts.clear();
- this.contexts.addAll(contexts);
+ @Override
+ public boolean hasContext(String context) {
+ return contexts.contains(context);
}
/**
* {@inheritDoc}
*/
@Override
- public boolean hasContext(String context) {
- return contexts.contains(context);
+ public void setContexts(Collection<String> contexts) {
+ this.contexts.clear();
+ this.contexts.addAll(contexts);
}
/**
- * Adds the given context to this identity.
- * <p>
- * This method is only called by the {@link IdentityManager}.
- *
- * @param context
- * The context to add
+ * {@inheritDoc}
*/
- void addContextPrivate(String context) {
+ @Override
+ public void addContext(String context) {
contexts.add(context);
}
/**
- * Removes the given context from this identity.
- * <p>
- * This method is only called by the {@link IdentityManager}.
- *
- * @param context
- * The context to remove
+ * {@inheritDoc}
*/
- public void removeContextPrivate(String context) {
+ @Override
+ public void removeContext(String context) {
contexts.remove(context);
}
*/
@Override
public Map<String, String> getProperties() {
- synchronized (properties) {
- return Collections.unmodifiableMap(properties);
- }
+ return Collections.unmodifiableMap(properties);
}
/**
- * Sets all properties of this identity.
- * <p>
- * This method is only called by the {@link IdentityManager}.
- *
- * @param properties
- * The new properties of this identity
+ * {@inheritDoc}
*/
- void setPropertiesPrivate(Map<String, String> properties) {
- synchronized (this.properties) {
- this.properties.clear();
- this.properties.putAll(properties);
- }
+ @Override
+ public void setProperties(Map<String, String> properties) {
+ this.properties.clear();
+ this.properties.putAll(properties);
}
/**
- * Sets the property with the given name to the given value.
- * <p>
- * This method is only called by the {@link IdentityManager}.
- *
- * @param name
- * The name of the property
- * @param value
- * The value of the property
+ * {@inheritDoc}
*/
- void setPropertyPrivate(String name, String value) {
- synchronized (properties) {
- properties.put(name, value);
- }
+ @Override
+ public String getProperty(String name) {
+ return properties.get(name);
}
/**
* {@inheritDoc}
*/
@Override
- public String getProperty(String name) {
- synchronized (properties) {
- return properties.get(name);
- }
+ public void setProperty(String name, String value) {
+ properties.put(name, value);
}
/**
- * Removes the property with the given name.
- * <p>
- * This method is only called by the {@link IdentityManager}.
- *
- * @param name
- * The name of the property to remove
+ * {@inheritDoc}
*/
- void removePropertyPrivate(String name) {
- synchronized (properties) {
- properties.remove(name);
- }
+ @Override
+ public void removeProperty(String name) {
+ properties.remove(name);
}
/**
*/
@Override
public Trust getTrust(OwnIdentity ownIdentity) {
- try {
- synchronized (trustCache) {
- return trustCache.get(ownIdentity);
- }
- } catch (CacheException ce1) {
- logger.log(Level.WARNING, String.format("Could not get trust for OwnIdentity: %s", ownIdentity), ce1);
- return null;
- }
+ return trustCache.get(ownIdentity);
}
/**
- * Sets the trust received for this identity by the given own identity.
- *
- * @param ownIdentity
- * The own identity that gives the trust
- * @param trust
- * The trust received for this identity
+ * {@inheritDoc}
*/
- void setTrustPrivate(OwnIdentity ownIdentity, Trust trust) {
- synchronized (trustCache) {
- trustCache.put(ownIdentity, trust);
- }
+ @Override
+ public void setTrust(OwnIdentity ownIdentity, Trust trust) {
+ trustCache.put(ownIdentity, trust);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void removeTrust(OwnIdentity ownIdentity) {
+ trustCache.remove(ownIdentity);
}
//
package net.pterodactylus.sone.freenet.wot;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-import net.pterodactylus.util.validation.Validation;
-
/**
* An own identity is an identity that the owner of the node has full control
* over.
*/
public class DefaultOwnIdentity extends DefaultIdentity implements OwnIdentity {
- /** The identity manager. */
- private final WebOfTrustConnector webOfTrustConnector;
-
/** The insert URI of the identity. */
private final String insertUri;
/**
* Creates a new own identity.
*
- * @param webOfTrustConnector
- * The identity manager
* @param id
* The ID of the identity
* @param nickname
* @param insertUri
* The insert URI of the identity
*/
- public DefaultOwnIdentity(WebOfTrustConnector webOfTrustConnector, String id, String nickname, String requestUri, String insertUri) {
- super(webOfTrustConnector, id, nickname, requestUri);
- this.webOfTrustConnector = webOfTrustConnector;
+ public DefaultOwnIdentity(String id, String nickname, String requestUri, String insertUri) {
+ super(id, nickname, requestUri);
this.insertUri = insertUri;
}
/**
* Copy constructor for an own identity.
*
- * @param webOfTrustConnector
- * The web of trust connector
* @param ownIdentity
* The own identity to copy
*/
- public DefaultOwnIdentity(WebOfTrustConnector webOfTrustConnector, OwnIdentity ownIdentity) {
- super(webOfTrustConnector, ownIdentity.getId(), ownIdentity.getNickname(), ownIdentity.getRequestUri());
- this.webOfTrustConnector = webOfTrustConnector;
+ public DefaultOwnIdentity(OwnIdentity ownIdentity) {
+ super(ownIdentity.getId(), ownIdentity.getNickname(), ownIdentity.getRequestUri());
this.insertUri = ownIdentity.getInsertUri();
- setContextsPrivate(ownIdentity.getContexts());
- setPropertiesPrivate(ownIdentity.getProperties());
+ setContexts(ownIdentity.getContexts());
+ setProperties(ownIdentity.getProperties());
}
//
return insertUri;
}
- /**
- * {@inheritDoc}
- */
- @Override
- public void addContext(String context) throws WebOfTrustException {
- webOfTrustConnector.addContext(this, context);
- addContextPrivate(context);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void removeContext(String context) throws WebOfTrustException {
- webOfTrustConnector.removeContext(this, context);
- removeContextPrivate(context);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setContexts(Set<String> contexts) throws WebOfTrustException {
- for (String context : getContexts()) {
- if (!contexts.contains(context)) {
- webOfTrustConnector.removeContext(this, context);
- }
- }
- for (String context : contexts) {
- if (!getContexts().contains(context)) {
- webOfTrustConnector.addContext(this, context);
- }
- }
- setContextsPrivate(contexts);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setProperty(String name, String value) throws WebOfTrustException {
- webOfTrustConnector.setProperty(this, name, value);
- setPropertyPrivate(name, value);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void removeProperty(String name) throws WebOfTrustException {
- webOfTrustConnector.removeProperty(this, name);
- removePropertyPrivate(name);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setProperties(Map<String, String> properties) throws WebOfTrustException {
- for (Entry<String, String> oldProperty : getProperties().entrySet()) {
- if (!properties.containsKey(oldProperty.getKey())) {
- webOfTrustConnector.removeProperty(this, oldProperty.getKey());
- } else {
- webOfTrustConnector.setProperty(this, oldProperty.getKey(), properties.get(oldProperty.getKey()));
- }
- }
- for (Entry<String, String> newProperty : properties.entrySet()) {
- if (!getProperties().containsKey(newProperty.getKey())) {
- webOfTrustConnector.setProperty(this, newProperty.getKey(), newProperty.getValue());
- }
- }
- setPropertiesPrivate(properties);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setTrust(Identity target, int trustValue, String comment) throws WebOfTrustException {
- Validation.begin().isNotNull("Trust Target", target).isNotNull("Trust Comment", comment).isLessOrEqual("Trust Value", trustValue, 100).isGreaterOrEqual("Trust Value", trustValue, -100).check();
- webOfTrustConnector.setTrust(this, target, trustValue, comment);
- if (target instanceof DefaultIdentity) {
- ((DefaultIdentity) target).setTrustPrivate(this, new Trust(trustValue, trustValue, 0));
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void removeTrust(Identity target) throws WebOfTrustException {
- Validation.begin().isNotNull("Trust Target", target).check();
- webOfTrustConnector.removeTrust(this, target);
- if (target instanceof DefaultIdentity) {
- ((DefaultIdentity) target).setTrustPrivate(this, new Trust(null, null, null));
- }
- }
-
- //
- // OBJECT METHODS
- //
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int hashCode() {
- /* The hash of DefaultIdentity is fine. */
- return super.hashCode();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean equals(Object object) {
- /* The ID of the superclass is still enough. */
- return super.equals(object);
- }
-
}
package net.pterodactylus.sone.freenet.wot;
+import java.util.Collection;
import java.util.Map;
import java.util.Set;
/**
* Interface for web of trust identities, defining all functions that can be
- * performed on an identity. The identity is the main entry point for identity
- * management.
+ * performed on an identity. An identity is only a container for identity data
+ * and will not perform any updating in the WebOfTrust plugin itself.
*
* @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
*/
public boolean hasContext(String context);
/**
+ * Adds the given context to this identity.
+ *
+ * @param context
+ * The context to add
+ */
+ public void addContext(String context);
+
+ /**
+ * Sets all contexts of this identity.
+ *
+ * @param contexts
+ * All contexts of the identity
+ */
+ public void setContexts(Collection<String> contexts);
+
+ /**
+ * Removes the given context from this identity.
+ *
+ * @param context
+ * The context to remove
+ */
+ public void removeContext(String context);
+
+ /**
* Returns all properties of this identity.
*
* @return All properties of this identity
public String getProperty(String name);
/**
+ * Sets the property with the given name to the given value.
+ *
+ * @param name
+ * The name of the property
+ * @param value
+ * The value of the property
+ */
+ public void setProperty(String name, String value);
+
+ /**
+ * Sets all properties of this identity.
+ *
+ * @param properties
+ * The new properties of this identity
+ */
+ public void setProperties(Map<String, String> properties);
+
+ /**
+ * Removes the property with the given name.
+ *
+ * @param name
+ * The name of the property to remove
+ */
+ public void removeProperty(String name);
+
+ /**
* Retrieves the trust that this identity receives from the given own
* identity. If this identity is not in the own identity’s trust tree, a
* {@link Trust} is returned that has all its elements set to {@code null}.
*/
public Trust getTrust(OwnIdentity ownIdentity);
+ /**
+ * Sets the trust given by an own identity to this identity.
+ *
+ * @param ownIdentity
+ * The own identity that gave trust to this identity
+ * @param trust
+ * The trust given by the given own identity
+ */
+ public void setTrust(OwnIdentity ownIdentity, Trust trust);
+
+ /**
+ * Removes trust assignment from the given own identity for this identity.
+ *
+ * @param ownIdentity
+ * The own identity that removed the trust assignment for this
+ * identity
+ */
+ public void removeTrust(OwnIdentity ownIdentity);
+
}
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Logger;
import net.pterodactylus.sone.freenet.plugin.PluginException;
-import net.pterodactylus.util.collection.mapper.Mapper;
-import net.pterodactylus.util.collection.mapper.Mappers;
import net.pterodactylus.util.logging.Logging;
import net.pterodactylus.util.service.AbstractService;
private final WebOfTrustConnector webOfTrustConnector;
/** The context to filter for. */
- private volatile String context;
+ private final String context;
/** The currently known own identities. */
/* synchronize access on syncObject. */
- private Map<String, OwnIdentity> currentOwnIdentities = new HashMap<String, OwnIdentity>();
+ private final Map<String, OwnIdentity> currentOwnIdentities = new HashMap<String, OwnIdentity>();
+
+ /** The last time all identities were loaded. */
+ private volatile long identitiesLastLoaded;
/**
* Creates a new identity manager.
*
* @param webOfTrustConnector
* The Web of Trust connector
+ * @param context
+ * The context to focus on (may be {@code null} to ignore
+ * contexts)
*/
- public IdentityManager(WebOfTrustConnector webOfTrustConnector) {
+ public IdentityManager(WebOfTrustConnector webOfTrustConnector, String context) {
super("Sone Identity Manager", false);
this.webOfTrustConnector = webOfTrustConnector;
+ this.context = context;
}
//
//
/**
- * Sets the context to filter own identities and trusted identities for.
+ * Returns the last time all identities were loaded.
*
- * @param context
- * The context to filter for, or {@code null} to not filter
+ * @return The last time all identities were loaded (in milliseconds since
+ * Jan 1, 1970 UTC)
*/
- public void setContext(String context) {
- this.context = context;
+ public long getIdentitiesLastLoaded() {
+ return identitiesLastLoaded;
}
/**
Set<OwnIdentity> allOwnIdentities = getAllOwnIdentities();
for (OwnIdentity ownIdentity : allOwnIdentities) {
if (ownIdentity.getId().equals(id)) {
- return new DefaultOwnIdentity(webOfTrustConnector, ownIdentity);
+ return new DefaultOwnIdentity(ownIdentity);
}
}
return null;
* @return All own identities
*/
public Set<OwnIdentity> getAllOwnIdentities() {
- try {
- Set<OwnIdentity> ownIdentities = webOfTrustConnector.loadAllOwnIdentities();
- Map<String, OwnIdentity> newOwnIdentities = new HashMap<String, OwnIdentity>();
- for (OwnIdentity ownIdentity : ownIdentities) {
- newOwnIdentities.put(ownIdentity.getId(), ownIdentity);
- }
- checkOwnIdentities(newOwnIdentities);
- return Mappers.mappedSet(ownIdentities, new Mapper<OwnIdentity, OwnIdentity>() {
-
- /**
- * {@inheritDoc}
- */
- @Override
- @SuppressWarnings("synthetic-access")
- public OwnIdentity map(OwnIdentity input) {
- return new DefaultOwnIdentity(webOfTrustConnector, input);
- }
- });
- } catch (WebOfTrustException wote1) {
- logger.log(Level.WARNING, "Could not load all own identities!", wote1);
- return Collections.emptySet();
- }
+ return new HashSet<OwnIdentity>(currentOwnIdentities.values());
}
//
}
}
identitiesLoaded = true;
+ identitiesLastLoaded = System.currentTimeMillis();
} catch (WebOfTrustException wote1) {
logger.log(Level.WARNING, "WoT has disappeared!", wote1);
}
for (OwnIdentity oldOwnIdentity : currentOwnIdentities.values()) {
OwnIdentity newOwnIdentity = newOwnIdentities.get(oldOwnIdentity.getId());
if ((newOwnIdentity == null) || ((context != null) && oldOwnIdentity.hasContext(context) && !newOwnIdentity.hasContext(context))) {
- identityListenerManager.fireOwnIdentityRemoved(new DefaultOwnIdentity(webOfTrustConnector, oldOwnIdentity));
+ identityListenerManager.fireOwnIdentityRemoved(new DefaultOwnIdentity(oldOwnIdentity));
}
}
for (OwnIdentity currentOwnIdentity : newOwnIdentities.values()) {
OwnIdentity oldOwnIdentity = currentOwnIdentities.get(currentOwnIdentity.getId());
if (((oldOwnIdentity == null) && ((context == null) || currentOwnIdentity.hasContext(context))) || ((oldOwnIdentity != null) && (context != null) && (!oldOwnIdentity.hasContext(context) && currentOwnIdentity.hasContext(context)))) {
- identityListenerManager.fireOwnIdentityAdded(new DefaultOwnIdentity(webOfTrustConnector, currentOwnIdentity));
+ identityListenerManager.fireOwnIdentityAdded(new DefaultOwnIdentity(currentOwnIdentity));
}
}
package net.pterodactylus.sone.freenet.wot;
-import java.util.Map;
-import java.util.Set;
/**
* Defines a local identity, an own identity.
*/
public String getInsertUri();
- /**
- * Adds the given context to this identity.
- * <p>
- * This method is only called by the {@link IdentityManager}.
- *
- * @param context
- * The context to add
- * @throws WebOfTrustException
- * if an error occurs
- */
- public void addContext(String context) throws WebOfTrustException;
-
- /**
- * Sets all contexts of this identity.
- * <p>
- * This method is only called by the {@link IdentityManager}.
- *
- * @param contexts
- * All contexts of the identity
- * @throws WebOfTrustException
- * if an error occurs
- */
- public void setContexts(Set<String> contexts) throws WebOfTrustException;
-
- /**
- * Removes the given context from this identity.
- * <p>
- * This method is only called by the {@link IdentityManager}.
- *
- * @param context
- * The context to remove
- * @throws WebOfTrustException
- * if an error occurs
- */
- public void removeContext(String context) throws WebOfTrustException;
-
- /**
- * Sets the property with the given name to the given value.
- *
- * @param name
- * The name of the property
- * @param value
- * The value of the property
- * @throws WebOfTrustException
- * if an error occurs
- */
- public void setProperty(String name, String value) throws WebOfTrustException;
-
- /**
- * Sets all properties of this identity.
- * <p>
- * This method is only called by the {@link IdentityManager}.
- *
- * @param properties
- * The new properties of this identity
- * @throws WebOfTrustException
- * if an error occurs
- */
- public void setProperties(Map<String, String> properties) throws WebOfTrustException;
-
- /**
- * Removes the property with the given name.
- * <p>
- * This method is only called by the {@link IdentityManager}.
- *
- * @param name
- * The name of the property to remove
- * @throws WebOfTrustException
- * if an error occurs
- */
- public void removeProperty(String name) throws WebOfTrustException;
-
- /**
- * Sets the trust for the given target identity.
- *
- * @param target
- * The target to set the trust for
- * @param trustValue
- * The new trust value (from {@code -100} or {@code 100})
- * @param comment
- * The comment for the trust assignment
- * @throws WebOfTrustException
- * if an error occurs
- */
- public void setTrust(Identity target, int trustValue, String comment) throws WebOfTrustException;
-
- /**
- * Removes any trust assignment for the given target identity.
- *
- * @param target
- * The targe to remove the trust assignment for
- * @throws WebOfTrustException
- * if an error occurs
- */
- public void removeTrust(Identity target) throws WebOfTrustException;
-
}
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.pterodactylus.sone.freenet.plugin.PluginConnector;
import net.pterodactylus.sone.freenet.plugin.PluginException;
import net.pterodactylus.util.logging.Logging;
+import net.pterodactylus.util.number.Numbers;
import freenet.support.SimpleFieldSet;
import freenet.support.api.Bucket;
*
* @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
*/
-public class WebOfTrustConnector implements ConnectorListener {
+public class WebOfTrustConnector {
/** The logger. */
private static final Logger logger = Logging.getLogger(WebOfTrustConnector.class);
/** The name of the WoT plugin. */
private static final String WOT_PLUGIN_NAME = "plugins.WebOfTrust.WebOfTrust";
- /** A random connection identifier. */
- private static final String PLUGIN_CONNECTION_IDENTIFIER = "Sone-WoT-Connector-" + Math.abs(Math.random());
-
- /** The current reply. */
- private Reply reply;
+ /** Counter for connection identifiers. */
+ private final AtomicLong counter = new AtomicLong();
/** The plugin connector. */
private final PluginConnector pluginConnector;
*/
public WebOfTrustConnector(PluginConnector pluginConnector) {
this.pluginConnector = pluginConnector;
- pluginConnector.addConnectorListener(WOT_PLUGIN_NAME, PLUGIN_CONNECTION_IDENTIFIER, this);
}
//
* Stops the web of trust connector.
*/
public void stop() {
- pluginConnector.removeConnectorListener(WOT_PLUGIN_NAME, PLUGIN_CONNECTION_IDENTIFIER, this);
- synchronized (reply) {
- reply.notifyAll();
- }
+ /* does nothing. */
}
/**
String requestUri = fields.get("RequestURI" + ownIdentityCounter);
String insertUri = fields.get("InsertURI" + ownIdentityCounter);
String nickname = fields.get("Nickname" + ownIdentityCounter);
- DefaultOwnIdentity ownIdentity = new DefaultOwnIdentity(this, id, nickname, requestUri, insertUri);
- ownIdentity.setContextsPrivate(parseContexts("Contexts" + ownIdentityCounter + ".", fields));
- ownIdentity.setPropertiesPrivate(parseProperties("Properties" + ownIdentityCounter + ".", fields));
+ DefaultOwnIdentity ownIdentity = new DefaultOwnIdentity(id, nickname, requestUri, insertUri);
+ ownIdentity.setContexts(parseContexts("Contexts" + ownIdentityCounter + ".", fields));
+ ownIdentity.setProperties(parseProperties("Properties" + ownIdentityCounter + ".", fields));
ownIdentities.add(ownIdentity);
}
return ownIdentities;
* if an error occured talking to the Web of Trust plugin
*/
public Set<Identity> loadTrustedIdentities(OwnIdentity ownIdentity, String context) throws PluginException {
- Reply reply = performRequest(SimpleFieldSetConstructor.create().put("Message", "GetIdentitiesByScore").put("Truster", ownIdentity.getId()).put("Selection", "+").put("Context", (context == null) ? "" : context).get());
+ Reply reply = performRequest(SimpleFieldSetConstructor.create().put("Message", "GetIdentitiesByScore").put("Truster", ownIdentity.getId()).put("Selection", "+").put("Context", (context == null) ? "" : context).put("WantTrustValues", "true").get());
SimpleFieldSet fields = reply.getFields();
Set<Identity> identities = new HashSet<Identity>();
int identityCounter = -1;
}
String nickname = fields.get("Nickname" + identityCounter);
String requestUri = fields.get("RequestURI" + identityCounter);
- DefaultIdentity identity = new DefaultIdentity(this, id, nickname, requestUri);
- identity.setContextsPrivate(parseContexts("Contexts" + identityCounter + ".", fields));
- identity.setPropertiesPrivate(parseProperties("Properties" + identityCounter + ".", fields));
+ DefaultIdentity identity = new DefaultIdentity(id, nickname, requestUri);
+ identity.setContexts(parseContexts("Contexts" + identityCounter + ".", fields));
+ identity.setProperties(parseProperties("Properties" + identityCounter + ".", fields));
+ Integer trust = Numbers.safeParseInteger(fields.get("Trust" + identityCounter), null);
+ int score = Numbers.safeParseInteger(fields.get("Score" + identityCounter));
+ int rank = Numbers.safeParseInteger(fields.get("Rank" + identityCounter));
+ identity.setTrust(ownIdentity, new Trust(trust, score, rank));
identities.add(identity);
}
return identities;
* The fields to parse the contexts from
* @return The parsed contexts
*/
- private Set<String> parseContexts(String prefix, SimpleFieldSet fields) {
+ private static Set<String> parseContexts(String prefix, SimpleFieldSet fields) {
Set<String> contexts = new HashSet<String>();
int contextCounter = -1;
while (true) {
* The fields to parse the properties from
* @return The parsed properties
*/
- private Map<String, String> parseProperties(String prefix, SimpleFieldSet fields) {
+ private static Map<String, String> parseProperties(String prefix, SimpleFieldSet fields) {
Map<String, String> properties = new HashMap<String, String>();
int propertiesCounter = -1;
while (true) {
* @throws PluginException
* if the request could not be sent
*/
- private synchronized Reply performRequest(SimpleFieldSet fields, Bucket data) throws PluginException {
- reply = new Reply();
+ private Reply performRequest(SimpleFieldSet fields, Bucket data) throws PluginException {
+ final String identifier = "FCP-Command-" + System.currentTimeMillis() + "-" + counter.getAndIncrement();
+ final Reply reply = new Reply();
logger.log(Level.FINE, String.format("Sending FCP Request: %s", fields.get("Message")));
+ ConnectorListener connectorListener = new ConnectorListener() {
+
+ @Override
+ @SuppressWarnings("synthetic-access")
+ public void receivedReply(PluginConnector pluginConnector, SimpleFieldSet fields, Bucket data) {
+ String messageName = fields.get("Message");
+ logger.log(Level.FINEST, String.format("Received Reply from Plugin: %s", messageName));
+ synchronized (reply) {
+ reply.setFields(fields);
+ reply.setData(data);
+ reply.notify();
+ }
+ }
+ };
+ pluginConnector.addConnectorListener(WOT_PLUGIN_NAME, identifier, connectorListener);
synchronized (reply) {
- pluginConnector.sendRequest(WOT_PLUGIN_NAME, PLUGIN_CONNECTION_IDENTIFIER, fields, data);
try {
- reply.wait();
- } catch (InterruptedException ie1) {
- logger.log(Level.WARNING, String.format("Got interrupted while waiting for reply on %s.", fields.get("Message")), ie1);
+ pluginConnector.sendRequest(WOT_PLUGIN_NAME, identifier, fields, data);
+ while (reply.getFields() == null) {
+ try {
+ reply.wait();
+ } catch (InterruptedException ie1) {
+ logger.log(Level.WARNING, String.format("Got interrupted while waiting for reply on %s.", fields.get("Message")), ie1);
+ }
+ }
+ } finally {
+ pluginConnector.removeConnectorListener(WOT_PLUGIN_NAME, identifier, connectorListener);
}
}
logger.log(Level.FINEST, String.format("Received FCP Response for %s: %s", fields.get("Message"), (reply.getFields() != null) ? reply.getFields().get("Message") : null));
return reply;
}
- //
- // INTERFACE ConnectorListener
- //
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void receivedReply(PluginConnector pluginConnector, SimpleFieldSet fields, Bucket data) {
- String messageName = fields.get("Message");
- logger.log(Level.FINEST, String.format("Received Reply from Plugin: %s", messageName));
- synchronized (reply) {
- reply.setFields(fields);
- reply.setData(data);
- reply.notify();
- }
- }
-
/**
* Container for the data of the reply from a plugin.
*
import net.pterodactylus.sone.core.Core;
import net.pterodactylus.sone.core.FreenetInterface;
+import net.pterodactylus.sone.core.WebOfTrustUpdater;
import net.pterodactylus.sone.fcp.FcpInterface;
import net.pterodactylus.sone.freenet.PluginStoreConfigurationBackend;
import net.pterodactylus.sone.freenet.plugin.PluginConnector;
}
/** The version. */
- public static final Version VERSION = new Version(0, 8, 2);
+ public static final Version VERSION = new Version(0, 8, 3);
/** The logger. */
private static final Logger logger = Logging.getLogger(SonePlugin.class);
/* create web of trust connector. */
PluginConnector pluginConnector = new PluginConnector(pluginRespirator);
webOfTrustConnector = new WebOfTrustConnector(pluginConnector);
- identityManager = new IdentityManager(webOfTrustConnector);
- identityManager.setContext("Sone");
+ identityManager = new IdentityManager(webOfTrustConnector, "Sone");
+
+ /* create trust updater. */
+ WebOfTrustUpdater trustUpdater = new WebOfTrustUpdater(webOfTrustConnector);
+ trustUpdater.init();
/* create core. */
- core = new Core(oldConfiguration, freenetInterface, identityManager);
+ core = new Core(oldConfiguration, freenetInterface, identityManager, trustUpdater);
/* create the web interface. */
webInterface = new WebInterface(this);
return false;
}
} else {
- return false;
+ /*
+ * a null trust means that the trust updater has not yet
+ * received a trust value for this relation. if we return false,
+ * the post feed will stay empty until the trust updater has
+ * received trust values. to prevent this we simply assume that
+ * posts are visible if there is no trust.
+ */
+ return true;
}
if ((!postSone.equals(sone)) && !sone.hasFriend(postSone.getId()) && !sone.equals(post.getRecipient())) {
return false;
* The name of the link
* @return The created map containing the mappings
*/
- private Map<String, String> createLink(String target, String name) {
+ private static Map<String, String> createLink(String target, String name) {
Map<String, String> link = new HashMap<String, String>();
link.put("target", target);
link.put("name", name);
* append to the nickname
* @return The nickname with optional ID appendage
*/
- private String getAbbreviatedNickname(Identity identity, int length) {
+ private static String getAbbreviatedNickname(Identity identity, int length) {
return identity.getNickname() + ((length > 0) ? "@" + identity.getId().substring(0, length) : "");
}
private final TemplateContextFactory templateContextFactory;
/** The template for {@link PlainTextPart}s. */
- private final Template plainTextTemplate = TemplateParser.parse(new StringReader("<%text|html>"));
+ private static final Template plainTextTemplate = TemplateParser.parse(new StringReader("<%text|html>"));
/** The template for {@link FreenetLinkPart}s. */
- private final Template linkTemplate = TemplateParser.parse(new StringReader("<a class=\"<%cssClass|html>\" href=\"<%link|html>\" title=\"<%title|html>\"><%text|html></a>"));
+ private static final Template linkTemplate = TemplateParser.parse(new StringReader("<a class=\"<%cssClass|html>\" href=\"<%link|html>\" title=\"<%title|html>\"><%text|html></a>"));
/**
* Creates a new filter that runs its input through a {@link SoneTextParser}
* The part to render
*/
private void render(Writer writer, PostPart postPart) {
- renderLink(writer, "viewPost.html?post=" + postPart.getPost().getId(), getExcerpt(postPart.getPost().getText(), 20), SoneAccessor.getNiceName(postPart.getPost().getSone()), "in-sone");
+ SoneTextParser parser = new SoneTextParser(core, core);
+ SoneTextParserContext parserContext = new SoneTextParserContext(null, postPart.getPost().getSone());
+ try {
+ Iterable<Part> parts = parser.parse(parserContext, new StringReader(postPart.getPost().getText()));
+ StringBuilder excerpt = new StringBuilder();
+ for (Part part : parts) {
+ excerpt.append(part.getText());
+ if (excerpt.length() > 20) {
+ int lastSpace = excerpt.lastIndexOf(" ", 20);
+ if (lastSpace > -1) {
+ excerpt.setLength(lastSpace);
+ } else {
+ excerpt.setLength(20);
+ }
+ excerpt.append("…");
+ break;
+ }
+ }
+ renderLink(writer, "viewPost.html?post=" + postPart.getPost().getId(), excerpt.toString(), SoneAccessor.getNiceName(postPart.getPost().getSone()), "in-sone");
+ } catch (IOException ioe1) {
+ /* StringReader shouldn’t throw. */
+ }
}
/**
linkTemplate.render(templateContext, writer);
}
- //
- // STATIC METHODS
- //
-
- /**
- * Returns up to {@code length} characters from the given text, appending
- * “…” if the text is longer.
- *
- * @param text
- * The text to get an excerpt from
- * @param length
- * The maximum length of the excerpt (without the ellipsis)
- * @return The excerpt of the text
- */
- private static String getExcerpt(String text, int length) {
- String filteredText = text.replaceAll("(\r\n)+", "\r\n").replaceAll("\n+", "\n").replace("\r\n", " ").replace('\n', ' ');
- if (filteredText.length() > length) {
- return filteredText.substring(0, length) + "…";
- }
- return filteredText;
- }
-
}
import net.pterodactylus.sone.data.Profile;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.data.Sone.ShowCustomAvatars;
+import net.pterodactylus.sone.freenet.wot.OwnIdentity;
import net.pterodactylus.sone.freenet.wot.Trust;
import net.pterodactylus.util.template.Accessor;
import net.pterodactylus.util.template.ReflectionAccessor;
if (showCustomAvatars == ShowCustomAvatars.FOLLOWED) {
return currentSone.hasFriend(remoteSone.getId()) ? avatarId : null;
}
- Trust trust = core.getTrust(currentSone, remoteSone);
+ Trust trust = remoteSone.getIdentity().getTrust((OwnIdentity) currentSone.getIdentity());
if (trust == null) {
return null;
}
import net.pterodactylus.sone.data.Profile;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.data.Sone.SoneStatus;
+import net.pterodactylus.sone.freenet.wot.OwnIdentity;
import net.pterodactylus.sone.freenet.wot.Trust;
import net.pterodactylus.sone.web.WebInterface;
import net.pterodactylus.sone.web.ajax.GetTimesAjaxPage;
if (currentSone == null) {
return null;
}
- Trust trust = core.getTrust(currentSone, sone);
+ Trust trust = sone.getIdentity().getTrust((OwnIdentity) currentSone.getIdentity());
logger.log(Level.FINEST, String.format("Trust for %s by %s: %s", sone, currentSone, trust));
if (trust == null) {
return new Trust(null, null, null);
}
/**
- * Returns the text of this part.
+ * Returns the title of this part.
*
- * @return The text of this part
+ * @return The title of this part
*/
- public String getText() {
- return text;
+ public String getTitle() {
+ return title;
}
+ //
+ // PART METHODS
+ //
+
/**
- * Returns the title of this part.
+ * Returns the text of this part.
*
- * @return The title of this part
+ * @return The text of this part
*/
- public String getTitle() {
- return title;
+ @Override
+ public String getText() {
+ return text;
}
}
*/
public interface Part {
- /* no methods. */
+ /**
+ * Returns the text contained in this part. This should return plain text
+ * without any format information.
+ *
+ * @return The plain text of this part
+ */
+ public String getText();
}
}
//
+ // PART METHODS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getText() {
+ StringBuilder partText = new StringBuilder();
+ for (Part part : parts) {
+ partText.append(part.getText());
+ }
+ return partText.toString();
+ }
+
+ //
// ITERABLE METHODS
//
}
//
- // ACCESSORS
+ // PART METHODS
//
/**
*
* @return The text of this part
*/
+ @Override
public String getText() {
return text;
}
return post;
}
+ //
+ // PART METHODS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getText() {
+ return post.getText();
+ }
+
}
package net.pterodactylus.sone.text;
import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.sone.template.SoneAccessor;
/**
* {@link Part} implementation that stores a reference to a {@link Sone}.
return sone;
}
+ //
+ // PART METHODS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getText() {
+ return SoneAccessor.getNiceName(sone);
+ }
+
}
import net.pterodactylus.sone.core.SoneProvider;
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.util.io.Closer;
import net.pterodactylus.util.logging.Logging;
import freenet.keys.FreenetURI;
public Iterable<Part> parse(SoneTextParserContext context, Reader source) throws IOException {
PartContainer parts = new PartContainer();
BufferedReader bufferedReader = (source instanceof BufferedReader) ? (BufferedReader) source : new BufferedReader(source);
- String line;
- boolean lastLineEmpty = true;
- int emptyLines = 0;
- while ((line = bufferedReader.readLine()) != null) {
- if (line.trim().length() == 0) {
- if (lastLineEmpty) {
+ try {
+ String line;
+ boolean lastLineEmpty = true;
+ int emptyLines = 0;
+ while ((line = bufferedReader.readLine()) != null) {
+ if (line.trim().length() == 0) {
+ if (lastLineEmpty) {
+ continue;
+ }
+ parts.add(new PlainTextPart("\n"));
+ ++emptyLines;
+ lastLineEmpty = emptyLines == 2;
continue;
}
- parts.add(new PlainTextPart("\n"));
- ++emptyLines;
- lastLineEmpty = emptyLines == 2;
- continue;
- }
- emptyLines = 0;
- /*
- * lineComplete tracks whether the block you are parsing is the
- * first block of the line. this is important because sometimes you
- * have to add an additional line break.
- */
- boolean lineComplete = true;
- while (line.length() > 0) {
- int nextKsk = line.indexOf("KSK@");
- int nextChk = line.indexOf("CHK@");
- int nextSsk = line.indexOf("SSK@");
- int nextUsk = line.indexOf("USK@");
- int nextHttp = line.indexOf("http://");
- int nextHttps = line.indexOf("https://");
- int nextSone = line.indexOf("sone://");
- int nextPost = line.indexOf("post://");
- if ((nextKsk == -1) && (nextChk == -1) && (nextSsk == -1) && (nextUsk == -1) && (nextHttp == -1) && (nextHttps == -1) && (nextSone == -1) && (nextPost == -1)) {
- if (lineComplete && !lastLineEmpty) {
- parts.add(new PlainTextPart("\n" + line));
- } else {
- parts.add(new PlainTextPart(line));
+ emptyLines = 0;
+ /*
+ * lineComplete tracks whether the block you are parsing is the
+ * first block of the line. this is important because sometimes
+ * you have to add an additional line break.
+ */
+ boolean lineComplete = true;
+ while (line.length() > 0) {
+ int nextKsk = line.indexOf("KSK@");
+ int nextChk = line.indexOf("CHK@");
+ int nextSsk = line.indexOf("SSK@");
+ int nextUsk = line.indexOf("USK@");
+ int nextHttp = line.indexOf("http://");
+ int nextHttps = line.indexOf("https://");
+ int nextSone = line.indexOf("sone://");
+ int nextPost = line.indexOf("post://");
+ if ((nextKsk == -1) && (nextChk == -1) && (nextSsk == -1) && (nextUsk == -1) && (nextHttp == -1) && (nextHttps == -1) && (nextSone == -1) && (nextPost == -1)) {
+ if (lineComplete && !lastLineEmpty) {
+ parts.add(new PlainTextPart("\n" + line));
+ } else {
+ parts.add(new PlainTextPart(line));
+ }
+ break;
+ }
+ int next = Integer.MAX_VALUE;
+ LinkType linkType = null;
+ if ((nextKsk > -1) && (nextKsk < next)) {
+ next = nextKsk;
+ linkType = LinkType.KSK;
+ }
+ if ((nextChk > -1) && (nextChk < next)) {
+ next = nextChk;
+ linkType = LinkType.CHK;
+ }
+ if ((nextSsk > -1) && (nextSsk < next)) {
+ next = nextSsk;
+ linkType = LinkType.SSK;
+ }
+ if ((nextUsk > -1) && (nextUsk < next)) {
+ next = nextUsk;
+ linkType = LinkType.USK;
+ }
+ if ((nextHttp > -1) && (nextHttp < next)) {
+ next = nextHttp;
+ linkType = LinkType.HTTP;
+ }
+ if ((nextHttps > -1) && (nextHttps < next)) {
+ next = nextHttps;
+ linkType = LinkType.HTTPS;
+ }
+ if ((nextSone > -1) && (nextSone < next)) {
+ next = nextSone;
+ linkType = LinkType.SONE;
+ }
+ if ((nextPost > -1) && (nextPost < next)) {
+ next = nextPost;
+ linkType = LinkType.POST;
}
- break;
- }
- int next = Integer.MAX_VALUE;
- LinkType linkType = null;
- if ((nextKsk > -1) && (nextKsk < next)) {
- next = nextKsk;
- linkType = LinkType.KSK;
- }
- if ((nextChk > -1) && (nextChk < next)) {
- next = nextChk;
- linkType = LinkType.CHK;
- }
- if ((nextSsk > -1) && (nextSsk < next)) {
- next = nextSsk;
- linkType = LinkType.SSK;
- }
- if ((nextUsk > -1) && (nextUsk < next)) {
- next = nextUsk;
- linkType = LinkType.USK;
- }
- if ((nextHttp > -1) && (nextHttp < next)) {
- next = nextHttp;
- linkType = LinkType.HTTP;
- }
- if ((nextHttps > -1) && (nextHttps < next)) {
- next = nextHttps;
- linkType = LinkType.HTTPS;
- }
- if ((nextSone > -1) && (nextSone < next)) {
- next = nextSone;
- linkType = LinkType.SONE;
- }
- if ((nextPost > -1) && (nextPost < next)) {
- next = nextPost;
- linkType = LinkType.POST;
- }
- /* cut off “freenet:” from before keys. */
- if (((linkType == LinkType.KSK) || (linkType == LinkType.CHK) || (linkType == LinkType.SSK) || (linkType == LinkType.USK)) && (next >= 8) && (line.substring(next - 8, next).equals("freenet:"))) {
- next -= 8;
- line = line.substring(0, next) + line.substring(next + 8);
- }
+ /* cut off “freenet:” from before keys. */
+ if (((linkType == LinkType.KSK) || (linkType == LinkType.CHK) || (linkType == LinkType.SSK) || (linkType == LinkType.USK)) && (next >= 8) && (line.substring(next - 8, next).equals("freenet:"))) {
+ next -= 8;
+ line = line.substring(0, next) + line.substring(next + 8);
+ }
- /* if there is text before the next item, write it out. */
- if (lineComplete && !lastLineEmpty) {
- parts.add(new PlainTextPart("\n"));
- }
- if (next > 0) {
- parts.add(new PlainTextPart(line.substring(0, next)));
- line = line.substring(next);
- next = 0;
- }
- lineComplete = false;
+ /* if there is text before the next item, write it out. */
+ if (lineComplete && !lastLineEmpty) {
+ parts.add(new PlainTextPart("\n"));
+ }
+ if (next > 0) {
+ parts.add(new PlainTextPart(line.substring(0, next)));
+ line = line.substring(next);
+ next = 0;
+ }
+ lineComplete = false;
- if (linkType == LinkType.SONE) {
- if (line.length() >= (7 + 43)) {
- String soneId = line.substring(7, 50);
- Sone sone = soneProvider.getSone(soneId, false);
- if (sone == null) {
- /*
- * don’t use create=true above, we don’t want the
- * empty shell.
- */
- sone = new Sone(soneId);
+ if (linkType == LinkType.SONE) {
+ if (line.length() >= (7 + 43)) {
+ String soneId = line.substring(7, 50);
+ Sone sone = soneProvider.getSone(soneId, false);
+ if (sone == null) {
+ /*
+ * don’t use create=true above, we don’t want
+ * the empty shell.
+ */
+ sone = new Sone(soneId);
+ }
+ parts.add(new SonePart(sone));
+ line = line.substring(50);
+ } else {
+ parts.add(new PlainTextPart(line));
+ line = "";
}
- parts.add(new SonePart(sone));
- line = line.substring(50);
- } else {
- parts.add(new PlainTextPart(line));
- line = "";
+ continue;
}
- continue;
- }
- if (linkType == LinkType.POST) {
- if (line.length() >= (7 + 36)) {
- String postId = line.substring(7, 43);
- Post post = postProvider.getPost(postId, false);
- if ((post != null) && (post.getSone() != null)) {
- parts.add(new PostPart(post));
+ if (linkType == LinkType.POST) {
+ if (line.length() >= (7 + 36)) {
+ String postId = line.substring(7, 43);
+ Post post = postProvider.getPost(postId, false);
+ if ((post != null) && (post.getSone() != null)) {
+ parts.add(new PostPart(post));
+ } else {
+ parts.add(new PlainTextPart(line.substring(0, 43)));
+ }
+ line = line.substring(43);
} else {
- parts.add(new PlainTextPart(line.substring(0, 43)));
+ parts.add(new PlainTextPart(line));
+ line = "";
}
- line = line.substring(43);
- } else {
- parts.add(new PlainTextPart(line));
- line = "";
+ continue;
}
- continue;
- }
- Matcher matcher = whitespacePattern.matcher(line);
- int nextSpace = matcher.find(0) ? matcher.start() : line.length();
- String link = line.substring(0, nextSpace);
- String name = link;
- logger.log(Level.FINER, String.format("Found link: %s", link));
- logger.log(Level.FINEST, String.format("CHK: %d, SSK: %d, USK: %d", nextChk, nextSsk, nextUsk));
+ Matcher matcher = whitespacePattern.matcher(line);
+ int nextSpace = matcher.find(0) ? matcher.start() : line.length();
+ String link = line.substring(0, nextSpace);
+ String name = link;
+ logger.log(Level.FINER, String.format("Found link: %s", link));
+ logger.log(Level.FINEST, String.format("CHK: %d, SSK: %d, USK: %d", nextChk, nextSsk, nextUsk));
- if ((linkType == LinkType.KSK) || (linkType == LinkType.CHK) || (linkType == LinkType.SSK) || (linkType == LinkType.USK)) {
- FreenetURI uri;
- if (name.indexOf('?') > -1) {
- name = name.substring(0, name.indexOf('?'));
- }
- if (name.endsWith("/")) {
- name = name.substring(0, name.length() - 1);
- }
- try {
- uri = new FreenetURI(name);
- name = uri.lastMetaString();
- if (name == null) {
- name = uri.getDocName();
+ if ((linkType == LinkType.KSK) || (linkType == LinkType.CHK) || (linkType == LinkType.SSK) || (linkType == LinkType.USK)) {
+ FreenetURI uri;
+ if (name.indexOf('?') > -1) {
+ name = name.substring(0, name.indexOf('?'));
}
- if (name == null) {
- name = link.substring(0, Math.min(9, link.length()));
+ if (name.endsWith("/")) {
+ name = name.substring(0, name.length() - 1);
}
- boolean fromPostingSone = ((linkType == LinkType.SSK) || (linkType == LinkType.USK)) && (context != null) && (context.getPostingSone() != null) && link.substring(4, Math.min(link.length(), 47)).equals(context.getPostingSone().getId());
- parts.add(new FreenetLinkPart(link, name, fromPostingSone));
- } catch (MalformedURLException mue1) {
- /* not a valid link, insert as plain text. */
- parts.add(new PlainTextPart(link));
- } catch (NullPointerException npe1) {
- /* FreenetURI sometimes throws these, too. */
- parts.add(new PlainTextPart(link));
- } catch (ArrayIndexOutOfBoundsException aioobe1) {
- /* oh, and these, too. */
- parts.add(new PlainTextPart(link));
- }
- } else if ((linkType == LinkType.HTTP) || (linkType == LinkType.HTTPS)) {
- name = link.substring(linkType == LinkType.HTTP ? 7 : 8);
- int firstSlash = name.indexOf('/');
- int lastSlash = name.lastIndexOf('/');
- if ((lastSlash - firstSlash) > 3) {
- name = name.substring(0, firstSlash + 1) + "…" + name.substring(lastSlash);
- }
- if (name.endsWith("/")) {
- name = name.substring(0, name.length() - 1);
- }
- if (((name.indexOf('/') > -1) && (name.indexOf('.') < name.lastIndexOf('.', name.indexOf('/'))) || ((name.indexOf('/') == -1) && (name.indexOf('.') < name.lastIndexOf('.')))) && name.startsWith("www.")) {
- name = name.substring(4);
- }
- if (name.indexOf('?') > -1) {
- name = name.substring(0, name.indexOf('?'));
+ try {
+ uri = new FreenetURI(name);
+ name = uri.lastMetaString();
+ if (name == null) {
+ name = uri.getDocName();
+ }
+ if (name == null) {
+ name = link.substring(0, Math.min(9, link.length()));
+ }
+ boolean fromPostingSone = ((linkType == LinkType.SSK) || (linkType == LinkType.USK)) && (context != null) && (context.getPostingSone() != null) && link.substring(4, Math.min(link.length(), 47)).equals(context.getPostingSone().getId());
+ parts.add(new FreenetLinkPart(link, name, fromPostingSone));
+ } catch (MalformedURLException mue1) {
+ /* not a valid link, insert as plain text. */
+ parts.add(new PlainTextPart(link));
+ } catch (NullPointerException npe1) {
+ /* FreenetURI sometimes throws these, too. */
+ parts.add(new PlainTextPart(link));
+ } catch (ArrayIndexOutOfBoundsException aioobe1) {
+ /* oh, and these, too. */
+ parts.add(new PlainTextPart(link));
+ }
+ } else if ((linkType == LinkType.HTTP) || (linkType == LinkType.HTTPS)) {
+ name = link.substring(linkType == LinkType.HTTP ? 7 : 8);
+ int firstSlash = name.indexOf('/');
+ int lastSlash = name.lastIndexOf('/');
+ if ((lastSlash - firstSlash) > 3) {
+ name = name.substring(0, firstSlash + 1) + "…" + name.substring(lastSlash);
+ }
+ if (name.endsWith("/")) {
+ name = name.substring(0, name.length() - 1);
+ }
+ if (((name.indexOf('/') > -1) && (name.indexOf('.') < name.lastIndexOf('.', name.indexOf('/'))) || ((name.indexOf('/') == -1) && (name.indexOf('.') < name.lastIndexOf('.')))) && name.startsWith("www.")) {
+ name = name.substring(4);
+ }
+ if (name.indexOf('?') > -1) {
+ name = name.substring(0, name.indexOf('?'));
+ }
+ parts.add(new LinkPart(link, name));
}
- parts.add(new LinkPart(link, name));
+ line = line.substring(nextSpace);
}
- line = line.substring(nextSpace);
+ lastLineEmpty = false;
+ }
+ } finally {
+ if (bufferedReader != source) {
+ Closer.close(bufferedReader);
}
- lastLineEmpty = false;
}
for (int partIndex = parts.size() - 1; partIndex >= 0; --partIndex) {
Part part = parts.getPart(partIndex);
* @return The parsed ID, or {@code null} if there was no part matching the
* given string
*/
- private String getFieldId(FreenetRequest request, String partNameStart) {
+ private static String getFieldId(FreenetRequest request, String partNameStart) {
for (String partName : request.getHttpRequest().getParts()) {
if (partName.startsWith(partNameStart)) {
return partName.substring(partNameStart.length());
Album album = webInterface.getCore().getAlbum(albumId, false);
templateContext.set("albumRequested", true);
templateContext.set("album", album);
+ templateContext.set("page", request.getHttpRequest().getParam("page"));
return;
}
String imageId = request.getHttpRequest().getParam("image", null);
Integer fcpFullAccessRequiredInteger = Numbers.safeParseInteger(request.getHttpRequest().getPartAsStringFailsafe("fcp-full-access-required", 1), preferences.getFcpFullAccessRequired().ordinal());
FullAccessRequired fcpFullAccessRequired = FullAccessRequired.values()[fcpFullAccessRequiredInteger];
preferences.setFcpFullAccessRequired(fcpFullAccessRequired);
- boolean clearOnNextRestart = Boolean.parseBoolean(request.getHttpRequest().getPartAsStringFailsafe("clear-on-next-restart", 5));
- preferences.setClearOnNextRestart(clearOnNextRestart);
- boolean reallyClearOnNextRestart = Boolean.parseBoolean(request.getHttpRequest().getPartAsStringFailsafe("really-clear-on-next-restart", 5));
- preferences.setReallyClearOnNextRestart(reallyClearOnNextRestart);
webInterface.getCore().touchConfiguration();
if (fieldErrors.isEmpty()) {
throw new RedirectException(getPath());
templateContext.set("trust-comment", preferences.getTrustComment());
templateContext.set("fcp-interface-active", preferences.isFcpInterfaceActive());
templateContext.set("fcp-full-access-required", preferences.getFcpFullAccessRequired().ordinal());
- templateContext.set("clear-on-next-restart", preferences.isClearOnNextRestart());
- templateContext.set("really-clear-on-next-restart", preferences.isReallyClearOnNextRestart());
}
}
throw new RedirectException("index.html");
}
+ /* check for a couple of shortcuts. */
+ if (phrases.size() == 1) {
+ String phrase = phrases.get(0).getPhrase();
+
+ /* is it a Sone ID? */
+ redirectIfNotNull(getSoneId(phrase), "viewSone.html?sone=");
+
+ /* is it a post ID? */
+ redirectIfNotNull(getPostId(phrase), "viewPost.html?post=");
+
+ /* is it a reply ID? show the post. */
+ redirectIfNotNull(getReplyPostId(phrase), "viewPost.html?post=");
+
+ /* is it an album ID? */
+ redirectIfNotNull(getAlbumId(phrase), "imageBrowser.html?album=");
+
+ /* is it an image ID? */
+ redirectIfNotNull(getImageId(phrase), "imageBrowser.html?image=");
+ }
+
Set<Sone> sones = webInterface.getCore().getSones();
Set<Hit<Sone>> soneHits = getHits(sones, phrases, SoneStringGenerator.COMPLETE_GENERATOR);
* The string generator for the objects
* @return The hits for the given phrases
*/
- private <T> Set<Hit<T>> getHits(Collection<T> objects, List<Phrase> phrases, StringGenerator<T> stringGenerator) {
+ private static <T> Set<Hit<T>> getHits(Collection<T> objects, List<Phrase> phrases, StringGenerator<T> stringGenerator) {
Set<Hit<T>> hits = new HashSet<Hit<T>>();
for (T object : objects) {
String objectString = stringGenerator.generateString(object);
* The query to parse
* @return The parsed phrases
*/
- private List<Phrase> parseSearchPhrases(String query) {
+ private static List<Phrase> parseSearchPhrases(String query) {
List<String> parsedPhrases = null;
try {
parsedPhrases = StringEscaper.parseLine(query);
* The expression to search
* @return The score of the expression
*/
- private double calculateScore(List<Phrase> phrases, String expression) {
+ private static double calculateScore(List<Phrase> phrases, String expression) {
logger.log(Level.FINEST, String.format("Calculating Score for “%s”…", expression));
double optionalHits = 0;
double requiredHits = 0;
}
/**
+ * Throws a
+ * {@link net.pterodactylus.sone.web.page.FreenetTemplatePage.RedirectException}
+ * if the given object is not {@code null}, appending the object to the
+ * given target URL.
+ *
+ * @param object
+ * The object on which to redirect
+ * @param target
+ * The target of the redirect
+ * @throws RedirectException
+ * if {@code object} is not {@code null}
+ */
+ private static void redirectIfNotNull(String object, String target) throws RedirectException {
+ if (object != null) {
+ throw new RedirectException(target + object);
+ }
+ }
+
+ /**
+ * If the given phrase contains a Sone ID (optionally prefixed by
+ * “sone://”), returns said Sone ID, otherwise return {@code null}.
+ *
+ * @param phrase
+ * The phrase that maybe is a Sone ID
+ * @return The Sone ID, or {@code null}
+ */
+ private String getSoneId(String phrase) {
+ String soneId = phrase.startsWith("sone://") ? phrase.substring(7) : phrase;
+ return (webInterface.getCore().getSone(soneId, false) != null) ? soneId : null;
+ }
+
+ /**
+ * If the given phrase contains a post ID (optionally prefixed by
+ * “post://”), returns said post ID, otherwise return {@code null}.
+ *
+ * @param phrase
+ * The phrase that maybe is a post ID
+ * @return The post ID, or {@code null}
+ */
+ private String getPostId(String phrase) {
+ String postId = phrase.startsWith("post://") ? phrase.substring(7) : phrase;
+ return (webInterface.getCore().getPost(postId, false) != null) ? postId : null;
+ }
+
+ /**
+ * If the given phrase contains a reply ID (optionally prefixed by
+ * “reply://”), returns the ID of the post the reply belongs to, otherwise
+ * return {@code null}.
+ *
+ * @param phrase
+ * The phrase that maybe is a reply ID
+ * @return The reply’s post ID, or {@code null}
+ */
+ private String getReplyPostId(String phrase) {
+ String replyId = phrase.startsWith("reply://") ? phrase.substring(8) : phrase;
+ return (webInterface.getCore().getReply(replyId, false) != null) ? webInterface.getCore().getReply(replyId, false).getPost().getId() : null;
+ }
+
+ /**
+ * If the given phrase contains an album ID (optionally prefixed by
+ * “album://”), returns said album ID, otherwise return {@code null}.
+ *
+ * @param phrase
+ * The phrase that maybe is an album ID
+ * @return The album ID, or {@code null}
+ */
+ private String getAlbumId(String phrase) {
+ String albumId = phrase.startsWith("album://") ? phrase.substring(8) : phrase;
+ return (webInterface.getCore().getAlbum(albumId, false) != null) ? albumId : null;
+ }
+
+ /**
+ * If the given phrase contains an image ID (optionally prefixed by
+ * “image://”), returns said image ID, otherwise return {@code null}.
+ *
+ * @param phrase
+ * The phrase that maybe is an image ID
+ * @return The image ID, or {@code null}
+ */
+ private String getImageId(String phrase) {
+ String imageId = phrase.startsWith("image://") ? phrase.substring(8) : phrase;
+ return (webInterface.getCore().getImage(imageId, false) != null) ? imageId : null;
+ }
+
+ /**
* Converts a given object into a {@link String}.
*
* @param <T>
* @return The MIME type of the image, or “application/octet-stream” if the
* image type could not be detected
*/
- private String getMimeType(byte[] imageData) {
+ private static String getMimeType(byte[] imageData) {
ByteArrayInputStream imageDataInputStream = new ByteArrayInputStream(imageData);
try {
ImageInputStream imageInputStream = ImageIO.createImageInputStream(imageDataInputStream);
import net.pterodactylus.sone.web.page.FreenetRequest;
import net.pterodactylus.sone.web.page.PageToadlet;
import net.pterodactylus.sone.web.page.PageToadletFactory;
-import net.pterodactylus.util.cache.Cache;
-import net.pterodactylus.util.cache.CacheException;
-import net.pterodactylus.util.cache.CacheItem;
-import net.pterodactylus.util.cache.DefaultCacheItem;
-import net.pterodactylus.util.cache.MemoryCache;
-import net.pterodactylus.util.cache.ValueRetriever;
import net.pterodactylus.util.collection.SetBuilder;
import net.pterodactylus.util.collection.filter.Filters;
import net.pterodactylus.util.logging.Logging;
import net.pterodactylus.util.notify.Notification;
import net.pterodactylus.util.notify.NotificationManager;
import net.pterodactylus.util.notify.TemplateNotification;
+import net.pterodactylus.util.template.ClassPathTemplateProvider;
import net.pterodactylus.util.template.CollectionSortFilter;
import net.pterodactylus.util.template.ContainsFilter;
import net.pterodactylus.util.template.DateFilter;
import net.pterodactylus.util.template.MatchFilter;
import net.pterodactylus.util.template.ModFilter;
import net.pterodactylus.util.template.PaginationFilter;
-import net.pterodactylus.util.template.Provider;
import net.pterodactylus.util.template.ReflectionAccessor;
import net.pterodactylus.util.template.ReplaceFilter;
import net.pterodactylus.util.template.StoreFilter;
import net.pterodactylus.util.template.Template;
-import net.pterodactylus.util.template.TemplateContext;
import net.pterodactylus.util.template.TemplateContextFactory;
-import net.pterodactylus.util.template.TemplateException;
import net.pterodactylus.util.template.TemplateParser;
+import net.pterodactylus.util.template.TemplateProvider;
import net.pterodactylus.util.template.XmlFilter;
import net.pterodactylus.util.thread.Ticker;
import net.pterodactylus.util.version.Version;
* @param sonePlugin
* The Sone plugin
*/
- @SuppressWarnings("synthetic-access")
public WebInterface(SonePlugin sonePlugin) {
this.sonePlugin = sonePlugin;
formPassword = sonePlugin.pluginRespirator().getToadletContainer().getFormPassword();
templateContextFactory.addFilter("unique", new UniqueElementFilter());
templateContextFactory.addFilter("mod", new ModFilter());
templateContextFactory.addFilter("paginate", new PaginationFilter());
- templateContextFactory.addProvider(Provider.TEMPLATE_CONTEXT_PROVIDER);
- templateContextFactory.addProvider(new ClassPathTemplateProvider());
+ templateContextFactory.addProvider(TemplateProvider.TEMPLATE_CONTEXT_PROVIDER);
+ templateContextFactory.addProvider(new ClassPathTemplateProvider(WebInterface.class, "/templates/"));
templateContextFactory.addTemplateObject("webInterface", this);
templateContextFactory.addTemplateObject("formPassword", formPassword);
notificationManager.addNotification(imageInsertFailedNotification);
}
- /**
- * Template provider implementation that uses
- * {@link WebInterface#createReader(String)} to load templates for
- * inclusion.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
- */
- private class ClassPathTemplateProvider implements Provider {
-
- /** Cache for templates. */
- private final Cache<String, Template> templateCache = new MemoryCache<String, Template>(new ValueRetriever<String, Template>() {
-
- @Override
- @SuppressWarnings("synthetic-access")
- public CacheItem<Template> retrieve(String key) throws CacheException {
- Template template = findTemplate(key);
- if (template != null) {
- return new DefaultCacheItem<Template>(template);
- }
- return null;
- }
- });
-
- /**
- * {@inheritDoc}
- */
- @Override
- @SuppressWarnings("synthetic-access")
- public Template getTemplate(TemplateContext templateContext, String templateName) {
- try {
- return templateCache.get(templateName);
- } catch (CacheException ce1) {
- logger.log(Level.WARNING, String.format("Could not get template for %s!", templateName), ce1);
- return null;
- }
- }
-
- /**
- * Locates a template in the class path.
- *
- * @param templateName
- * The name of the template to load
- * @return The loaded template, or {@code null} if no template could be
- * found
- */
- @SuppressWarnings("synthetic-access")
- private Template findTemplate(String templateName) {
- Reader templateReader = createReader("/templates/" + templateName);
- if (templateReader == null) {
- return null;
- }
- Template template = null;
- try {
- template = TemplateParser.parse(templateReader);
- } catch (TemplateException te1) {
- logger.log(Level.WARNING, String.format("Could not parse template “%s” for inclusion!", templateName), te1);
- }
- return template;
- }
-
- }
-
}
import net.pterodactylus.sone.core.Core;
import net.pterodactylus.sone.data.Sone;
-import net.pterodactylus.sone.freenet.wot.Trust;
import net.pterodactylus.sone.web.WebInterface;
import net.pterodactylus.sone.web.page.FreenetRequest;
import net.pterodactylus.util.json.JsonObject;
return createErrorJsonObject("invalid-sone-id");
}
webInterface.getCore().distrustSone(currentSone, sone);
- Trust trust = webInterface.getCore().getTrust(currentSone, sone);
- if (trust == null) {
- return createErrorJsonObject("wot-plugin");
- }
- return createSuccessJsonObject().put("trustValue", trust.getExplicit());
+ return createSuccessJsonObject().put("trustValue", webInterface.getCore().getPreferences().getNegativeTrust());
}
}
* The Sones to convert to an array
* @return The Sones, sorted by name
*/
- private JsonArray getSones(Set<Sone> sones) {
+ private static JsonArray getSones(Set<Sone> sones) {
JsonArray soneArray = new JsonArray();
List<Sone> sortedSones = new ArrayList<Sone>(sones);
Collections.sort(sortedSones, Sone.NICE_NAME_COMPARATOR);
* The current Sone (may be {@code null})
* @return The current options
*/
- private JsonObject createJsonOptions(Sone currentSone) {
+ private static JsonObject createJsonOptions(Sone currentSone) {
JsonObject options = new JsonObject();
if (currentSone != null) {
options.put("ShowNotification/NewSones", currentSone.getOptions().getBooleanOption("ShowNotification/NewSones").get());
@Override
protected JsonObject createJsonObject(FreenetRequest request) {
final Sone currentSone = getCurrentSone(request.getToadletContext(), false);
- /* load Sones. */
- boolean loadAllSones = Boolean.parseBoolean(request.getHttpRequest().getParam("loadAllSones", "false"));
+ /* load Sones. always return the status of the current Sone. */
Set<Sone> sones = new HashSet<Sone>(Collections.singleton(getCurrentSone(request.getToadletContext(), false)));
- if (loadAllSones) {
- sones.addAll(webInterface.getCore().getSones());
- } else {
- String loadSoneIds = request.getHttpRequest().getParam("soneIds");
- if (loadSoneIds.length() > 0) {
- String[] soneIds = loadSoneIds.split(",");
- for (String soneId : soneIds) {
- /* just add it, we skip null further down. */
- sones.add(webInterface.getCore().getSone(soneId, false));
- }
+ String loadSoneIds = request.getHttpRequest().getParam("soneIds");
+ if (loadSoneIds.length() > 0) {
+ String[] soneIds = loadSoneIds.split(",");
+ for (String soneId : soneIds) {
+ /* just add it, we skip null further down. */
+ sones.add(webInterface.getCore().getSone(soneId, false));
}
}
JsonArray jsonSones = new JsonArray();
* The current Sone (may be {@code null})
* @return The current options
*/
- private JsonObject createJsonOptions(Sone currentSone) {
+ private static JsonObject createJsonOptions(Sone currentSone) {
JsonObject options = new JsonObject();
if (currentSone != null) {
options.put("ShowNotification/NewSones", currentSone.getOptions().getBooleanOption("ShowNotification/NewSones").get());
Time time = getTime(post.getTime());
postTime.put("timeText", time.getText());
postTime.put("refreshTime", time.getRefresh() / Time.SECOND);
- postTime.put("tooltip", dateFormat.format(new Date(post.getTime())));
+ synchronized (dateFormat) {
+ postTime.put("tooltip", dateFormat.format(new Date(post.getTime())));
+ }
postTimes.put(id, postTime);
}
}
Time time = getTime(reply.getTime());
replyTime.put("timeText", time.getText());
replyTime.put("refreshTime", time.getRefresh() / Time.SECOND);
- replyTime.put("tooltip", dateFormat.format(new Date(reply.getTime())));
+ synchronized (dateFormat) {
+ replyTime.put("tooltip", dateFormat.format(new Date(reply.getTime())));
+ }
replyTimes.put(id, replyTime);
}
}
* @return {@code true} if the form password (given as “formPassword”) is
* required, {@code false} otherwise
*/
+ @SuppressWarnings("static-method")
protected boolean needsFormPassword() {
return true;
}
* @return {@code true} if the user needs to be logged in to use this page,
* {@code false} otherwise
*/
+ @SuppressWarnings("static-method")
protected boolean requiresLogin() {
return true;
}
*
* @return A reply signaling success
*/
- protected JsonObject createSuccessJsonObject() {
+ protected static JsonObject createSuccessJsonObject() {
return new JsonObject().put("success", true);
}
* The error that has occured
* @return The JSON object, signalling failure and the error code
*/
- protected JsonObject createErrorJsonObject(String error) {
+ protected static JsonObject createErrorJsonObject(String error) {
return new JsonObject().put("success", false).put("error", error);
}
import net.pterodactylus.sone.core.Core;
import net.pterodactylus.sone.data.Sone;
-import net.pterodactylus.sone.freenet.wot.Trust;
import net.pterodactylus.sone.web.WebInterface;
import net.pterodactylus.sone.web.page.FreenetRequest;
import net.pterodactylus.util.json.JsonObject;
return createErrorJsonObject("invalid-sone-id");
}
webInterface.getCore().trustSone(currentSone, sone);
- Trust trust = webInterface.getCore().getTrust(currentSone, sone);
- if (trust == null) {
- return createErrorJsonObject("wot-plugin");
- }
- return createSuccessJsonObject().put("trustValue", trust.getExplicit());
+ return createSuccessJsonObject().put("trustValue", webInterface.getCore().getPreferences().getPositiveTrust());
}
}
import net.pterodactylus.sone.core.Core;
import net.pterodactylus.sone.data.Sone;
-import net.pterodactylus.sone.freenet.wot.Trust;
import net.pterodactylus.sone.web.WebInterface;
import net.pterodactylus.sone.web.page.FreenetRequest;
import net.pterodactylus.util.json.JsonObject;
return createErrorJsonObject("invalid-sone-id");
}
webInterface.getCore().untrustSone(currentSone, sone);
- Trust trust = webInterface.getCore().getTrust(currentSone, sone);
- if (trust == null) {
- return createErrorJsonObject("wot-plugin");
- }
- return createSuccessJsonObject().put("trustValue", trust.getExplicit());
+ return createSuccessJsonObject().put("trustValue", (String) null);
}
}
* The request to serve
* @return The title of the page
*/
+ @SuppressWarnings("static-method")
protected String getPageTitle(FreenetRequest request) {
return null;
}
*
* @return Additional style sheets to load
*/
+ @SuppressWarnings("static-method")
protected Collection<String> getStyleSheets() {
return Collections.emptySet();
}
*
* @return The URL of the shortcut icon, or {@code null} for no icon
*/
+ @SuppressWarnings("static-method")
protected String getShortcutIcon() {
return null;
}
* The request that is processed
* @return The URL to redirect to, or {@code null} to not redirect
*/
+ @SuppressWarnings("static-method")
protected String getRedirectTarget(FreenetRequest request) {
return null;
}
* The request for which to return the link nodes
* @return All link nodes that should be added to the HTML head
*/
+ @SuppressWarnings("static-method")
protected List<Map<String, String>> getAdditionalLinkNodes(FreenetRequest request) {
return Collections.emptyList();
}
* @return {@code true} if this page should only be allowed for hosts with
* full access, {@code false} to allow this page for any host
*/
+ @SuppressWarnings("static-method")
protected boolean isFullAccessOnly() {
return false;
}
Page.Options.Option.ShowAvatars.Followed.Description=Nur benutzerdefinierte Avatare von Sones, denen Sie folgen, anzeigen.
Page.Options.Option.ShowAvatars.ManuallyTrusted.Description=Nur benutzerdefinierte Avatare von Sones, denen Sie manuell einen Vertrauenswert von mehr als 0 zugewiesen haben, anzeigen.
Page.Options.Option.ShowAvatars.Trusted.Description=Nur benutzerdefinierte Avatare von Sones, die einen berechneten Vertrauenswert von mehr als 0 haben, anzeigen.
-Page.Options.Option.ShowAvatars.Always.Description=Immer benutzerdefinierte Avatare anzeigen. Warnung: Benutzerdefinierte Avatare können beliebiges Bildmaterial enthalten!
+Page.Options.Option.ShowAvatars.Always.Description=Immer benutzerdefinierte Avatare anzeigen. Warnung: Benutzerdefinierte Avatare können beliebiges Bildmaterial enthalten!
Page.Options.Section.RuntimeOptions.Title=Laufzeitverhalten
Page.Options.Option.InsertionDelay.Description=Anzahl der Sekunden, die vor dem Hochladen einer Sone nach einer Änderung gewartet wird.
Page.Options.Option.PostsPerPage.Description=Anzahl der Nachrichten pro Seite.
+Page.Options.Option.ImagesPerPage.Description=Anzahl der Bilder pro Seite.
Page.Options.Option.CharactersPerPost.Description=Die Anzahl der Zeichen, die eine Nachricht enthalten muss, damit sie gekürzt angezeigt wird (-1 für „nie kürzen“). Die Anzahl der tatsächlich angezeigten Zeichen wird in der nächsten Option konfiguriert.
Page.Options.Option.PostCutOffLength.Description=Die Anzahl der Zeichen, die von einer gekürzten Nachricht sichtbar sind (siehe Option hierüber).
Page.Options.Option.RequireFullAccess.Description=Zugriff auf Sone für alle Rechner, die keinen vollen Zugriff haben, unterbinden.
Page.Index.Button.Post=Abschicken!
Page.Index.PostList.Title=Nachrichtenliste
Page.Index.PostList.Text.NoPostYet=Bisher hat noch niemand etwas geschrieben. Sie sollten sofort damit anfangen!
+Page.Index.PostList.Text.FollowSomeSones=Oder vielleicht folgen Sie gar keinen Sones? Werfen Sie doch mal einen Blick auf {link}bekannte Sones{/link} und folgen Sie Sones, die interessant aussehen!
Page.New.Title=Neue Nachrichten und Antworten - Sone
Page.New.Page.Title=Neue Nachrichten und Antworten
WebInterface.DefaultText.EditImage.Title=Bildtitel
WebInterface.DefaultText.EditImage.Description=Bildbeschreibung
WebInterface.DefaultText.Option.PostsPerPage=Anzahl der Nachrichten pro Seite
+WebInterface.DefaultText.Option.ImagesPerPage=Anzahl der Bilder pro Seite
WebInterface.DefaultText.Option.CharactersPerPost=Anzahl der Zeichen, die eine Nachricht haben muss, damit er gekürzt wird
-WebInterface.DefaultText.Option.PostCutOffLength=Anzahl der Zeichen, die von einer gekürzten Nachricht angezeigt werden
+WebInterface.DefaultText.Option.PostCutOffLength=Anzahl der Zeichen, die von einer gekürzten Nachricht angezeigt werden
WebInterface.DefaultText.Option.PositiveTrust=Der positive Vertrauenswert
WebInterface.DefaultText.Option.NegativeTrust=Der negative Vertrauenswert
WebInterface.DefaultText.Option.TrustComment=Der Kommentar für die Vertrauenszuweisung
WebInterface.ClickToShow.Replies=Hier klicken, um ausgeblendete Antworten zu zeigen.
WebInterface.VersionInformation.CurrentVersion=Aktuelle Version:
WebInterface.VersionInformation.LatestVersion=Neueste Version:
+WebInterface.VersionInformation.Homepage=Homepage
Notification.ClickHereToRead=Hier klicken, um den vollen Text der Benachrichtigung zu lesen.
Notification.FirstStart.Text=Es scheint, als wäre dies das erste Mal, dass Sie Sone starten. Legen Sie eine neue Sone an und folgen Sie anderen Sones!
Page.Index.Button.Post=Post!
Page.Index.PostList.Title=Post Feed
Page.Index.PostList.Text.NoPostYet=Nobody has written any posts yet. You should probably start it right now!
+Page.Index.PostList.Text.FollowSomeSones=Or maybe you are not following any Sones? Take a look at the list of {link}known Sones{/link} and follow whoever looks interesting!
Page.New.Title=New Posts and Replies - Sone
Page.New.Page.Title=New Posts and Replies
WebInterface.ClickToShow.Replies=Click here to show hidden replies.
WebInterface.VersionInformation.CurrentVersion=Current Version:
WebInterface.VersionInformation.LatestVersion=Latest Version:
+WebInterface.VersionInformation.Homepage=Homepage
Notification.ClickHereToRead=Click here to read the full text of the notification.
Notification.FirstStart.Text=This seems to be the first time you start Sone. To start, create a new Sone from a web of trust identity and start following other Sones.
Navigation.Menu.Sone.Item.EditProfile.Tooltip=Editer le profil de votre Sone
Navigation.Menu.Sone.Item.ImageBrowser.Name=Images
Navigation.Menu.Sone.Item.ImageBrowser.Tooltip=Gérer vos images
-Navigation.Menu.Sone.Item.DeleteSone.Name=Efface Sone
-Navigation.Menu.Sone.Item.DeleteSone.Tooltip=Efface les Sones actuels
+Navigation.Menu.Sone.Item.DeleteSone.Name=Effacer ce Sone
+Navigation.Menu.Sone.Item.DeleteSone.Tooltip=Effacer les Sones actuels
Navigation.Menu.Sone.Item.Logout.Name=Déconnexion
Navigation.Menu.Sone.Item.Logout.Tooltip=Vous déconnecte de votre Sone actuel
Navigation.Menu.Sone.Item.Options.Name=Options
Navigation.Menu.Sone.Item.Options.Tooltip=Options concernant le plugin Sone
-Navigation.Menu.Sone.Item.Rescue.Name=Réparation
-Navigation.Menu.Sone.Item.Rescue.Tooltip=Réparer Sone
+Navigation.Menu.Sone.Item.Rescue.Name=Récupération
+Navigation.Menu.Sone.Item.Rescue.Tooltip=Récupération de votre Sone
Navigation.Menu.Sone.Item.About.Name=A propos
Navigation.Menu.Sone.Item.About.Tooltip=Informations à propos de Sone
Page.About.Title=A propos de - Sone
Page.About.Page.Title=A propos
-Page.About.Flattr.Description=Si vous aimez Sone et aue vous voulez me récompenser, vous pouvez utiliser le bouton Flattr au bas de la page de recherche. Flattr est un système de micro-payement non anonyme comparable au principe du pouboire via internet où le montant que chaque utilisateur dépense est limité (le minimum est de 2€ par mois). Plus d'informations sur {link}flattr.com{/link}.
-Page.About.Homepage.Title=Paage d'accueil
+Page.About.Flattr.Description=Si vous aimez Sone et que vous voulez me récompenser, vous pouvez utiliser le bouton Flattr au bas de la page de recherche. Flattr est un système de micro-payement non anonyme comparable au principe du pourboire via internet où le montant que chaque utilisateur dépense est limité (le minimum est de 2€ par mois). Plus d'informations sur {link}flattr.com{/link}.
+Page.About.Homepage.Title=Page d'accueil
Page.About.Homepage.Description=Vous pouvez trouver plus d'informations ainsi que le code source de Sone sur la {link}page d'accueil{/link}.
Page.About.License.Title=Licence
Page.Options.Page.Description=Ces options influencent le comportement de l'exécution du plugin Sone
Page.Options.Section.SoneSpecificOptions.Title=Options spécifiques à Sone
Page.Options.Section.SoneSpecificOptions.NotLoggedIn=Ces options sont uniquement disponibles si vous êtes {link}connecté{/link}.
-Page.Options.Section.SoneSpecificOptions.LoggedIn=Ces options sont uniquement disponibles pour le Sone entant que tel vous êtes enregistré.
+Page.Options.Section.SoneSpecificOptions.LoggedIn=Ces options sont uniquement disponibles pour le Sone actif.
Page.Options.Option.AutoFollow.Description=si un nouveau Sone est découvert, automatiquement le suivre. Veuillez noter que cela suivra uniquement les Sones qui seront découverts après que cette option soit activée!
-Page.Options.Option.EnableSoneInsertNotifications.Description=Si activé, cela affichera les notifications chaque fois que votre Sone insère un message ou qu'il a fini d'insérer.
+Page.Options.Option.EnableSoneInsertNotifications.Description=Si cette option est activée, Sone affichera les notifications chaque fois que vous insèrerez un message ou qu'il sera correctement inséré.
Page.Options.Option.ShowNotificationNewSones.Description=Affiche les notifications des nouveaux Sones.
Page.Options.Option.ShowNotificationNewPosts.Description=Affiche une notification lors d'un nouveau message.
Page.Options.Option.ShowNotificationNewReplies.Description=Affiche une notification lors d'une nouvelle réponse.
Page.Options.Option.ShowAvatars.Always.Description=Montre tout le temps les avatars personnalisés.Attention: certains avatars peuvent être offensants !
Page.Options.Section.RuntimeOptions.Title=Comportement runtime
Page.Options.Option.InsertionDelay.Description=Le nombre de secondes que l'inserteur de Sone attends après une modification d'un Sone avant qu'elle soit insérée.
-Page.Options.Option.PostsPerPage.Description=Le nombre de message à afficher par page avant que les boutons de contrôle de page sont affichés.
+Page.Options.Option.PostsPerPage.Description=Le nombre de message à afficher par page avant que les boutons de pagination soit affichés.
+Page.Options.Option.ImagesPerPage.Description=Le nombre de message à afficher par page avant que les boutons de pagination soit affichés.
Page.Options.Option.CharactersPerPost.Description=Le nombre de caractères à afficher par message avant que le lien proposant de voir l'intégralité ne soit proposé (-1 pour désactiver). La taille du composant est determinée par l'option ci-desssous.
-Page.Options.Option.PostCutOffLength.Description=Le nombre de charactère à afficher avant que le message ne soit considéré comme trops long. (voir option du dessus)
-Page.Options.Option.RequireFullAccess.Description=Que ce soit pour refuser l'accès à Sone à tout hôte à qui un accès complet n'a pas été accordé.
+Page.Options.Option.PostCutOffLength.Description=Le nombre de charactère à afficher avant que le message ne soit considéré comme trop long. (voir option du dessus)
+Page.Options.Option.RequireFullAccess.Description=Pour refuser l'accès à Sone à tout hôte à qui un accès complet n'a pas été accordé.
Page.Options.Section.TrustOptions.Title=Réglages de confiance
Page.Options.Option.PositiveTrust.Description=La quantité de note de confiance positive que vous voulez assigner à d'autres Sones en cochant la case en dessous d'un message ou d'une réponse.
Page.Options.Option.NegativeTrust.Description=La quantité de note de confiance que vous voulez assigner à d'autres Sones en cliquand le X rouge en dessous d'un message ou d'une réponse. Cette valeur devrait être négative.
Page.Options.Option.TrustComment.Description=Le commentaire qui sera mis dans le web of trust pour chaque note de confiance que vous assignez de Sone.
Page.Options.Section.FcpOptions.Title=Réglages de l'Interface FCP
-Page.Options.Option.FcpInterfaceActive.Description=Activer l'interface FCP aafin de permettre à d'autres plugins et clients à distance d'accéder votre plugin Sone.
+Page.Options.Option.FcpInterfaceActive.Description=Activer l'interface FCP afin de permettre à d'autres plugins et clients à distance d'accéder votre plugin Sone.
Page.Options.Option.FcpFullAccessRequired.Description=Requière une connexion FCP d'hôtes autorisés (Veuillez voir votre {link}configuration du noeud, section “FCP”{/link})
Page.Options.Option.FcpFullAccessRequired.Value.No=Non
Page.Options.Option.FcpFullAccessRequired.Value.Writing=Pour accès à l'écriture
Page.Options.Option.FcpFullAccessRequired.Value.Always=toujours
Page.Options.Section.Cleaning.Title=Nettoyer
-Page.Options.Option.ClearOnNextRestart.Description=Réinitialiser la configuration du plugin Sone au prochain redémarrage. Attention! {strong}Cela détruira tous vos Sones{/strong}. Soyez sûr d'avoir sauvegardé tout ce dont vous avez besoin! Vous devez également choisir "vrai" à l'option suivante pour procéder à la réinitialisation.
-Page.Options.Option.ReallyClearOnNextRestart.Description=Choisir "oui" pour cette option si vous voulez vraiment{strong}vraiment{/strong} effacer la configuration au prochain redémarrage.
+Page.Options.Option.ClearOnNextRestart.Description=Réinitialiser la configuration du plugin Sone au prochain redémarrage. Attention! {strong}Cela détruira tous vos Sones{/strong}. Soyez sûr d'avoir sauvegardé tout ce dont vous avez besoin! Vous devez également choisir "Oui" à l'option suivante pour procéder à la réinitialisation.
+Page.Options.Option.ReallyClearOnNextRestart.Description=Choisir "Oui" pour cette option si vous voulez vraiment{strong}vraiment{/strong} effacer la configuration au prochain redémarrage.
Page.Options.Warnings.ValueNotChanged=Cette option n'a pas été modifiée car la valeur que vous avez spécifiée n'est pas valide.
Page.Options.Button.Save=Enregistrer
Page.DeleteSone.Title=Effacer Sone - Sone
Page.DeleteSone.Page.Title=Effacer Sone “{sone}”?
-Page.DeleteSone.Page.Description=Ceci n'effacera pas le Sone de Freenet(car ceci est impossible), celaa déconnectera seulement votre identité Web of Trust de Sone.
+Page.DeleteSone.Page.Description=Ceci n'effacera pas le Sone de Freenet(car ceci est impossible), cela déconnectera seulement votre identité Web of Trust de Sone.
Page.DeleteSone.Button.Yes=Oui, effacer.
Page.DeleteSone.Button.No=Non, ne pas effacer.
Page.Index.Button.Post=Envoyer!
Page.Index.PostList.Title=Envoyer du contenu
Page.Index.PostList.Text.NoPostYet=Personne n'a encore écrit de message. vous devriez probablement commencer maintenant!
+Page.Index.PostList.Text.FollowSomeSones=Peut-être ne suivez vous pas encore de Sones? Jetez un oeil à la liste des {link}Sones connus{/link} et suivez ceux qui pourrait vous intéresser!
Page.New.Title=Nouveaux messages et réponses - Sone
Page.New.Page.Title=Nouveaux messages et réponses
Page.EditProfile.Title=Editer le profil - Sone
Page.EditProfile.Page.Title=Éditer le profil
Page.EditProfile.Page.Description=Sur cette page, vous pouvez entrer les données de votre profil.
-Page.EditProfile.Page.Hint.Optionality=Veuillez noter que chaque champ de ce profil est optionnel! Vous n'êtes pas obligés de remplir quoi que ce soit ici! Tout ce que vous remplissez ici serq probqblement stocké dans Freenet pour très longtemps!
+Page.EditProfile.Page.Hint.Optionality=Veuillez noter que chaque champ de ce profil est optionnel! Vous n'êtes pas obligés de remplir quoi que ce soit ici! Tout ce que vous remplissez ici sera probablement stocké dans Freenet pour très longtemps!
Page.EditProfile.Label.FirstName=Prénom:
Page.EditProfile.Label.MiddleName=Prénom(s):
Page.EditProfile.Label.LastName=Nom de famille:
Page.EditProfile.Avatar.Description=Vous pouvez selectionner une de vos images comme avatar. Elle ne doit pas dépasser la taille de 64x64 pixels car c'est la taille la plus grande vue par les autre. (La taille 80x80 est réservée pour l'entête).
Page.EditProfile.Avatar.Delete=Pas d'avatar
Page.EditProfile.Fields.Title=Champs personnalisés
-Page.EditProfile.Fields.Description=Vous pouvez ajouter ici des champs personalisés à votre profil. Ces champs peuvent contenir tout ce que vous voulez et être aussi laconique ou aussi long que vous le souhaitez. Veuillez juste vous souvenir que quand on parle d'anonymat, parfois le moins, le mieux.
+Page.EditProfile.Fields.Description=Vous pouvez ajouter ici des champs personalisés à votre profil. Ces champs peuvent contenir tout ce que vous voulez et être aussi laconique ou aussi long que vous le souhaitez. Gardez à l'esprit qu'en terme d'anonymat, moins vous en dite, mieux c'est!
Page.EditProfile.Fields.Button.Edit=Éditer
Page.EditProfile.Fields.Button.MoveUp=Déplacer vers le haut
Page.EditProfile.Fields.Button.MoveDown=Déplacer vers le bas
Page.ViewSone.WriteAMessage=Vous pouvez écrire un message à ce Sone ici. Veuillez noter que tout le monde sera capable de lire ce message!
Page.ViewSone.PostList.Title=Messages par {sone}
Page.ViewSone.PostList.Text.NoPostYet=Ce Sone n'as encore rien envoyé.
-Page.ViewSone.Profile.Title=Profil
+Page.ViewSone.Profile.Title=Profile
Page.ViewSone.Profile.Label.Name=Nom
Page.ViewSone.Profile.Label.Albums=Albums
-Page.ViewSone.Profile.Albums.Text.All=All Albums
-Page.ViewSone.Profile.Name.WoTLink=Profil Web of trust
+Page.ViewSone.Profile.Albums.Text.All=Tous les albums
+Page.ViewSone.Profile.Name.WoTLink=Profile Web of trust
Page.ViewSone.Replies.Title=Messages {sone} a répondu à
Page.ViewPost.Title=Voir message - Sone
Page.UnfollowSone.Title=Ne plus suivre Sone - Sone
-Page.ImageBrowser.Title=Image Browser - Sone
+Page.ImageBrowser.Title=Explorateur d'images - Sone
Page.ImageBrowser.Album.Title=Album “{album}”
-Page.ImageBrowser.Album.Error.NotFound.Text=l'Album recherché n'est pas disponible. Il est possible qu'il ne soit pas encore mis à jour, ou qu'il est été dupprimé.
+Page.ImageBrowser.Album.Error.NotFound.Text=l'Album recherché n'est pas disponible. Il est possible qu'il ne soit pas encore mis à jour, ou qu'il est été supprimé.
Page.ImageBrowser.Sone.Title=Albums de {sone}
Page.ImageBrowser.Sone.Error.NotFound.Text=Le Sone recherché ne peut pas être trouvé. Il est possible qu'il ne soit pas encore téléchargé.
Page.ImageBrowser.Header.Albums=Albums
Page.ImageBrowser.Header.Images=Images
Page.ImageBrowser.Link.All=Tous les Sones
-Page.ImageBrowser.CreateAlbum.Button.CreateAlbum=Creer un Album
-Page.ImageBrowser.Album.Edit.Title=Editer l'Album
-Page.ImageBrowser.Album.Delete.Title=Supprimer l'Album
-Page.ImageBrowser.Album.Label.AlbumImage=Album d'Images:
-Page.ImageBrowser.Album.Label.Title=Title:
+Page.ImageBrowser.CreateAlbum.Button.CreateAlbum=Creer un album
+Page.ImageBrowser.Album.Edit.Title=Editer l'album
+Page.ImageBrowser.Album.Delete.Title=Supprimer l'album
+Page.ImageBrowser.Album.Label.AlbumImage=Album d'images:
+Page.ImageBrowser.Album.Label.Title=Titre:
Page.ImageBrowser.Album.Label.Description=Description:
-Page.ImageBrowser.Album.AlbumImage.Choose=Vhoisissez un Album d'images…
-Page.ImageBrowser.Album.Button.Save=Sauver l'Album
-Page.ImageBrowser.Album.Button.Delete=Supprimer l'Album
+Page.ImageBrowser.Album.AlbumImage.Choose=Choisissez un album d'images…
+Page.ImageBrowser.Album.Button.Save=Sauver l'album
+Page.ImageBrowser.Album.Button.Delete=Supprimer l'album
Page.ImageBrowser.Image.Edit.Title=Editer l'image
-Page.ImageBrowser.Image.Title.Label=Title:
+Page.ImageBrowser.Image.Title.Label=Titre:
Page.ImageBrowser.Image.Description.Label=Description:
Page.ImageBrowser.Image.Button.MoveLeft=◀
-Page.ImageBrowser.Image.Button.Save=Save Image
+Page.ImageBrowser.Image.Button.Save=Sauvegarder l'image
Page.ImageBrowser.Image.Button.MoveRight=►
-Page.ImageBrowser.Image.Delete.Title=Supprimer l'Image
-Page.ImageBrowser.Image.Button.Delete=Supprimer l'Image
+Page.ImageBrowser.Image.Delete.Title=Supprimer l'image
+Page.ImageBrowser.Image.Button.Delete=Supprimer l'image
-Page.CreateAlbum.Title=Créer un Album - Sone
-Page.CreateAlbum.Page.Title=Créer un Album
+Page.CreateAlbum.Title=Créer un album - Sone
+Page.CreateAlbum.Page.Title=Créer un album
Page.CreateAlbum.Error.NameMissing=Vous avez oublié de donner un nom à votre Album.
Page.UploadImage.Title=Insérer une Image - Sone
-Page.UploadImage.Error.InvalidImage=L'Image qu vous éssayez d'insérer n'est pas reconnue. Merci de n'insérer que des JPEG (*.jpg or *.jpeg), ou des PNG (*.png).
+Page.UploadImage.Error.InvalidImage=L'image qu vous essayez d'insérer n'est pas reconnue. Merci de n'insérer que des JPEG (*.jpg or *.jpeg), ou des PNG (*.png).
-Page.EditImage.Title=Editer l'Image - Sone
+Page.EditImage.Title=Editer l'image - Sone
-Page.DeleteImage.Title=Supprimer l'Image - Sone
-Page.DeleteImage.Page.Title=Supprimer l'Image
-Page.DeleteImage.Text.ImageWillBeGone=Ceci supprimera l'image “{image}” de l'Album “{album}”. Si elle a déjà été insérée sur Freenet elle ne pourra pas être supprimée. Voulez-vous supprimer cette Image ?
+Page.DeleteImage.Title=Supprimer l'image - Sone
+Page.DeleteImage.Page.Title=Supprimer l'image
+Page.DeleteImage.Text.ImageWillBeGone=Ceci supprimera l'image “{image}” de l'Album “{album}”. Si elle a déjà été insérée sur Freenet elle ne pourra pas être supprimée. Voulez-vous supprimer cette image ?
Page.DeleteImage.Button.Yes=Oui, supprimer cette image.
Page.DeleteImage.Button.No=Non, ne pas supprimer cette image.
-Page.EditAlbum.Title=Editer l'Album - Sone
+Page.EditAlbum.Title=Editer l'album - Sone
-Page.DeleteAlbum.Title=Supprimer l'Album - Sone
-Page.DeleteAlbum.Page.Title=Supprimer l'Album
+Page.DeleteAlbum.Title=Supprimer l'album - Sone
+Page.DeleteAlbum.Page.Title=Supprimer l'album
Page.DeleteAlbum.Text.AlbumWillBeGone=Vous allez supprimer l'Album “{title}”. Etes vous certain de vouloir faire cela ?
Page.DeleteAlbum.Button.Yes=Oui, supprimer cet album.
Page.DeleteAlbum.Button.No=Non, ne pas supprimer cet album.
Page.Search.Text.PostHits=Les messages suivants correspondent aux termes de votre recherche.
Page.Search.Text.NoHits=Aucun Sone ou message ne correspond aux termes de votre recherche.
-Page.Rescue.Title=Secours Sone - Sone
-Page.Rescue.Page.Title=Secours Sone “{0}”
-Page.Rescue.Text.Description=Le Mode Secours vous permet de restaurer une version précédente de Sone. Cela peut être nécessaire si votre configuration est perdue
-Page.Rescue.Text.Procedure=Le Mode secours fonctionne en récupérant vos dernières insertions. Si une insertion est récupérée elle sera chargé dans votre Sone, vous permettant de reprendre le controle de vos messages, profile, et autres configurations (vous pouvez faire cela dans une seconde fenetre ou tabulation Sone). Si vos messages ne peuvent être récupérés, demandez au Mode Secours de récupérer les anciennes versions ci-dessous.
-Page.Rescue.Text.Fetching=Le Secouriste de Sone est en train de récupérer la version {0} de votre Sone.
-Page.Rescue.Text.Fetched=Le Secouriste de Sone a récupéré la version {0} de votre Sone. Merci de vérifire vos messages, réponses et profile. Si les informations vous conviennent, débloquez la version.
-Page.Rescue.Text.FetchedLast=Le secouriste de Sone a récupéré la dernière version disponible. Si vous ne souhaitiez pas récupérer une ancienne version de Sone. Consiédérez que vous n'avez pas de chance.
-Page.Rescue.Text.NotFetched=Le Secouriste de Sone ne peut pas récupérer la version {0} de votre Sone. Merci de réessayer, ou essayez avec une version plus ancienne.
+Page.Rescue.Title=Récupération de Sone - Sone
+Page.Rescue.Page.Title=Récupération du Sone “{0}”
+Page.Rescue.Text.Description=Le Mode Récupération vous permet de restaurer une version précédente de Sone. Cela peut être nécessaire si votre configuration est perdue
+Page.Rescue.Text.Procedure=Le Mode Récupération fonctionne en récupérant vos dernières insertions. Si une insertion est récupérée elle sera chargé dans votre Sone, vous permettant de reprendre le controle de vos messages, profile, et autres configurations (vous pouvez faire cela dans une seconde fenêtre ou tabulation Sone). Si vos messages ne peuvent être récupérés, demandez au Mode Récupération de restaurer les anciennes versions ci-dessous.
+Page.Rescue.Text.Fetching=Le récupérateur de Sone est en train de restaurer la version {0} de votre Sone.
+Page.Rescue.Text.Fetched=Le récupérateur de Sone a restauré la version {0} de votre Sone. Merci de vérifier vos messages, réponses et profile. Si les informations vous conviennent, débloquez la version.
+Page.Rescue.Text.FetchedLast=Le récupérateur de Sone a restauré la dernière version disponible. Si vous ne souhaitiez pas récupérer une ancienne version de Sone. Considérez que vous n'avez pas de chance.
+Page.Rescue.Text.NotFetched=Le récupérateur de Sone ne peut pas restaurer la version {0} de votre Sone. Merci de réessayer, ou essayez avec une version plus ancienne.
Page.Rescue.Label.NextEdition=Prochaine version:
Page.Rescue.Button.Fetch=Récupérer la version.
Page.DismissNotification.Title=Effacer la notification - Sone
Page.WotPluginMissing.Text.LoadPlugin=Veuillez charger le plugin Web of Trust dans le {link}plugin manager{/link}.
-Page.WotPluginMissing.Text.WotRequired=Parce que le Web of Trust est une partie intégrante de Sone, le plugin Web of trust doit être chargé afin de pouvoir faire fontionner Sone.
+Page.WotPluginMissing.Text.WotRequired=Parce que Web of Trust est une partie intégrante de Sone, le plugin Web of trust doit être chargé afin de pouvoir faire fontionner Sone.
Page.Logout.Title=Déconnexion - Sone
View.Sone.Status.Downloading=Ce Sone est en train d'être téléchargé.
View.Sone.Status.Inserting=Ce Sone est en train d'être inséré.
-View.SoneMenu.Link.AllAlbums=tous les Albums
+View.SoneMenu.Link.AllAlbums=Tous les Albums
View.Post.UnknownAuthor=(inconnu)
-View.Post.WebOfTrustLink=profile web of trust
-View.Post.Permalink=lier le message
+View.Post.WebOfTrustLink=Profile web of trust
+View.Post.Permalink=Lier le message
View.Post.PermalinkAuthor=Lier l'auteur
View.Post.Bookmarks.PostIsBookmarked=Ce message a été ajouté aux marque-pages, cliquer pour retirer des marque-pages
View.Post.Bookmarks.PostIsNotBookmarked=Ce message n'est pas dans les marque-pages, cliquer pour marquer cette page
View.Post.UnlikeLink=N'aime pas
View.Post.ShowSource=Activer/Désactiver le parser
View.Post.NotDownloaded=Ce message n'a pas encore été téléchargé, ou a été effacé.
-View.Post.ShowMore=voir plus
-View.Post.ShowLess=vois moins
+View.Post.ShowMore=Voir plus
+View.Post.ShowLess=Vois moins
View.UpdateStatus.Text.ChooseSenderIdentity=Choisir l'identité de l'expéditeur
WebInterface.DefaultText.BirthDay=Jour
WebInterface.DefaultText.BirthMonth=Mois
WebInterface.DefaultText.BirthYear=Année
-WebInterface.DefaultText.FieldName=nom du champ
-WebInterface.DefaultText.Option.InsertionDelay=Temps d'attente après qu'un Sone aie été modifié avant l'insertion (en secondes)
+WebInterface.DefaultText.FieldName=Nom du champ
+WebInterface.DefaultText.Option.InsertionDelay=Temps d'attente après qu'un Sone ai été modifié avant l'insertion (en secondes)
WebInterface.DefaultText.Search=Que recherchez vous ?
-WebInterface.DefaultText.CreateAlbum.Name=Album title
-WebInterface.DefaultText.CreateAlbum.Description=Album description
-WebInterface.DefaultText.EditAlbum.Title=Album title
-WebInterface.DefaultText.EditAlbum.Description=Album description
-WebInterface.DefaultText.UploadImage.Title=Image title
-WebInterface.DefaultText.UploadImage.Description=Image description
-WebInterface.DefaultText.EditImage.Title=Image title
-WebInterface.DefaultText.EditImage.Description=Image description
+WebInterface.DefaultText.CreateAlbum.Name=Titre de l'album
+WebInterface.DefaultText.CreateAlbum.Description=Description de l'album
+WebInterface.DefaultText.EditAlbum.Title=Title de l'album
+WebInterface.DefaultText.EditAlbum.Description=Description de l'album
+WebInterface.DefaultText.UploadImage.Title=Titre de l'image
+WebInterface.DefaultText.UploadImage.Description=Description de l'image
+WebInterface.DefaultText.EditImage.Title=Titre de l'image
+WebInterface.DefaultText.EditImage.Description=Description de l'image
WebInterface.DefaultText.Option.PostsPerPage=Nombre de messages à afficher par page
-WebInterface.DefaultText.Option.CharactersPerPost=Number of characters a post must have to be shortened
-WebInterface.DefaultText.Option.PostCutOffLength=Number of characters for the snippet of the shortened post
+WebInterface.DefaultText.Option.ImagesPerPage=Nombre d'images à afficher par pages
+WebInterface.DefaultText.Option.CharactersPerPost=Nombre de charactère qu'une publication doit avoir pour être racourcie
+WebInterface.DefaultText.Option.PostCutOffLength=Nombre de charactère du descriptif de la publication racourcie
WebInterface.DefaultText.Option.PositiveTrust=La note de confiance positive à assigner
WebInterface.DefaultText.Option.NegativeTrust=Une note de confiance négative à assigner
WebInterface.DefaultText.Option.TrustComment=Le commentaire à mettre dans le "Web of Trust"
WebInterface.ClickToShow.Replies=Cliquer ici pour afficher les réponses cachées.
WebInterface.VersionInformation.CurrentVersion=Version actuelle:
WebInterface.VersionInformation.LatestVersion=Dernière version:
+WebInterface.VersionInformation.Homepage=Accueil
Notification.ClickHereToRead=Cliquer ici pour lire le texte entier de la notification.
Notification.FirstStart.Text=Il semble que ce soit la première fois que vous démarrez Sone. Pour démarrer, créez un nouveau Sone depuis une identité Web of Trust et commencez à suivre d'autres Sones.
Notification.Startup.Text=Sone est cours de démarrage. Cela peut prendre un certain temps afin de récupérer toutes les identités et Sones du Web of Trust. Si il vous manque certains éléments, veuillez être patient, ils réapparaîtrons probablement assez tôt.
-Notification.ConfigNotRead.Text=Le fichier de configuration “sone.properties” n'a pas pu être lu probablement car il n'a pas été sauvegardé correctement. Ceci peut arriver avec les versions antérieures à Sone 0.3.3 et il n'y a rien que vous puissiez faire à ce propos.
+Notification.ConfigNotRead.Text=Le fichier de configuration “sone.properties” n'a pas pu être lu probablement parce qu'il n'a pas été sauvegardé correctement. Ceci peut arriver avec les versions antérieures à Sone 0.3.3 et il n'y a rien que vous puissiez faire à ce propos.
Notification.Button.Dismiss=Rejeter
Notification.NewSone.ShortText=De nouveaux Sones ont été découverts:
Notification.NewSone.Text=De nouveaux Sones ont été découverts:
Notification.SoneRescued.Text=Les Sones suivants ont été sauvés:
Notification.SoneRescued.Text.RememberToUnlock=Veuillez vous souvenir de contrôler les messages et réponses que vous avez donnés et n'oubliez ps de déverrouiller vos Sones!
Notification.LockedSones.Text=Les Sones suivants ont été verrouillés pour plus de 5 minutes. Veuillez vérifier si vous voulez vraiment garder ces Sones bloqués:
-Notification.NewVersion.Text=La version {version} du pluggin Sone a été trouvée. Téléchargez la depuis USK@nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI,DuQSUZiI~agF8c-6tjsFFGuZ8eICrzWCILB60nT8KKo,AQACAAE/sone/{edition}!
+Notification.NewVersion.Text=La version {version} du plugin Sone a été trouvée. Téléchargez la depuis USK@nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI,DuQSUZiI~agF8c-6tjsFFGuZ8eICrzWCILB60nT8KKo,AQACAAE/sone/{edition}!
Notification.InsertingImages.Text=Les images suivantes sont en cours d'insertion:
Notification.InsertedImages.Text=Les images suivantes ont été insérées:
Notification.ImageInsertFailed.Text=Les images suivantes ne peuvent être insérées:
Page.Options.Section.RuntimeOptions.Title=Oppførsel ved kjøretid
Page.Options.Option.InsertionDelay.Description=Antall sekunder Sone-innsetteren skal vente etter en endring av en Sone før den blir innsatt.
Page.Options.Option.PostsPerPage.Description=Antallet innlegg å vise pr side før side-kontroller blir vist.
+Page.Options.Option.ImagesPerPage.Description=Antall bilder å vise på en side før side-kontroller blir vist.
Page.Options.Option.CharactersPerPost.Description=Antall tegn å vise fra et innlegg før resten blir skjult og en link blir vist for å utvide til hele innlegget (-1 for å deaktivere). Lengden på den viste teksten kan endres under.
Page.Options.Option.PostCutOffLength.Description=Antallet tegn som blir vist hvis et innlegg er for langt (Se innstilling over).
Page.Options.Option.RequireFullAccess.Description=For å avslå tilgang til Sone fra enhver host som ikke har blitt gitt full tilgang.
Page.Index.Button.Post=Publiser!
Page.Index.PostList.Title=Innleggsstrøm
Page.Index.PostList.Text.NoPostYet=Ingen har skrevet noen innlegg enda. Du burde starte med en gang!
+Page.Index.PostList.Text.FollowSomeSones=Eller kanskje du ikke følger noen Soner? Naviger til {link}Kjente Soner{/link} og følg de som ser interessante ut!
Page.New.Title=Nye innlegg og svar - Sone
Page.New.Page.Title=Nye innlegg og svar
WebInterface.DefaultText.EditImage.Description=Bildebeskrivelse
WebInterface.DefaultText.EditImage.Title=Bildetittel
WebInterface.DefaultText.Option.PostsPerPage=Antall innlegg å vise på en side
+WebInterface.DefaultText.Option.ImagesPerPage=Antall bilder å vise per side
WebInterface.DefaultText.Option.CharactersPerPost=Antall tegn et innlegg må ha for å bli skjult.
WebInterface.DefaultText.Option.PostCutOffLength=Antall tegn som vises når et innlegg blir skjult
WebInterface.DefaultText.Option.PositiveTrust=Positiv tillit å gi
WebInterface.ClickToShow.Replies=Klikk her for å vise skjulte svar.
WebInterface.VersionInformation.CurrentVersion=Gjeldende utgave:
WebInterface.VersionInformation.LatestVersion=Siste utgave:
+WebInterface.VersionInformation.Homepage=Hjemmeside
Notification.ClickHereToRead=Klikk her for å lese hele varslingen.
Notification.FirstStart.Text=Dette ser ut til å være første gang du starter Sone. For å starte, lag en ny Sone fra et 'Web Of Trust'-pseudonym og start å følge andre Soner.
Page.Options.Page.Description=Te opcje wpływaja na pracę wtyczki Sone.
Page.Options.Section.SoneSpecificOptions.Title=Sone-Konkretne Opcje
Page.Options.Section.SoneSpecificOptions.NotLoggedIn=Opcje dostępne po zalogowaniu {link}zalogowany{/link}.
-Page.Options.Section.SoneSpecificOptions.LoggedIn=Opcje dostępne po zalogowaniu dla aktualnie używanego profilu Sone.
+Page.Options.Section.SoneSpecificOptions.LoggedIn=Opcje dostępne po zalogowaniu dla aktualnie używanego profilu Sone.
Page.Options.Option.AutoFollow.Description=Śledź automatycznie nowych uzytkowników Sone. Śledzeni będą tylko użytkownicy Sone odnalezieni po uruchomieniu tej opcji!
Page.Options.Option.EnableSoneInsertNotifications.Description=Włączenie tej opcji uruchamia powiadomienia o tym, że twój Sone jest wysyłany lub zakończył wysyłanie na serwer.
Page.Options.Option.ShowNotificationNewSones.Description=Pokaż powiadomienie o nowych użytkownikach Sone.
Page.Options.Option.ShowAvatars.Never.Description=Nigdy nie pokazuj niestandardowych avatarów.
Page.Options.Option.ShowAvatars.Followed.Description=Pokazuj avatary tylko śledzonych użytkowników Sone.
Page.Options.Option.ShowAvatars.ManuallyTrusted.Description=Pokazuj avatary tylko tych użytkowników Sone, którym ręcznie przyznałeś ilość punktów zaufania przekraczającą 0.
-Page.Options.Option.ShowAvatars.Trusted.Description=Pokazuj avatary tylko tych użytkowników Sone, którzy mają ilość punktów zaufania większą niż 0.
-Page.Options.Option.ShowAvatars.Always.Description=Zawsze pokazuj niestandardowe avatary. Uwaga: niektóre avatary mogą zawierać obraźliwe treści.
+Page.Options.Option.ShowAvatars.Trusted.Description=Pokazuj avatary tylko tych użytkowników Sone, którzy mają ilość punktów zaufania większą niż 0.
+Page.Options.Option.ShowAvatars.Always.Description=Zawsze pokazuj niestandardowe avatary. Uwaga: niektóre avatary mogą zawierać obraźliwe treści.
Page.Options.Section.RuntimeOptions.Title=Tryb pracy
-Page.Options.Option.InsertionDelay.Description=Czas oczekiwania użytkownika Sone na modifikację profilu Sone przed jego załadowaniem.
+Page.Options.Option.InsertionDelay.Description=Czas oczekiwania użytkownika Sone na modifikację profilu Sone przed jego załadowaniem.
Page.Options.Option.PostsPerPage.Description=Ilość postów wyświetlanych na stronie przed pojawieniem się znaków paginacji.
-Page.Options.Option.CharactersPerPost.Description=Ilość znaków pokazywanych w poście zanim zostanie on obcięty i pojawi się link do jego rozszerzenia (-1 powoduje wyłączenie). Długość fragmentu zależy od poniższej opcji.
+Page.Options.Option.ImagesPerPage.Description=Ilość obrazków wyświetlanych na stronie przed pojawieniem się znaków paginacji.
+Page.Options.Option.CharactersPerPost.Description=Ilość znaków pokazywanych w poście zanim zostanie on obcięty i pojawi się link do jego rozszerzenia (-1 powoduje wyłączenie). Długość fragmentu zależy od poniższej opcji.
Page.Options.Option.PostCutOffLength.Description=Ilość znaków wyświetlanych w przypadku za długiego postu (zobacz opcję powyżej).
-Page.Options.Option.RequireFullAccess.Description=Opcja odmowy dostępu do Sone hostom bez przyznanego pełnego dostępu.
+Page.Options.Option.RequireFullAccess.Description=Opcja odmowy dostępu do Sone hostom bez przyznanego pełnego dostępu.
Page.Options.Section.TrustOptions.Title=Ustawienia Zaufania
-Page.Options.Option.PositiveTrust.Description=Punkty pozytywnego zaufania, które chcesz przyznać innym użytkownikom Sone klikając na ikonę pod postem lub odpowiedzią.
-Page.Options.Option.NegativeTrust.Description=Punkty zaufania, które chcesz przyznać innym użytkownikom Sone klikając na czerwony krzyżyk pod postem lub odpowiedzią. Wartosć powinna być negatywna.
-Page.Options.Option.TrustComment.Description=Komentarz, który wyświetli się w sieci zaufania w momencie przyznawania punktów zaufania w obrębie Sone.
-Page.Options.Section.FcpOptions.Title=Ustawienia Interfejsu FCP
-Page.Options.Option.FcpInterfaceActive.Description=Uruchom interfejs FCP, aby umożliwić innym wtyczkom i klientom zdalnym dostęp do twojej wtyczki Sone.
+Page.Options.Option.PositiveTrust.Description=Punkty pozytywnego zaufania, które chcesz przyznać innym użytkownikom Sone klikając na ikonę pod postem lub odpowiedzią.
+Page.Options.Option.NegativeTrust.Description=Punkty zaufania, które chcesz przyznać innym użytkownikom Sone klikając na czerwony krzyżyk pod postem lub odpowiedzią. Wartosć powinna być negatywna.
+Page.Options.Option.TrustComment.Description=Komentarz, który wyświetli się w sieci zaufania w momencie przyznawania punktów zaufania w obrębie Sone.
+Page.Options.Section.FcpOptions.Title=Ustawienia Interfejsu FCP
+Page.Options.Option.FcpInterfaceActive.Description=Uruchom interfejs FCP, aby umożliwić innym wtyczkom i klientom zdalnym dostęp do twojej wtyczki Sone.
Page.Options.Option.FcpFullAccessRequired.Description=Wymagane połączenie FCP dla hostów z dostępem (patrz twoja {link}konfiguracja Freenet, sekcja “FCP”{/link})
Page.Options.Option.FcpFullAccessRequired.Value.No=Nie
Page.Options.Option.FcpFullAccessRequired.Value.Writing=Dostęp z zapisem
Page.Options.Section.Cleaning.Title=Wyczyść
Page.Options.Option.ClearOnNextRestart.Description=Przy kolejnym uruchomieniu zresetuj ustawienia wtyczki Sone. Uwaga!{strong}Wszystkie twoje profile Sone zostaną zniszczone{/strong}upewnij się, że wykonano kopie zapasowe wszystkich niezbędnych danych! Wymagane wybranie odpowiedzi "tak" w następnej opcji.
Page.Options.Option.ReallyClearOnNextRestart.Description=Wymagane wybranie opcji"tak"jeśli {strong}naprawdę{/strong} jesteś zdecydowany zresetować ustawienia wtyczki konfiguracyjnej przy kolejnym uruchomieniu.
-Page.Options.Warnings.ValueNotChanged=Opcja nie została zmieniona, ponieważ wprowadzono błędną wartość.
+Page.Options.Warnings.ValueNotChanged=Opcja nie została zmieniona, ponieważ wprowadzono błędną wartość.
Page.Options.Button.Save=Zapisz
Page.Login.Title=Login - Sone
Page.Index.Label.Sender=Autor:
Page.Index.Button.Post=Napisz!
Page.Index.PostList.Title=Wątek
-Page.Index.PostList.Text.NoPostYet=Nie ma jeszcze żądnych postów. Można rozpocząć pisanie wątku!
+Page.Index.PostList.Text.NoPostYet=Nie ma jeszcze żądnych postów. Można rozpocząć pisanie wątku!
+Page.Index.PostList.Text.FollowSomeSones=Być może nie śledzisz żadnych Sone? Spójrz na tę listę {link}znane Sone{/link} i zacznij kogoś śledzić.
Page.New.Title=Nowe Posty i Odpowiedzi - Sone
Page.New.Page.Title=Nowe Posty i Odpowiedzi
Page.KnownSones.Filter.NotNew=Ukryj nowe Sone
Page.KnownSones.Button.Apply=Zastosuj
Page.KnownSones.Button.FollowAllSones=Śledź wszystkie Sone na tej stronie
-Page.KnownSones.Button.UnfollowAllSones=Przestań śledzić wszystkie Sone na tej stronie
+Page.KnownSones.Button.UnfollowAllSones=Przestań śledzić wszystkie Sone na tej stronie
Page.EditProfile.Title=Edytuj Profil - Sone
-Page.EditProfile.Page.Title=Edytuj Profil
+Page.EditProfile.Page.Title=Edytuj Profil
Page.EditProfile.Page.Description=Na tej stronie uzyskasz dostęp do swoich danych profilowych.
Page.EditProfile.Page.Hint.Optionality=Pamiętaj, każde pole w profilu jest opcjonalne! Nie musisz nic wpisywać! Wszystko co wpiszesz będzie bardzo długo przechowywane na Freenet!
Page.EditProfile.Label.FirstName=Imię:
Page.EditProfile.Avatar.Description=Możesz ustawić jako avatar jedno z załadowanych zdjęć. Nie może być większe niż 64×64 pikseli, poniważ jest to największy rozmiar zdjęć wyświetlanych u innych osób (80×80 pikseli jest stosowany jako nagłówek strony).
Page.EditProfile.Avatar.Delete=Brak avataru
Page.EditProfile.Fields.Title=Pola niestandardowe
-Page.EditProfile.Fields.Description=Tutaj możesz wprowadzać pola nistandardowe do profilu. Pola mogą zawierać dowolne treści oraz dowolą ilość tekstu. Należy pamiętać, że ze względu na anonimowość często mniej znaczy więcej.
+Page.EditProfile.Fields.Description=Tutaj możesz wprowadzać pola nistandardowe do profilu. Pola mogą zawierać dowolne treści oraz dowolą ilość tekstu. Należy pamiętać, że ze względu na anonimowość często mniej znaczy więcej.
Page.EditProfile.Fields.Button.Edit=Edytuj
Page.EditProfile.Fields.Button.MoveUp=Idź do góry
Page.EditProfile.Fields.Button.MoveDown=Idź na dół
Page.EditProfileField.Title=Edytuj profil - Sone
Page.EditProfileField.Page.Title=Edytuj profil
-Page.EditProfileField.Text=Wprowadź nową nazwę dla tego profilu
+Page.EditProfileField.Text=Wprowadź nową nazwę dla tego profilu
Page.EditProfileField.Error.DuplicateFieldName=Wprowadzona nazwa pola już istnieje.
Page.EditProfileField.Button.Save=Zmień
Page.EditProfileField.Button.Reset=Wróć do poprzedniej nazwy
Page.DeleteProfileField.Title=Usuń profil - Sone
Page.DeleteProfileField.Page.Title=Usuń profil
-Page.DeleteProfileField.Text=Czy naprawdę chcesz usunąć ten profil?
-Page.DeleteProfileField.Button.Yes=Tak, usuń.
+Page.DeleteProfileField.Text=Czy naprawdę chcesz usunąć ten profil?
+Page.DeleteProfileField.Button.Yes=Tak, usuń.
Page.DeleteProfileField.Button.No=Nie, nie usuwaj.
Page.CreatePost.Title=Napisz post - Sone
Page.ViewSone.Title=Zobacz Sone - Sone
Page.ViewSone.Page.TitleWithoutSone=Zobacz nieznany Sone
-Page.ViewSone.NoSone.Description= Nie ma obecnie Sone z tym ID {sone}. Jesli szukasz konkretnego użytkownika to upewnij się, że jest widoczny w twojej sieci zaufania.
-Page.ViewSone.UnknownSone.Description=Ten Sone nie został jeszcze odzyskany. Proszę sprawdzić za chwilę.
-Page.ViewSone.UnknownSone.LinkToWebOfTrust=Ten Sone nie jest jeszcze znany, ale jego profil w Sieci Zaufania może być już dostępny.
+Page.ViewSone.NoSone.Description= Nie ma obecnie Sone z tym ID {sone}. Jesli szukasz konkretnego użytkownika to upewnij się, że jest widoczny w twojej sieci zaufania.
+Page.ViewSone.UnknownSone.Description=Ten Sone nie został jeszcze odzyskany. Proszę sprawdzić za chwilę.
+Page.ViewSone.UnknownSone.LinkToWebOfTrust=Ten Sone nie jest jeszcze znany, ale jego profil w Sieci Zaufania może być już dostępny.
Page.ViewSone.WriteAMessage=Tu możesz napisać wiadomość do tego Sone. Każdy będzie mógł zobaczyć tą wiadomość!
Page.ViewSone.PostList.Title=Posty {sone}
Page.ViewSone.PostList.Text.NoPostYet=Ten Sone nie ma jeszcze żadnych postów.
Page.ViewSone.Profile.Label.Name=Nazwa
Page.ViewSone.Profile.Label.Albums=Album
Page.ViewSone.Profile.Albums.Text.All=Wszystkie albumy
-Page.ViewSone.Profile.Name.WoTLink=Profil
+Page.ViewSone.Profile.Name.WoTLink=Profil
Page.ViewSone.Replies.Title=Posty, na które odpowiedział {sone}
Page.ViewPost.Title=Zobacz Post - Sone
Page.DeletePost.Title=Usuń Sone - Sone
Page.DeletePost.Page.Title=Usuń Sone
-Page.DeletePost.Text.PostWillBeGone=Usunięty post nie będzie widoczny na twoim Sone. Nie zostanie jednak usunięty z Freenetu, ponieważ nie ma takiej możliwości. Starsze wersje twojego Sone będą zawsze zawierały usunięte posty.
+Page.DeletePost.Text.PostWillBeGone=Usunięty post nie będzie widoczny na twoim Sone. Nie zostanie jednak usunięty z Freenetu, ponieważ nie ma takiej możliwości. Starsze wersje twojego Sone będą zawsze zawierały usunięte posty.
Page.DeletePost.Button.Yes=Tak, usuń.
Page.DeletePost.Button.No=Nie, nie usuwaj.
Page.DeleteReply.Title=Usuń odpowiedź - Sone
Page.DeleteReply.Page.Title=Usuń odpowiedź
-Page.DeleteReply.Text.PostWillBeGone= Usunięta odpowiedź nie będzie widoczna na twoim Sone. Nie zostanie jednak usunięta z Freenet, ponieważ nie ma takiej możlowość. Starsze wersje twojego Sone zawsze będa zawierały usunięte odpowiedzi.
+Page.DeleteReply.Text.PostWillBeGone= Usunięta odpowiedź nie będzie widoczna na twoim Sone. Nie zostanie jednak usunięta z Freenet, ponieważ nie ma takiej możlowość. Starsze wersje twojego Sone zawsze będa zawierały usunięte odpowiedzi.
Page.DeleteReply.Button.Yes=Tak, usuń.
Page.DeleteReply.Button.No=Nie, nie usuwaj.
Page.ImageBrowser.Title=Wyszukiwarka Obrazów - Sone
Page.ImageBrowser.Album.Title=Album “{album}”
-Page.ImageBrowser.Album.Error.NotFound.Text=Nie można znaleźć żądanego albumu. Prawdopodobnie nie został jeszcze ściagnięty, albo został usunięty.
+Page.ImageBrowser.Album.Error.NotFound.Text=Nie można znaleźć żądanego albumu. Prawdopodobnie nie został jeszcze ściagnięty, albo został usunięty.
Page.ImageBrowser.Sone.Title=Albumy {sone}
-Page.ImageBrowser.Sone.Error.NotFound.Text=Nie można znaleźć żądanego Sone. Prawdopodobnie nie został jeszcze ściągnięty.
+Page.ImageBrowser.Sone.Error.NotFound.Text=Nie można znaleźć żądanego Sone. Prawdopodobnie nie został jeszcze ściągnięty.
Page.ImageBrowser.Header.Albums=Albumy
Page.ImageBrowser.Header.Images=Obrazy
Page.ImageBrowser.Link.All=Wszystkie Sone
Page.ImageBrowser.Image.Button.MoveLeft=◀
Page.ImageBrowser.Image.Button.Save=Zapisz Obraz
Page.ImageBrowser.Image.Button.MoveRight=►
-Page.ImageBrowser.Image.Delete.Title=Usuń Obraz
+Page.ImageBrowser.Image.Delete.Title=Usuń Obraz
Page.ImageBrowser.Image.Button.Delete=Usuń Obraz
Page.CreateAlbum.Title=Utwórz Album - Sone
Page.DeleteImage.Page.Title=Usuń Obraz
Page.DeleteImage.Text.ImageWillBeGone=Obraz “{image}” zostanie usunięty z twojego albumu “{album}”. Jeśli został już umieszczony na Freenet to nie bedzie można go usunąć. Czy chcesz usunąć obraz?
Page.DeleteImage.Button.Yes=Tak, usuń obraz.
-Page.DeleteImage.Button.No=Nie, nie usuwaj obrazu.
+Page.DeleteImage.Button.No=Nie, nie usuwaj obrazu.
Page.EditAlbum.Title=Edytuj Album
Page.Unbookmark.Title=Usuń zakładkę - Sone
Page.Bookmarks.Title=Zakładka - Sone
Page.Bookmarks.Page.Title=Zakładki
-Page.Bookmarks.Text.NoBookmarks= Nie masz obecnie żadnych zakładek. Możesz dodać posty do zakładek klikając gwiazdkę poniżej postu.
+Page.Bookmarks.Text.NoBookmarks= Nie masz obecnie żadnych zakładek. Możesz dodać posty do zakładek klikając gwiazdkę poniżej postu.
Page.Bookmarks.Text.PostsNotLoaded=Niektóre z zaznaczonych przez ciebie postów nie zostały wyświetlone, ponieważ wystąpił problem z ich załadowaniem. Dzieje się tak, jeśli Sone było niedawno restartowane, lub gdy posty zostały usunięte. Jeśli jesteś pewien, że posty zostały usunięte, to możesz je {link}odznaczyć{/link}.
Page.Search.Title=Szukaj - Sone
-Page.Search.Page.Title=Szukaj
-Page.Search.Text.SoneHits=Następujące Sone pasuja do twoich wyników wyszukiwania.
-Page.Search.Text.PostHits=Następujące posty pasują do twoich wyników wyszukiwania.
-Page.Search.Text.NoHits=Nie znaleziono żadnych Sone ani postów pasujących do twoich wyników wyszukiwania.
+Page.Search.Page.Title=Szukaj
+Page.Search.Text.SoneHits=Następujące Sone pasuja do twoich wyników wyszukiwania.
+Page.Search.Text.PostHits=Następujące posty pasują do twoich wyników wyszukiwania.
+Page.Search.Text.NoHits=Nie znaleziono żadnych Sone ani postów pasujących do twoich wyników wyszukiwania.
Page.Rescue.Title=Ratuj Sone
Page.Rescue.Page.Title=Ratuj Sone “{0}”
-Page.Rescue.Text.Description=Tryb Ratunkowy pozwala przywrócić poprzednią wersję twojego Sone. Może to okazać się niezbędne, jeśli twoje ustawienia zostaną utracone.
+Page.Rescue.Text.Description=Tryb Ratunkowy pozwala przywrócić poprzednią wersję twojego Sone. Może to okazać się niezbędne, jeśli twoje ustawienia zostaną utracone.
Page.Rescue.Text.Procedure=Tryb Rarunkowy polega na pobraniu ostatniej wprowadzonej edycji twojego Sone. Jeśli edycja zostanie poprawnie pobrana wówczas zostanie załadowana na twój Sone, co umożliwi zarządzanie twoimi postami, profilem oraz innymi ustawieniami (można to zrobić w nowej zakładce lub oknie przegladarki). Jeśli pobrana edycja różni się od tej, którą chcesz przywrócić, wówczas ustaw Tryb Ratunkowy tak, aby poprał jeszcze wcześniejszą edycję.
-Page.Rescue.Text.Fetching=Tryb Ratunkowy Sone pobiera właśnie edycję {0} twojego Sone.
-Page.Rescue.Text.Fetched=Tryb Ratunkowy Sone pobrał edycję {0} twojego Sone. Sprawdź swoje posty, odpowiedzi oraz profil. Jeśli podoba ci się zawartość aktualnego Sone, to mozesz go odblokować.
+Page.Rescue.Text.Fetching=Tryb Ratunkowy Sone pobiera właśnie edycję {0} twojego Sone.
+Page.Rescue.Text.Fetched=Tryb Ratunkowy Sone pobrał edycję {0} twojego Sone. Sprawdź swoje posty, odpowiedzi oraz profil. Jeśli podoba ci się zawartość aktualnego Sone, to mozesz go odblokować.
Page.Rescue.Text.FetchedLast= Tryb Ratunkowy Sone pobrał ostatnią dostępną edycję. Jeśli nie udało się przywrócić twojego Sone, to nie masz teraz szczęścia.
Page.Rescue.Text.NotFetched=Tryb Ratunkowy Sone nie mógł sćiągnąć edycji {0} twojego Sone. Spróbuj pobrać ponownie edycję {0}, albo pobierz kolejną starszą edycję.
Page.Rescue.Label.NextEdition=Następna edycja:
Page.NoPermission.Title=Nieupoważniony dostęp- Sone
Page.NoPermission.Page.Title=Nieupoważniony dostęp
-Page.NoPermission.Text.NoPermission=Próbowałeś zrobić coś do czego nie masz wystarczającej autoryzacji. Na przyszłość nie podejmuj tego typu działań, albo będziemy zmuszeni podjać odpowiednie kroki.
+Page.NoPermission.Text.NoPermission=Próbowałeś zrobić coś do czego nie masz wystarczającej autoryzacji. Na przyszłość nie podejmuj tego typu działań, albo będziemy zmuszeni podjać odpowiednie kroki.
Page.DismissNotification.Title=Odrzuć powiadomienie - Sone
-Page.WotPluginMissing.Text.WotRequired=Sieć Zaufania jest integralną częścią Sone. Należy załądować wtyczkę Sieci Zaufania, aby móc korzystać z Sone.
+Page.WotPluginMissing.Text.WotRequired=Sieć Zaufania jest integralną częścią Sone. Należy załądować wtyczkę Sieci Zaufania, aby móc korzystać z Sone.
Page.WotPluginMissing.Text.LoadPlugin=Załaduj wtyczkę Sieci Zaufania w {link}menadżerze wtyczek{/link}.
Page.Logout.Title=Wyloguj - Sone
Page.Invalid.Title=Niepoprawne działanie
Page.Invalid.Page.Title=Niepoprawne działanie
-Page.Invalid.Text=Podjęto niepoprawne działanie, lub też działanie było poprawne, ale parametry nie. Wróć do{link}strony głównej{/link} i spróbuj ponownie. Jeśli problem będzie się utrzymywać to najprawdopodobniej znalazłeś błąd.
+Page.Invalid.Text=Podjęto niepoprawne działanie, lub też działanie było poprawne, ale parametry nie. Wróć do{link}strony głównej{/link} i spróbuj ponownie. Jeśli problem będzie się utrzymywać to najprawdopodobniej znalazłeś błąd.
View.Search.Button.Search=Szukaj
View.Sone.Button.UnlockSone=odblokuj
View.Sone.Button.UnlockSone.Tooltip=Pozwala na załadowanie Sone
View.Sone.Button.LockSone=zablokuj
-View.Sone.Button.LockSone.Tooltip=Uniemożliwia załadowanie Sone
+View.Sone.Button.LockSone.Tooltip=Uniemożliwia załadowanie Sone
View.Sone.Button.UnfollowSone=przestań śledzić
View.Sone.Button.FollowSone=śledź
View.Sone.Status.Modified=Ten Sone został zmodyfikowany i czeka na załadowanie
-View.Sone.Status.Unknown=Ten Sone nie został jeszcze odzyskany
+View.Sone.Status.Unknown=Ten Sone nie został jeszcze odzyskany
View.Sone.Status.Idle=Ten Sone nie jest używany, t.j. nie jest ani ładowany ani ściągany.
View.Sone.Status.Downloading=Ten Sone jest właśnie ściągany.
View.Sone.Status.Inserting=Ten Sone jest właśnie ładowany.
View.Post.WebOfTrustLink=Profil sieci zaufania
View.Post.Permalink=linkuj post
View.Post.PermalinkAuthor=linkuj autora
-View.Post.Bookmarks.PostIsBookmarked=Post został oznaczony, kliknij, żeby odznaczyć
-View.Post.Bookmarks.PostIsNotBookmarked=Post nie jest oznaczony, kliknij, żeby dodać do zakładek
+View.Post.Bookmarks.PostIsBookmarked=Post został oznaczony, kliknij, żeby odznaczyć
+View.Post.Bookmarks.PostIsNotBookmarked=Post nie jest oznaczony, kliknij, żeby dodać do zakładek
View.Post.DeleteLink=Usuń
View.Post.SendReply=Wyślij Odpowiedź!
View.Post.Reply.DeleteLink=Usuń
View.Post.LikeLink=Lubię
View.Post.UnlikeLink=Nie lubię
View.Post.ShowSource=Parsowanie
-View.Post.NotDownloaded=Ten post albo nie został jeszcze ściągnięty albo został usunięty.
+View.Post.NotDownloaded=Ten post albo nie został jeszcze ściągnięty albo został usunięty.
View.Post.ShowMore=pokaż więcej
View.Post.ShowLess=pokaż mniej
-View.UpdateStatus.Text.ChooseSenderIdentity=Wybierz tożsamość nadawcy
+View.UpdateStatus.Text.ChooseSenderIdentity=Wybierz tożsamość nadawcy
View.Trust.Tooltip.Trust=Zaufaj tej osobie
View.Trust.Tooltip.Distrust=Przypisz tej osobie nagatywny poziom zaufania
View.UploadImage.Title=Załaduj Obraz
View.UploadImage.Label.Title=Tytuł:
View.UploadImage.Label.Description=Opis:
-View.UploadImage.Button.UploadImage=Załaduj Obraz
+View.UploadImage.Button.UploadImage=Załaduj Obraz
View.Time.InTheFuture=potem
View.Time.AFewSecondsAgo=kilka sekund temu
WebInterface.DefaultText.Message=Napisz Wiadomość…
WebInterface.DefaultText.Reply=Napisz Odpowiedź…
WebInterface.DefaultText.FirstName=Imię
-WebInterface.DefaultText.MiddleName=Drugie imię
+WebInterface.DefaultText.MiddleName=Drugie imię
WebInterface.DefaultText.LastName=Nazwisko
WebInterface.DefaultText.BirthDay=Dzień
WebInterface.DefaultText.BirthMonth=Miesiąc
WebInterface.DefaultText.BirthYear=Rok
WebInterface.DefaultText.FieldName=Nazwa Pola
-WebInterface.DefaultText.Option.InsertionDelay=Czas potrzebny na załadowanie Sone po modyfikacji (w sekundach)
+WebInterface.DefaultText.Option.InsertionDelay=Czas potrzebny na załadowanie Sone po modyfikacji (w sekundach)
WebInterface.DefaultText.Search=Czego szukasz?
WebInterface.DefaultText.CreateAlbum.Name=Tytuł Albumu
WebInterface.DefaultText.CreateAlbum.Description=Opis Albumu
WebInterface.DefaultText.EditImage.Title=Tytuł Obrazka
WebInterface.DefaultText.EditImage.Description=Opis Obrazka
WebInterface.DefaultText.Option.PostsPerPage=Ilość postów wyświetlanych na jednej stronie
-WebInterface.DefaultText.Option.CharactersPerPost=Ilość znaków, które ma zawierać post, aby zostać skrócony
+WebInterface.DefaultText.Option.ImagesPerPage=Ilość obrazków na stronie
+WebInterface.DefaultText.Option.CharactersPerPost=Ilość znaków, które ma zawierać post, aby zostać skrócony
WebInterface.DefaultText.Option.PostCutOffLength=Ilość znaków w skróconym poście
-WebInterface.DefaultText.Option.PositiveTrust=Pozytywny poziom zaufania
+WebInterface.DefaultText.Option.PositiveTrust=Pozytywny poziom zaufania
WebInterface.DefaultText.Option.NegativeTrust=Negatywny poziom zaufania
WebInterface.DefaultText.Option.TrustComment=Komentarz, który zostanie ustawiony w Sieci Zaufania
WebInterface.Button.Comment=Komentuj
WebInterface.SelectBox.Choose=Wybierz…
WebInterface.SelectBox.Yes=Tak
WebInterface.SelectBox.No=Nie
-WebInterface.ClickToShow.Replies=Kliknij, żeby pokazać ukryte odpowiedzi.
+WebInterface.ClickToShow.Replies=Kliknij, żeby pokazać ukryte odpowiedzi.
WebInterface.VersionInformation.CurrentVersion=Aktualna wersja:
WebInterface.VersionInformation.LatestVersion=Najnowsza wersja:
+WebInterface.VersionInformation.Homepage=Strona główna
Notification.ClickHereToRead=Kliknij tutaj, żeby przeczytać cały tekst powiadomienia.
-Notification.FirstStart.Text=Po raz pierwszy korzystasz z Sone. Zacznij od wybrania nowego Sone z tożsamości z Sieci Zaufania i zacznij śledzić inne Sone.
-Notification.Startup.Text=Sone właśnie się włącza. Należy chwilę poczekać zanim wszystkie tożsamości i Sone z sieci zaufania zostaną odzyskane. Jeśli brakuje jakichś elementów, należy być cierpliwym, najprawdopodobniej wkrótce się pojawią.
-Notification.ConfigNotRead.Text=Plik konfiguracyjny “sone.properties” nie mógł zostać odczytany, prawdopodobnie dlatego, że nie został poprawnie zapisany. Dotyczy to wersji wcześniejszych niż Sone 0.3.3 i nie można nic z tym zrobić.
+Notification.FirstStart.Text=Po raz pierwszy korzystasz z Sone. Zacznij od wybrania nowego Sone z tożsamości z Sieci Zaufania i zacznij śledzić inne Sone.
+Notification.Startup.Text=Sone właśnie się włącza. Należy chwilę poczekać zanim wszystkie tożsamości i Sone z sieci zaufania zostaną odzyskane. Jeśli brakuje jakichś elementów, należy być cierpliwym, najprawdopodobniej wkrótce się pojawią.
+Notification.ConfigNotRead.Text=Plik konfiguracyjny “sone.properties” nie mógł zostać odczytany, prawdopodobnie dlatego, że nie został poprawnie zapisany. Dotyczy to wersji wcześniejszych niż Sone 0.3.3 i nie można nic z tym zrobić.
Notification.Button.Dismiss=Odrzuć
Notification.NewSone.ShortText=Znaleziono nowe Sone:
Notification.NewSone.Text=Znaleziono nowe Sone:
Notification.NewPost.Button.MarkRead=Oznacz jako przeczytane
Notification.NewReply.ShortText=Znaleziono nowe odpowiedzi.
Notification.NewReply.Text=Znaleziono nowe odpowiedzi napisane przez poniższych użytkowników Sone:
-Notification.SoneIsBeingRescued.Text=Następujące Sone są aktualnie odzyskiwane:
+Notification.SoneIsBeingRescued.Text=Następujące Sone są aktualnie odzyskiwane:
Notification.SoneRescued.Text=Odzyskano następujące Sone:
Notification.SoneRescued.Text.RememberToUnlock=Należy pamiętać o zarządzaniu napisanymi postami i odpowiedziami oraz nie zapomnieć o odblokowaniu swoich Sone!
-Notification.LockedSones.Text=Następujące Sone są zablokowane od ponad 5 minut. Sprawdź czy chcesz, żeby pozostały zablokowane.
+Notification.LockedSones.Text=Następujące Sone są zablokowane od ponad 5 minut. Sprawdź czy chcesz, żeby pozostały zablokowane.
Notification.NewVersion.Text=Znaleziono wersję {version}wtyczki Sone. Ściągnij ją z USK@nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI,DuQSUZiI~agF8c-6tjsFFGuZ8eICrzWCILB60nT8KKo,AQACAAE/sone/{edition}!
Notification.InsertingImages.Text=Ładowane są następujące obrazy:
Notification.InsertedImages.Text=Załadowano nastepujące obrazy:
Page.Options.Section.RuntimeOptions.Title=Поведение во время работы.
Page.Options.Option.InsertionDelay.Description=Количество секунд, в течение которых выгрузчик Sone ожидает после изменения Sone до того, как он будет выгружен.
Page.Options.Option.PostsPerPage.Description=Количество сообщений, которое должно быть показно на странице до того, как будут показаны кнопки переключения страниц.
+Page.Options.Option.ImagesPerPage.Description=Количество изображений, которое должно быть показно на странице до того, как будут показаны кнопки переключения страниц.
Page.Options.Option.CharactersPerPost.Description=Количество символов сообщения, которые должны быть показаны до того, как оно будет обрезано и будет показана ссылка для его раскрытия (-1 для отключения). Фактическая длина обрезанного сообщения задается нижеследующей настройкой.
Page.Options.Option.PostCutOffLength.Description=Количество символов, которые показываются, если сообщение посчитано слишком длинным (см. настройку выше).
Page.Options.Option.RequireFullAccess.Description=Запрещать доступ к Sone любому хосту, которому не был дан полный доступ.
Page.Index.Button.Post=Отправить!
Page.Index.PostList.Title=Лента сообщений
Page.Index.PostList.Text.NoPostYet=Никто еще не написал ни одного сообщения. Вам, наверное, следует начать это прямо сейчас!
+Page.Index.PostList.Text.FollowSomeSones=Или возможно вы не подписаны ни на один Sone? Посмотрите на список {link}Известныx Sone{/link} и попдишитесь на всех, кто покажется вам интересным!
Page.New.Title=Новые сообщения и ответы - Sone
Page.New.Page.Title=Новые сообщения и ответы
WebInterface.DefaultText.EditImage.Title=Название изображения
WebInterface.DefaultText.EditImage.Description=Описание изображения
WebInterface.DefaultText.Option.PostsPerPage=Количество сообщений, показываемых на странице
+WebInterface.DefaultText.Option.ImagesPerPage=Количество изображений, показываемых на странице
WebInterface.DefaultText.Option.CharactersPerPost=Количество символов, которое должно быть у сообщения, чтобы оно было сокращено
WebInterface.DefaultText.Option.PostCutOffLength=Количество символов в сокращенном варианте сообщения
WebInterface.DefaultText.Option.PositiveTrust=Положительное доверие для назначения
WebInterface.DefaultText.Option.NegativeTrust=Отрицательное доверие для назначения
WebInterface.DefaultText.Option.TrustComment=Комментарий для установки в web of trust
-WebInterface.Button.Comment=Comment
+WebInterface.Button.Comment=Комментировать
WebInterface.Confirmation.DeletePostButton=Да, удалить!
WebInterface.Confirmation.DeleteReplyButton=Да, удалить!
WebInterface.SelectBox.Choose=Выбрать…
WebInterface.ClickToShow.Replies=Нажмите, чтобы показать скрытые ответы.
WebInterface.VersionInformation.CurrentVersion=Текущая версия:
WebInterface.VersionInformation.LatestVersion=Последняя версия:
+WebInterface.VersionInformation.Homepage=Домашняя страница
Notification.ClickHereToRead=Нажмите здесь, чтобы прочитать полный текст уведомления.
Notification.FirstStart.Text=Видимо, вы запустили Sone в первый раз. Чтобы начать, создайте новый Sone из личность web of trust и начните подписываться на другие Sone.
<ul id="avatar-selection">
<li id="no-avatar">
- <input type="radio" name="avatar-id" value="none"<%ifnull avatar-image> checked="checked"<%/if>/>
+ <input type="radio" name="avatar-id" value="none"<%ifnull avatar-id> checked="checked"<%/if>/>
<%= Page.EditProfile.Avatar.Delete|l10n|html>
</li>
<%foreach currentSone.allImages image>
</div>
<%/if>
- <%foreach album.images image|paginate pageSize=core.preferences.imagesPerPage page=request.page>
+ <%foreach album.images image|paginate pageSize=core.preferences.imagesPerPage page=page>
<%first>
<h2><%= Page.ImageBrowser.Header.Images|l10n|html></h2>
<%include include/pagination.html pageParameter=="page">
<%if hasLatestVersion>
<div class="latest-version"><%= WebInterface.VersionInformation.LatestVersion|l10n|html> <b><% latestVersion|html></b></div>
<%/if>
+ <div class="homepage"><a href="/USK@nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI,DuQSUZiI~agF8c-6tjsFFGuZ8eICrzWCILB60nT8KKo,AQACAAE/sone/<%latestEdition|html>/"><%=WebInterface.VersionInformation.Homepage|l10n|html></a></div>
</div>
</div>
<%ifnull !post.sone.profile.avatar>
<%post.sone.profile.avatar|image-link max-width==48 max-height==48 mode==enlarge title=="Avatar Image">
<%else>
- <img src="/WebOfTrust/GetIdenticon?identity=<% post.sone.id|html>&width=48&height=48" width="48" height="48" alt="Avatar Image" />
+ <img src="/WebOfTrust/GetIdenticon?identity=<% post.sone.id|html>&width=48&height=48" width="48" height="48" alt="Avatar Image" />
<%/if>
<%else>
<img src="images/sone-avatar.png" width="48" height="48" alt="Avatar Image" />
<button type="submit" value="1"><%= View.Post.UnlikeLink|l10n|html></button>
</form>
<%if !post.sone.current>
- <span class='separator'>·</span>
- <form class="trust post-trust<%if post.sone.trust.assigned> hidden<%/if>" action="trust.html" method="post">
- <input type="hidden" name="formPassword" value="<% formPassword|html>" />
- <input type="hidden" name="returnPage" value="<% request.uri|html>" />
- <input type="hidden" name="sone" value="<% post.sone.id|html>" />
- <button type="submit" title="<%= View.Trust.Tooltip.Trust|l10n|html>">✓</button>
- </form>
- <form class="distrust post-distrust<%if post.sone.trust.assigned> hidden<%/if>" action="distrust.html" method="post">
- <input type="hidden" name="formPassword" value="<% formPassword|html>" />
- <input type="hidden" name="returnPage" value="<% request.uri|html>" />
- <input type="hidden" name="sone" value="<% post.sone.id|html>" />
- <button type="submit" title="<%= View.Trust.Tooltip.Distrust|l10n|html>">✗</button>
- </form>
- <form class="untrust post-untrust<%if !post.sone.trust.assigned> hidden<%/if>" action="untrust.html" method="post">
- <input type="hidden" name="formPassword" value="<% formPassword|html>" />
- <input type="hidden" name="returnPage" value="<% request.uri|html>" />
- <input type="hidden" name="sone" value="<% post.sone.id|html>" />
- <button type="submit" title="<%= View.Trust.Tooltip.Untrust|l10n|html>">↶</button>
- </form>
+ <%ifnull !post.sone.trust>
+ <span class='separator'>·</span>
+ <form class="trust post-trust<%if post.sone.trust.assigned> hidden<%/if>" action="trust.html" method="post">
+ <input type="hidden" name="formPassword" value="<% formPassword|html>" />
+ <input type="hidden" name="returnPage" value="<% request.uri|html>" />
+ <input type="hidden" name="sone" value="<% post.sone.id|html>" />
+ <button type="submit" title="<%= View.Trust.Tooltip.Trust|l10n|html>">✓</button>
+ </form>
+ <form class="distrust post-distrust<%if post.sone.trust.assigned> hidden<%/if>" action="distrust.html" method="post">
+ <input type="hidden" name="formPassword" value="<% formPassword|html>" />
+ <input type="hidden" name="returnPage" value="<% request.uri|html>" />
+ <input type="hidden" name="sone" value="<% post.sone.id|html>" />
+ <button type="submit" title="<%= View.Trust.Tooltip.Distrust|l10n|html>">✗</button>
+ </form>
+ <form class="untrust post-untrust<%if !post.sone.trust.assigned> hidden<%/if>" action="untrust.html" method="post">
+ <input type="hidden" name="formPassword" value="<% formPassword|html>" />
+ <input type="hidden" name="returnPage" value="<% request.uri|html>" />
+ <input type="hidden" name="sone" value="<% post.sone.id|html>" />
+ <button type="submit" title="<%= View.Trust.Tooltip.Untrust|l10n|html>">↶</button>
+ </form>
+ <%/if>
<%/if>
<%/if>
<%if post.sone.local>
<button type="submit" value="1"><%= View.Post.UnlikeLink|l10n|html></button>
</form>
<%if !reply.sone.current>
- <span class='separator'>·</span>
- <form class="trust reply-trust<%if reply.sone.trust.assigned> hidden<%/if>" action="trust.html" method="post">
- <input type="hidden" name="formPassword" value="<% formPassword|html>" />
- <input type="hidden" name="returnPage" value="<% request.uri|html>" />
- <input type="hidden" name="sone" value="<% reply.sone.id|html>" />
- <button type="submit" title="<%= View.Trust.Tooltip.Trust|l10n|html>">✓</button>
- </form>
- <form class="distrust reply-distrust<%if reply.sone.trust.assigned> hidden<%/if>" action="distrust.html" method="post">
- <input type="hidden" name="formPassword" value="<% formPassword|html>" />
- <input type="hidden" name="returnPage" value="<% request.uri|html>" />
- <input type="hidden" name="sone" value="<% reply.sone.id|html>" />
- <button type="submit" title="<%= View.Trust.Tooltip.Distrust|l10n|html>">✗</button>
- </form>
- <form class="untrust reply-untrust<%if !reply.sone.trust.assigned> hidden<%/if>" action="untrust.html" method="post">
- <input type="hidden" name="formPassword" value="<% formPassword|html>" />
- <input type="hidden" name="returnPage" value="<% request.uri|html>" />
- <input type="hidden" name="sone" value="<% reply.sone.id|html>" />
- <button type="submit" title="<%= View.Trust.Tooltip.Untrust|l10n|html>">↶</button>
- </form>
+ <%ifnull !reply.sone.trust>
+ <span class='separator'>·</span>
+ <form class="trust reply-trust<%if reply.sone.trust.assigned> hidden<%/if>" action="trust.html" method="post">
+ <input type="hidden" name="formPassword" value="<% formPassword|html>" />
+ <input type="hidden" name="returnPage" value="<% request.uri|html>" />
+ <input type="hidden" name="sone" value="<% reply.sone.id|html>" />
+ <button type="submit" title="<%= View.Trust.Tooltip.Trust|l10n|html>">✓</button>
+ </form>
+ <form class="distrust reply-distrust<%if reply.sone.trust.assigned> hidden<%/if>" action="distrust.html" method="post">
+ <input type="hidden" name="formPassword" value="<% formPassword|html>" />
+ <input type="hidden" name="returnPage" value="<% request.uri|html>" />
+ <input type="hidden" name="sone" value="<% reply.sone.id|html>" />
+ <button type="submit" title="<%= View.Trust.Tooltip.Distrust|l10n|html>">✗</button>
+ </form>
+ <form class="untrust reply-untrust<%if !reply.sone.trust.assigned> hidden<%/if>" action="untrust.html" method="post">
+ <input type="hidden" name="formPassword" value="<% formPassword|html>" />
+ <input type="hidden" name="returnPage" value="<% request.uri|html>" />
+ <input type="hidden" name="sone" value="<% reply.sone.id|html>" />
+ <button type="submit" title="<%= View.Trust.Tooltip.Untrust|l10n|html>">↶</button>
+ </form>
+ <%/if>
<%/if>
<%/if>
<%if reply.sone.local>
<%foreach pagination.items post>
<%include include/viewPost.html>
<%foreachelse>
- <div><%= Page.Index.PostList.Text.NoPostYet|l10n|html></div>
+ <p><%= Page.Index.PostList.Text.NoPostYet|l10n|html></p>
+ <p><%= Page.Index.PostList.Text.FollowSomeSones|l10n|html|replace needle=='{link}' replacement=='<a href="knownSones.html">'|replace needle=='{/link}' replacement=='</a>'></p>
<%/foreach>
<%include include/pagination.html pageParameter==page>
</div>
</select>
</p>
- <h2><%= Page.Options.Section.Cleaning.Title|l10n|html></h2>
-
- <p><%= Page.Options.Option.ClearOnNextRestart.Description|l10n|html|replace needle=="{strong}" replacement=="<strong>"|replace needle=="{/strong}" replacement=="</strong>"></p>
- <p><select name="clear-on-next-restart"><option disabled="disabled"><%= WebInterface.SelectBox.Choose|l10n|html></option><option value="true"<%if clear-on-next-restart> selected="selected"<%/if>><%= WebInterface.SelectBox.Yes|l10n|html></option><option value="false"<%if ! clear-on-next-restart> selected="selected"<%/if>><%= WebInterface.SelectBox.No|l10n|html></option></select>
-
- <p><%= Page.Options.Option.ReallyClearOnNextRestart.Description|l10n|html|replace needle=="{strong}" replacement=="<strong>"|replace needle=="{/strong}" replacement=="</strong>"></p>
- <p><select name="really-clear-on-next-restart"><option disabled="disabled"><%= WebInterface.SelectBox.Choose|l10n|html></option><option value="true"<%if really-clear-on-next-restart> selected="selected"<%/if>><%= WebInterface.SelectBox.Yes|l10n|html></option><option value="false"<%if ! really-clear-on-next-restart> selected="selected"<%/if>><%= WebInterface.SelectBox.No|l10n|html></option></select>
-
<p><button type="submit"><%= Page.Options.Button.Save|l10n|html></button></p>
</form>
<%foreach sone.profile.fields field>
<div class="profile-field">
<div class="name"><% field.name|html></div>
- <div class="value"><% field.value|parse></div>
+ <div class="value"><% field.value|parse sone=sone></div>
</div>
<%/foreach>
* @throws IOException
* if an I/O error occurs
*/
+ @SuppressWarnings("static-method")
public void testPlainText() throws IOException {
SoneTextParser soneTextParser = new SoneTextParser(null, null);
Iterable<Part> parts;
* @throws IOException
* if an I/O error occurs
*/
+ @SuppressWarnings("static-method")
public void testKSKLinks() throws IOException {
SoneTextParser soneTextParser = new SoneTextParser(null, null);
Iterable<Part> parts;
* @throws IOException
* if an I/O error occurs
*/
- @SuppressWarnings("synthetic-access")
+ @SuppressWarnings({ "synthetic-access", "static-method" })
public void testEmptyLinesAndSoneLinks() throws IOException {
SoneTextParser soneTextParser = new SoneTextParser(new TestSoneProvider(), null);
Iterable<Part> parts;
* valid
* @return The converted text
*/
- private String convertText(Iterable<Part> parts, Class<?>... validClasses) {
+ private static String convertText(Iterable<Part> parts, Class<?>... validClasses) {
StringBuilder text = new StringBuilder();
for (Part part : parts) {
assertNotNull("Part", part);