From: David ‘Bombe’ Roden Date: Thu, 30 Dec 2010 20:39:40 +0000 (+0100) Subject: Merge branch 'next' into edit-wot-trust X-Git-Tag: 0.4^2~8^2~38 X-Git-Url: https://git.pterodactylus.net/?p=Sone.git;a=commitdiff_plain;h=4a2fdf3b0b3dfcfc761c83797018237ec4c82a4b;hp=a4f8fd83799515684b86e2257b4fcc7a15cbe670 Merge branch 'next' into edit-wot-trust --- diff --git a/src/main/java/net/pterodactylus/sone/core/Core.java b/src/main/java/net/pterodactylus/sone/core/Core.java index 1a92901..f7b56a1 100644 --- a/src/main/java/net/pterodactylus/sone/core/Core.java +++ b/src/main/java/net/pterodactylus/sone/core/Core.java @@ -40,6 +40,8 @@ import net.pterodactylus.sone.freenet.wot.Identity; 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; @@ -147,6 +149,9 @@ public class Core implements IdentityListener { /** All known replies. */ private Set knownReplies = new HashSet(); + /** Trusted identities, sorted by own identities. */ + private Map> trustedIdentities = Collections.synchronizedMap(new HashMap>()); + /** * Creates a new core. * @@ -503,6 +508,19 @@ public class Core implements IdentityListener { } /** + * Returns whether the target Sone is trusted by the origin Sone. + * + * @param origin + * The origin Sone + * @param target + * The target Sone + * @return {@code true} if the target Sone is trusted by the origin Sone + */ + public boolean isSoneTrusted(Sone origin, Sone target) { + return trustedIdentities.containsKey(origin) && trustedIdentities.get(origin.getIdentity()).contains(target); + } + + /** * Returns the post with the given ID. * * @param postId @@ -825,7 +843,12 @@ public class Core implements IdentityListener { * @return The created Sone */ public Sone createSone(OwnIdentity ownIdentity) { - identityManager.addContext(ownIdentity, "Sone"); + try { + ownIdentity.addContext("Sone"); + } catch (WebOfTrustException wote1) { + logger.log(Level.SEVERE, "Could not add “Sone” context to own identity: " + ownIdentity, wote1); + return null; + } Sone sone = addLocalSone(ownIdentity); return sone; } @@ -875,6 +898,28 @@ public class Core implements IdentityListener { } /** + * Retrieves the trust relationship from the origin to the target. + * + * @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, "Tried to get trust from remote Sone: %s", origin); + return null; + } + try { + return target.getIdentity().getTrust((OwnIdentity) origin.getIdentity()); + } catch (WebOfTrustException wote1) { + logger.log(Level.WARNING, "Could not get trust for Sone: " + target, wote1); + return null; + } + } + + /** * Updates the stores Sone with the given Sone. * * @param sone @@ -979,8 +1024,12 @@ public class Core implements IdentityListener { localSones.remove(sone.getId()); soneInserters.remove(sone).stop(); } - identityManager.removeContext((OwnIdentity) sone.getIdentity(), "Sone"); - identityManager.removeProperty((OwnIdentity) sone.getIdentity(), "Sone.LatestEdition"); + try { + ((OwnIdentity) sone.getIdentity()).removeContext("Sone"); + ((OwnIdentity) sone.getIdentity()).removeProperty("Sone.LatestEdition"); + } catch (WebOfTrustException wote1) { + logger.log(Level.WARNING, "Could not remove context and properties from Sone: " + sone, wote1); + } try { configuration.getLongValue("Sone/" + sone.getId() + "/Time").setValue(null); } catch (ConfigurationException ce1) { @@ -1135,8 +1184,9 @@ public class Core implements IdentityListener { } logger.log(Level.INFO, "Saving Sone: %s", sone); - identityManager.setProperty((OwnIdentity) sone.getIdentity(), "Sone.LatestEdition", String.valueOf(sone.getLatestEdition())); try { + ((OwnIdentity) sone.getIdentity()).setProperty("Sone.LatestEdition", String.valueOf(sone.getLatestEdition())); + /* save Sone into configuration. */ String sonePrefix = "Sone/" + sone.getId(); configuration.getLongValue(sonePrefix + "/Time").setValue(sone.getTime()); @@ -1198,6 +1248,8 @@ public class Core implements IdentityListener { logger.log(Level.INFO, "Sone %s saved.", sone); } catch (ConfigurationException ce1) { logger.log(Level.WARNING, "Could not save Sone: " + sone, ce1); + } catch (WebOfTrustException wote1) { + logger.log(Level.WARNING, "Could not set WoT property for Sone: " + sone, wote1); } } @@ -1576,6 +1628,7 @@ public class Core implements IdentityListener { public void ownIdentityAdded(OwnIdentity ownIdentity) { logger.log(Level.FINEST, "Adding OwnIdentity: " + ownIdentity); if (ownIdentity.hasContext("Sone")) { + trustedIdentities.put(ownIdentity, Collections.synchronizedSet(new HashSet())); addLocalSone(ownIdentity); } } @@ -1586,14 +1639,16 @@ public class Core implements IdentityListener { @Override public void ownIdentityRemoved(OwnIdentity ownIdentity) { logger.log(Level.FINEST, "Removing OwnIdentity: " + ownIdentity); + trustedIdentities.remove(ownIdentity); } /** * {@inheritDoc} */ @Override - public void identityAdded(Identity identity) { + public void identityAdded(OwnIdentity ownIdentity, Identity identity) { logger.log(Level.FINEST, "Adding Identity: " + identity); + trustedIdentities.get(ownIdentity).add(identity); addRemoteSone(identity); } @@ -1601,7 +1656,7 @@ public class Core implements IdentityListener { * {@inheritDoc} */ @Override - public void identityUpdated(final Identity identity) { + public void identityUpdated(OwnIdentity ownIdentity, final Identity identity) { new Thread(new Runnable() { @Override @@ -1617,8 +1672,8 @@ public class Core implements IdentityListener { * {@inheritDoc} */ @Override - public void identityRemoved(Identity identity) { - /* TODO */ + public void identityRemoved(OwnIdentity ownIdentity, Identity identity) { + trustedIdentities.get(ownIdentity).remove(identity); } } diff --git a/src/main/java/net/pterodactylus/sone/freenet/plugin/ConnectorListener.java b/src/main/java/net/pterodactylus/sone/freenet/plugin/ConnectorListener.java new file mode 100644 index 0000000..71710e4 --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/freenet/plugin/ConnectorListener.java @@ -0,0 +1,51 @@ +/* + * Sone - ConnectorListener.java - Copyright © 2010 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 . + */ + +package net.pterodactylus.sone.freenet.plugin; + +import java.util.EventListener; + + +import freenet.support.SimpleFieldSet; +import freenet.support.api.Bucket; + +/** + * Interface for objects that want to be notified if a {@link PluginConnector} + * receives a reply from a plugin. As a connection listener is always + * {@link PluginConnector#addConnectorListener(String, String, ConnectorListener) + * added} for a specific plugin, it will always be notified for replies from the + * correct plugin (unless you register the same listener for multiple + * plugins—which you subsequently should not do). + * + * @author David ‘Bombe’ Roden + */ +public interface ConnectorListener extends EventListener { + + /** + * A reply was received from the plugin this connection listener was added + * for. + * + * @param pluginConnector + * The plugin connector that received the reply + * @param fields + * The fields of the reply + * @param data + * The data of the reply (may be null) + */ + public void receivedReply(PluginConnector pluginConnector, SimpleFieldSet fields, Bucket data); + +} diff --git a/src/main/java/net/pterodactylus/sone/freenet/plugin/ConnectorListenerManager.java b/src/main/java/net/pterodactylus/sone/freenet/plugin/ConnectorListenerManager.java new file mode 100644 index 0000000..7021332 --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/freenet/plugin/ConnectorListenerManager.java @@ -0,0 +1,60 @@ +/* + * Sone - ConnectorListenerManager.java - Copyright © 2010 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 . + */ + +package net.pterodactylus.sone.freenet.plugin; + +import net.pterodactylus.util.event.AbstractListenerManager; +import freenet.support.SimpleFieldSet; +import freenet.support.api.Bucket; + +/** + * Manages {@link ConnectorListener}s and fire events. + * + * @author David ‘Bombe’ Roden + */ +public class ConnectorListenerManager extends AbstractListenerManager { + + /** + * Creates a new manager for {@link ConnectorListener}s. + * + * @param pluginConnector + * The plugin connector that is the source for all events + */ + public ConnectorListenerManager(PluginConnector pluginConnector) { + super(pluginConnector); + } + + // + // ACTIONS + // + + /** + * Notifies all registered listeners that a reply from the plugin was + * received. + * + * @param fields + * The fields of the reply + * @param data + * The data of the reply (may be null) + */ + public void fireReceivedReply(SimpleFieldSet fields, Bucket data) { + for (ConnectorListener connectorListener : getListeners()) { + connectorListener.receivedReply(getSource(), fields, data); + } + } + +} diff --git a/src/main/java/net/pterodactylus/sone/freenet/plugin/PluginConnector.java b/src/main/java/net/pterodactylus/sone/freenet/plugin/PluginConnector.java new file mode 100644 index 0000000..e7bf828 --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/freenet/plugin/PluginConnector.java @@ -0,0 +1,203 @@ +/* + * Sone - PluginConnector.java - Copyright © 2010 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 . + */ + +package net.pterodactylus.sone.freenet.plugin; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import net.pterodactylus.util.collection.Pair; +import freenet.pluginmanager.FredPluginTalker; +import freenet.pluginmanager.PluginNotFoundException; +import freenet.pluginmanager.PluginRespirator; +import freenet.pluginmanager.PluginTalker; +import freenet.support.SimpleFieldSet; +import freenet.support.api.Bucket; + +/** + * Interface for talking to other plugins. Other plugins are identified by their + * name and a unique connection identifier. + * + * @author David ‘Bombe’ Roden + */ +public class PluginConnector implements FredPluginTalker { + + /** The plugin respirator. */ + private final PluginRespirator pluginRespirator; + + /** Connector listener managers for all plugin connections. */ + private final Map, ConnectorListenerManager> connectorListenerManagers = Collections.synchronizedMap(new HashMap, ConnectorListenerManager>()); + + /** + * Creates a new plugin connector. + * + * @param pluginRespirator + * The plugin respirator + */ + public PluginConnector(PluginRespirator pluginRespirator) { + this.pluginRespirator = pluginRespirator; + } + + // + // LISTENER MANAGEMENT + // + + /** + * Adds a connection listener for the given plugin connection. + * + * @param pluginName + * The name of the plugin + * @param identifier + * The identifier of the connection + * @param connectorListener + * The listener to add + */ + public void addConnectorListener(String pluginName, String identifier, ConnectorListener connectorListener) { + getConnectorListenerManager(pluginName, identifier).addListener(connectorListener); + } + + /** + * Removes a connection listener for the given plugin connection. + * + * @param pluginName + * The name of the plugin + * @param identifier + * The identifier of the connection + * @param connectorListener + * The listener to remove + */ + public void removeConnectorListener(String pluginName, String identifier, ConnectorListener connectorListener) { + getConnectorListenerManager(pluginName, identifier).removeListener(connectorListener); + } + + // + // ACTIONS + // + + /** + * Sends a request to the given plugin. + * + * @param pluginName + * The name of the plugin + * @param identifier + * The identifier of the connection + * @param fields + * The fields of the message + * @throws PluginException + * if the plugin can not be found + */ + public void sendRequest(String pluginName, String identifier, SimpleFieldSet fields) throws PluginException { + sendRequest(pluginName, identifier, fields, null); + } + + /** + * Sends a request to the given plugin. + * + * @param pluginName + * The name of the plugin + * @param identifier + * The identifier of the connection + * @param fields + * The fields of the message + * @param data + * The payload of the message (may be null) + * @throws PluginException + * if the plugin can not be found + */ + public void sendRequest(String pluginName, String identifier, SimpleFieldSet fields, Bucket data) throws PluginException { + getPluginTalker(pluginName, identifier).send(fields, data); + } + + // + // PRIVATE METHODS + // + + /** + * Returns the connection listener manager for the given plugin connection, + * creating a new one if none does exist yet. + * + * @param pluginName + * The name of the plugin + * @param identifier + * The identifier of the connection + * @return The connection listener manager + */ + private ConnectorListenerManager getConnectorListenerManager(String pluginName, String identifier) { + return getConnectorListenerManager(pluginName, identifier, true); + } + + /** + * Returns the connection listener manager for the given plugin connection, + * optionally creating a new one if none does exist yet. + * + * @param pluginName + * The name of the plugin + * @param identifier + * The identifier of the connection + * @param create + * {@code true} to create a new manager if there is none, + * {@code false} to return {@code null} in that case + * @return The connection listener manager, or {@code null} if none existed + * and {@code create} is {@code false} + */ + private ConnectorListenerManager getConnectorListenerManager(String pluginName, String identifier, boolean create) { + ConnectorListenerManager connectorListenerManager = connectorListenerManagers.get(new Pair(pluginName, identifier)); + if (create && (connectorListenerManager == null)) { + connectorListenerManager = new ConnectorListenerManager(this); + connectorListenerManagers.put(new Pair(pluginName, identifier), connectorListenerManager); + } + return connectorListenerManager; + } + + /** + * Returns the plugin talker for the given plugin connection. + * + * @param pluginName + * The name of the plugin + * @param identifier + * The identifier of the connection + * @return The plugin talker + * @throws PluginException + * if the plugin can not be found + */ + private PluginTalker getPluginTalker(String pluginName, String identifier) throws PluginException { + try { + return pluginRespirator.getPluginTalker(this, pluginName, identifier); + } catch (PluginNotFoundException pnfe1) { + throw new PluginException(pnfe1); + } + } + + // + // INTERFACE FredPluginTalker + // + + /** + * {@inheritDoc} + */ + @Override + public void onReply(String pluginName, String identifier, SimpleFieldSet params, Bucket data) { + ConnectorListenerManager connectorListenerManager = getConnectorListenerManager(pluginName, identifier, false); + if (connectorListenerManager == null) { + /* we don’t care about events for this plugin. */ + return; + } + connectorListenerManager.fireReceivedReply(params, data); + } + +} diff --git a/src/main/java/net/pterodactylus/sone/freenet/plugin/PluginException.java b/src/main/java/net/pterodactylus/sone/freenet/plugin/PluginException.java new file mode 100644 index 0000000..0e1af2b --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/freenet/plugin/PluginException.java @@ -0,0 +1,68 @@ +/* + * Sone - PluginException.java - Copyright © 2010 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 . + */ + +package net.pterodactylus.sone.freenet.plugin; + +import net.pterodactylus.sone.freenet.wot.WebOfTrustException; + +/** + * Exception that signals an error when communicating with a plugin. + * + * @author David ‘Bombe’ Roden + */ +public class PluginException extends WebOfTrustException { + + /** + * Creates a new plugin exception. + */ + public PluginException() { + super(); + } + + /** + * Creates a new plugin exception. + * + * @param message + * The message of the exception + */ + public PluginException(String message) { + super(message); + } + + /** + * Creates a new plugin exception. + * + * @param cause + * The cause of the exception + */ + public PluginException(Throwable cause) { + super(cause); + } + + /** + * Creates a new plugin exception. + * + * @param message + * The message of the exception + * @param cause + * The cause of the exception + */ + public PluginException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/ConnectorListener.java b/src/main/java/net/pterodactylus/sone/freenet/wot/ConnectorListener.java deleted file mode 100644 index cf1d1e3..0000000 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/ConnectorListener.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Sone - ConnectorListener.java - Copyright © 2010 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 . - */ - -package net.pterodactylus.sone.freenet.wot; - -import java.util.EventListener; - -import freenet.support.SimpleFieldSet; -import freenet.support.api.Bucket; - -/** - * Interface for objects that want to be notified if a {@link PluginConnector} - * receives a reply from a plugin. As a connection listener is always - * {@link PluginConnector#addConnectorListener(String, String, ConnectorListener) - * added} for a specific plugin, it will always be notified for replies from the - * correct plugin (unless you register the same listener for multiple - * plugins—which you subsequently should not do). - * - * @author David ‘Bombe’ Roden - */ -public interface ConnectorListener extends EventListener { - - /** - * A reply was received from the plugin this connection listener was added - * for. - * - * @param pluginConnector - * The plugin connector that received the reply - * @param fields - * The fields of the reply - * @param data - * The data of the reply (may be null) - */ - public void receivedReply(PluginConnector pluginConnector, SimpleFieldSet fields, Bucket data); - -} diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/ConnectorListenerManager.java b/src/main/java/net/pterodactylus/sone/freenet/wot/ConnectorListenerManager.java deleted file mode 100644 index 3962eef..0000000 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/ConnectorListenerManager.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Sone - ConnectorListenerManager.java - Copyright © 2010 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 . - */ - -package net.pterodactylus.sone.freenet.wot; - -import net.pterodactylus.util.event.AbstractListenerManager; -import freenet.support.SimpleFieldSet; -import freenet.support.api.Bucket; - -/** - * Manages {@link ConnectorListener}s and fire events. - * - * @author David ‘Bombe’ Roden - */ -public class ConnectorListenerManager extends AbstractListenerManager { - - /** - * Creates a new manager for {@link ConnectorListener}s. - * - * @param pluginConnector - * The plugin connector that is the source for all events - */ - public ConnectorListenerManager(PluginConnector pluginConnector) { - super(pluginConnector); - } - - // - // ACTIONS - // - - /** - * Notifies all registered listeners that a reply from the plugin was - * received. - * - * @param fields - * The fields of the reply - * @param data - * The data of the reply (may be null) - */ - public void fireReceivedReply(SimpleFieldSet fields, Bucket data) { - for (ConnectorListener connectorListener : getListeners()) { - connectorListener.receivedReply(getSource(), fields, data); - } - } - -} diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/DefaultIdentity.java b/src/main/java/net/pterodactylus/sone/freenet/wot/DefaultIdentity.java new file mode 100644 index 0000000..d262d57 --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/DefaultIdentity.java @@ -0,0 +1,283 @@ +/* + * Sone - DefaultIdentity.java - Copyright © 2010 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 . + */ + +package net.pterodactylus.sone.freenet.wot; + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import net.pterodactylus.sone.freenet.plugin.PluginException; +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; + +/** + * A Web of Trust identity. + * + * @author David ‘Bombe’ Roden + */ +public class DefaultIdentity implements Identity { + + /** The web of trust connector. */ + private final WebOfTrustConnector webOfTrustConnector; + + /** The ID of the identity. */ + private final String id; + + /** The nickname of the identity. */ + private final String nickname; + + /** The request URI of the identity. */ + private final String requestUri; + + /** The contexts of the identity. */ + private final Set contexts = Collections.synchronizedSet(new HashSet()); + + /** The properties of the identity. */ + private final Map properties = Collections.synchronizedMap(new HashMap()); + + /** Cached trust. */ + private final Cache trustCache = new MemoryCache(new ValueRetriever() { + + @Override + @SuppressWarnings("synthetic-access") + public CacheItem retrieve(OwnIdentity ownIdentity) throws CacheException { + try { + return new DefaultCacheItem(webOfTrustConnector.getTrust(ownIdentity, DefaultIdentity.this)); + } catch (PluginException pe1) { + throw new CacheException("Could not retrieve trust for OwnIdentity: " + ownIdentity, pe1); + } + } + + }); + + /** + * Creates a new identity. + * + * @param webOfTrustConnector + * The web of trust connector + * @param id + * The ID of the identity + * @param nickname + * The nickname of the identity + * @param requestUri + * The request URI of the identity + */ + public DefaultIdentity(WebOfTrustConnector webOfTrustConnector, String id, String nickname, String requestUri) { + this.webOfTrustConnector = webOfTrustConnector; + this.id = id; + this.nickname = nickname; + this.requestUri = requestUri; + } + + // + // ACCESSORS + // + + /** + * {@inheritDoc} + */ + @Override + public String getId() { + return id; + } + + /** + * {@inheritDoc} + */ + @Override + public String getNickname() { + return nickname; + } + + /** + * {@inheritDoc} + */ + @Override + public String getRequestUri() { + return requestUri; + } + + /** + * {@inheritDoc} + */ + @Override + public Set getContexts() { + return Collections.unmodifiableSet(contexts); + } + + /** + * Sets the contexts of this identity. + *

+ * This method is only called by the {@link IdentityManager}. + * + * @param contexts + * The contexts to set + */ + void setContextsPrivate(Set contexts) { + this.contexts.clear(); + this.contexts.addAll(contexts); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean hasContext(String context) { + return contexts.contains(context); + } + + /** + * Adds the given context to this identity. + *

+ * This method is only called by the {@link IdentityManager}. + * + * @param context + * The context to add + */ + void addContextPrivate(String context) { + contexts.add(context); + } + + /** + * Removes the given context from this identity. + *

+ * This method is only called by the {@link IdentityManager}. + * + * @param context + * The context to remove + */ + public void removeContextPrivate(String context) { + contexts.remove(context); + } + + /** + * {@inheritDoc} + */ + @Override + public Map getProperties() { + synchronized (properties) { + return Collections.unmodifiableMap(properties); + } + } + + /** + * Sets all properties of this identity. + *

+ * This method is only called by the {@link IdentityManager}. + * + * @param properties + * The new properties of this identity + */ + void setPropertiesPrivate(Map properties) { + synchronized (this.properties) { + this.properties.clear(); + this.properties.putAll(properties); + } + } + + /** + * Sets the property with the given name to the given value. + *

+ * This method is only called by the {@link IdentityManager}. + * + * @param name + * The name of the property + * @param value + * The value of the property + */ + void setPropertyPrivate(String name, String value) { + synchronized (properties) { + properties.put(name, value); + } + } + + /** + * {@inheritDoc} + */ + @Override + public String getProperty(String name) { + synchronized (properties) { + return properties.get(name); + } + } + + /** + * Removes the property with the given name. + *

+ * This method is only called by the {@link IdentityManager}. + * + * @param name + * The name of the property to remove + */ + void removePropertyPrivate(String name) { + synchronized (properties) { + properties.remove(name); + } + } + + /** + * {@inheritDoc} + */ + @Override + public Trust getTrust(OwnIdentity ownIdentity) throws WebOfTrustException { + try { + return trustCache.get(ownIdentity); + } catch (CacheException ce1) { + throw new WebOfTrustException("Could not get trust for OwnIdentity: " + ownIdentity, ce1); + } + } + + // + // OBJECT METHODS + // + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return id.hashCode(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object object) { + if (!(object instanceof DefaultIdentity)) { + return false; + } + DefaultIdentity identity = (DefaultIdentity) object; + return identity.id.equals(id); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return getClass().getSimpleName() + "[id=" + id + ",nickname=" + nickname + ",contexts=" + contexts + ",properties=" + properties + "]"; + } + +} diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/DefaultOwnIdentity.java b/src/main/java/net/pterodactylus/sone/freenet/wot/DefaultOwnIdentity.java new file mode 100644 index 0000000..f89ddda --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/DefaultOwnIdentity.java @@ -0,0 +1,138 @@ +/* + * Sone - DefaultOwnIdentity.java - Copyright © 2010 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 . + */ + +package net.pterodactylus.sone.freenet.wot; + +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +/** + * An own identity is an identity that the owner of the node has full control + * over. + * + * @author David ‘Bombe’ Roden + */ +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 + * The nickname of the identity + * @param requestUri + * The request URI of the identity + * @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; + this.insertUri = insertUri; + } + + // + // ACCESSORS + // + + /** + * {@inheritDoc} + */ + @Override + public String getInsertUri() { + return insertUri; + } + + /** + * {@inheritDoc} + */ + @Override + public void addContext(String context) throws WebOfTrustException { + webOfTrustConnector.addContext(this, context); + } + + /** + * {@inheritDoc} + */ + @Override + public void removeContext(String context) throws WebOfTrustException { + webOfTrustConnector.removeContext(this, context); + } + + /** + * {@inheritDoc} + */ + @Override + public void setContexts(Set 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); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public void setProperty(String name, String value) throws WebOfTrustException { + webOfTrustConnector.setProperty(this, name, value); + } + + /** + * {@inheritDoc} + */ + @Override + public void removeProperty(String name) throws WebOfTrustException { + webOfTrustConnector.removeProperty(this, name); + } + + /** + * {@inheritDoc} + */ + @Override + public void setProperties(Map properties) throws WebOfTrustException { + for (Entry 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 newProperty : properties.entrySet()) { + if (!getProperties().containsKey(newProperty.getKey())) { + webOfTrustConnector.setProperty(this, newProperty.getKey(), newProperty.getValue()); + } + } + } + +} diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/Identity.java b/src/main/java/net/pterodactylus/sone/freenet/wot/Identity.java index 5816b47..41540e5 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/Identity.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/Identity.java @@ -17,102 +17,45 @@ package net.pterodactylus.sone.freenet.wot; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; import java.util.Map; import java.util.Set; /** - * A Web of Trust identity. + * 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. * * @author David ‘Bombe’ Roden */ -public class Identity { - - /** The ID of the identity. */ - private final String id; - - /** The nickname of the identity. */ - private final String nickname; - - /** The request URI of the identity. */ - private final String requestUri; - - /** The contexts of the identity. */ - private final Set contexts = Collections.synchronizedSet(new HashSet()); - - /** The properties of the identity. */ - private final Map properties = Collections.synchronizedMap(new HashMap()); - - /** - * Creates a new identity. - * - * @param id - * The ID of the identity - * @param nickname - * The nickname of the identity - * @param requestUri - * The request URI of the identity - */ - public Identity(String id, String nickname, String requestUri) { - this.id = id; - this.nickname = nickname; - this.requestUri = requestUri; - } - - // - // ACCESSORS - // +public interface Identity { /** * Returns the ID of the identity. * * @return The ID of the identity */ - public String getId() { - return id; - } + public String getId(); /** * Returns the nickname of the identity. * * @return The nickname of the identity */ - public String getNickname() { - return nickname; - } + public String getNickname(); /** * Returns the request URI of the identity. * * @return The request URI of the identity */ - public String getRequestUri() { - return requestUri; - } + public String getRequestUri(); /** * Returns all contexts of this identity. * * @return All contexts of this identity */ - public Set getContexts() { - return Collections.unmodifiableSet(contexts); - } - - /** - * Sets all contexts of this identity. - *

- * This method is only called by the {@link IdentityManager}. - * - * @param contexts - * All contexts of the identity - */ - void setContexts(Set contexts) { - this.contexts.clear(); - this.contexts.addAll(contexts); - } + public Set getContexts(); /** * Returns whether this identity has the given context. @@ -122,75 +65,14 @@ public class Identity { * @return {@code true} if this identity has the given context, * {@code false} otherwise */ - public boolean hasContext(String context) { - return contexts.contains(context); - } - - /** - * Adds the given context to this identity. - *

- * This method is only called by the {@link IdentityManager}. - * - * @param context - * The context to add - */ - void addContext(String context) { - contexts.add(context); - } - - /** - * Removes the given context from this identity. - *

- * This method is only called by the {@link IdentityManager}. - * - * @param context - * The context to remove - */ - void removeContext(String context) { - contexts.remove(context); - } + public boolean hasContext(String context); /** * Returns all properties of this identity. * * @return All properties of this identity */ - public Map getProperties() { - synchronized (properties) { - return Collections.unmodifiableMap(properties); - } - } - - /** - * Sets all properties of this identity. - *

- * This method is only called by the {@link IdentityManager}. - * - * @param properties - * The new properties of this identity - */ - void setProperties(Map properties) { - synchronized (this.properties) { - this.properties.clear(); - this.properties.putAll(properties); - } - } - - /** - * Sets the property with the given name to the given value. - *

- * This method is only called by the {@link IdentityManager}. - * - * @param name - * The name of the property - * @param value - * The value of the property - */ - void setProperty(String name, String value) { - synchronized (properties) { - properties.put(name, value); - } - } + public Map getProperties(); /** * Returns the value of the property with the given name. @@ -199,56 +81,17 @@ public class Identity { * The name of the property * @return The value of the property */ - public String getProperty(String name) { - synchronized (properties) { - return properties.get(name); - } - } + public String getProperty(String name); /** - * Removes the property with the given name. - *

- * This method is only called by the {@link IdentityManager}. + * Retrieves the trust that this identity receives from the given own + * identity. * - * @param name - * The name of the property to remove - */ - void removeProperty(String name) { - synchronized (properties) { - properties.remove(name); - } - } - - // - // OBJECT METHODS - // - - /** - * {@inheritDoc} - */ - @Override - public int hashCode() { - return id.hashCode(); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean equals(Object object) { - if (!(object instanceof Identity)) { - return false; - } - Identity identity = (Identity) object; - return identity.id.equals(id); - } - - /** - * {@inheritDoc} + * @param ownIdentity + * The own identity to get the trust for + * @return The trust assigned to this identity + * @throws WebOfTrustException */ - @Override - public String toString() { - return getClass().getSimpleName() + "[id=" + id + ",nickname=" + nickname + ",contexts=" + contexts + ",properties=" + properties + "]"; - } + public Trust getTrust(OwnIdentity ownIdentity) throws WebOfTrustException; } diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityListener.java b/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityListener.java index 64ea61f..3721f49 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityListener.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityListener.java @@ -47,25 +47,31 @@ public interface IdentityListener extends EventListener { /** * Notifies a listener that a new identity was discovered. * + * @param ownIdentity + * The own identity at the root of the trust tree * @param identity * The new identity */ - public void identityAdded(Identity identity); + public void identityAdded(OwnIdentity ownIdentity, Identity identity); /** * Notifies a listener that some properties of the identity have changed. * + * @param ownIdentity + * The own identity at the root of the trust tree * @param identity * The updated identity */ - public void identityUpdated(Identity identity); + public void identityUpdated(OwnIdentity ownIdentity, Identity identity); /** * Notifies a listener that an identity has gone away. * + * @param ownIdentity + * The own identity at the root of the trust tree * @param identity * The disappeared identity */ - public void identityRemoved(Identity identity); + public void identityRemoved(OwnIdentity ownIdentity, Identity identity); } diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityListenerManager.java b/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityListenerManager.java index c08fd16..c6ea783 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityListenerManager.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityListenerManager.java @@ -68,39 +68,45 @@ public class IdentityListenerManager extends AbstractListenerManager oldIdentities = Collections.emptyMap(); + Map> oldIdentities = Collections.emptyMap(); while (!shouldStop()) { - Map currentIdentities = new HashMap(); + Map> currentIdentities = new HashMap>(); Map currentOwnIdentities = new HashMap(); - /* get all identities with the wanted context from WoT. */ - Set ownIdentities; try { - ownIdentities = webOfTrustConnector.loadAllOwnIdentities(); + /* get all identities with the wanted context from WoT. */ + Set ownIdentities = webOfTrustConnector.loadAllOwnIdentities(); /* check for changes. */ for (OwnIdentity ownIdentity : ownIdentities) { @@ -271,76 +191,80 @@ public class IdentityManager extends AbstractService { checkOwnIdentities(currentOwnIdentities); /* now filter for context and get all identities. */ - currentOwnIdentities.clear(); for (OwnIdentity ownIdentity : ownIdentities) { if ((context != null) && !ownIdentity.hasContext(context)) { continue; } - currentOwnIdentities.put(ownIdentity.getId(), ownIdentity); - for (Identity identity : webOfTrustConnector.loadTrustedIdentities(ownIdentity, context)) { - currentIdentities.put(identity.getId(), identity); - } - } - /* find removed identities. */ - for (Identity oldIdentity : oldIdentities.values()) { - if (!currentIdentities.containsKey(oldIdentity.getId())) { - identityListenerManager.fireIdentityRemoved(oldIdentity); + Set trustedIdentities = webOfTrustConnector.loadTrustedIdentities(ownIdentity, context); + Map identities = new HashMap(); + currentIdentities.put(ownIdentity, identities); + for (Identity identity : trustedIdentities) { + identities.put(identity.getId(), identity); } - } - /* find new identities. */ - for (Identity currentIdentity : currentIdentities.values()) { - if (!oldIdentities.containsKey(currentIdentity.getId())) { - identityListenerManager.fireIdentityAdded(currentIdentity); + /* find new identities. */ + for (Identity currentIdentity : currentIdentities.get(ownIdentity).values()) { + if (!oldIdentities.containsKey(ownIdentity) || !oldIdentities.get(ownIdentity).containsKey(currentIdentity.getId())) { + identityListenerManager.fireIdentityAdded(ownIdentity, currentIdentity); + } } - } - /* check for changes in the contexts. */ - for (Identity oldIdentity : oldIdentities.values()) { - if (!currentIdentities.containsKey(oldIdentity.getId())) { - continue; - } - Identity newIdentity = currentIdentities.get(oldIdentity.getId()); - Set oldContexts = oldIdentity.getContexts(); - Set newContexts = newIdentity.getContexts(); - if (oldContexts.size() != newContexts.size()) { - identityListenerManager.fireIdentityUpdated(newIdentity); - continue; - } - for (String oldContext : oldContexts) { - if (!newContexts.contains(oldContext)) { - identityListenerManager.fireIdentityUpdated(newIdentity); - break; + /* find removed identities. */ + if (oldIdentities.containsKey(ownIdentity)) { + for (Identity oldIdentity : oldIdentities.get(ownIdentity).values()) { + if (!currentIdentities.containsKey(oldIdentity.getId())) { + identityListenerManager.fireIdentityRemoved(ownIdentity, oldIdentity); + } } - } - } - /* check for changes in the properties. */ - for (Identity oldIdentity : oldIdentities.values()) { - if (!currentIdentities.containsKey(oldIdentity.getId())) { - continue; - } - Identity newIdentity = currentIdentities.get(oldIdentity.getId()); - Map oldProperties = oldIdentity.getProperties(); - Map newProperties = newIdentity.getProperties(); - if (oldProperties.size() != newProperties.size()) { - identityListenerManager.fireIdentityUpdated(newIdentity); - continue; - } - for (Entry oldProperty : oldProperties.entrySet()) { - if (!newProperties.containsKey(oldProperty.getKey()) || !newProperties.get(oldProperty.getKey()).equals(oldProperty.getValue())) { - identityListenerManager.fireIdentityUpdated(newIdentity); - break; + /* check for changes in the contexts. */ + for (Identity oldIdentity : oldIdentities.get(ownIdentity).values()) { + if (!currentIdentities.get(ownIdentity).containsKey(oldIdentity.getId())) { + continue; + } + Identity newIdentity = currentIdentities.get(ownIdentity).get(oldIdentity.getId()); + Set oldContexts = oldIdentity.getContexts(); + Set newContexts = newIdentity.getContexts(); + if (oldContexts.size() != newContexts.size()) { + identityListenerManager.fireIdentityUpdated(ownIdentity, newIdentity); + continue; + } + for (String oldContext : oldContexts) { + if (!newContexts.contains(oldContext)) { + identityListenerManager.fireIdentityUpdated(ownIdentity, newIdentity); + break; + } + } + } + + /* check for changes in the properties. */ + for (Identity oldIdentity : oldIdentities.get(ownIdentity).values()) { + if (!currentIdentities.get(ownIdentity).containsKey(oldIdentity.getId())) { + continue; + } + Identity newIdentity = currentIdentities.get(ownIdentity).get(oldIdentity.getId()); + Map oldProperties = oldIdentity.getProperties(); + Map newProperties = newIdentity.getProperties(); + if (oldProperties.size() != newProperties.size()) { + identityListenerManager.fireIdentityUpdated(ownIdentity, newIdentity); + continue; + } + for (Entry oldProperty : oldProperties.entrySet()) { + if (!newProperties.containsKey(oldProperty.getKey()) || !newProperties.get(oldProperty.getKey()).equals(oldProperty.getValue())) { + identityListenerManager.fireIdentityUpdated(ownIdentity, newIdentity); + break; + } + } } } - } - /* remember the current set of identities. */ - oldIdentities = currentIdentities; + /* remember the current set of identities. */ + oldIdentities = currentIdentities; + } - } catch (PluginException pe1) { - logger.log(Level.WARNING, "WoT has disappeared!", pe1); + } catch (WebOfTrustException wote1) { + logger.log(Level.WARNING, "WoT has disappeared!", wote1); } /* wait a minute before checking again. */ diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/OwnIdentity.java b/src/main/java/net/pterodactylus/sone/freenet/wot/OwnIdentity.java index d9ec160..deaf25c 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/OwnIdentity.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/OwnIdentity.java @@ -17,45 +17,95 @@ package net.pterodactylus.sone.freenet.wot; +import java.util.Map; +import java.util.Set; + /** - * An own identity is an identity that the owner of the node has full control - * over. + * Defines a local identity, an own identity. * * @author David ‘Bombe’ Roden */ -public class OwnIdentity extends Identity { +public interface OwnIdentity extends Identity { - /** The insert URI of the identity. */ - private final String insertUri; + /** + * Returns the insert URI of the identity. + * + * @return The insert URI of the identity + */ + public String getInsertUri(); /** - * Creates a new own identity. + * Adds the given context to this identity. + *

+ * This method is only called by the {@link IdentityManager}. * - * @param id - * The ID of the identity - * @param nickname - * The nickname of the identity - * @param requestUri - * The request URI of the identity - * @param insertUri - * The insert URI of the identity + * @param context + * The context to add + * @throws WebOfTrustException + * if an error occurs */ - public OwnIdentity(String id, String nickname, String requestUri, String insertUri) { - super(id, nickname, requestUri); - this.insertUri = insertUri; - } + public void addContext(String context) throws WebOfTrustException; - // - // ACCESSORS - // + /** + * Sets all contexts of this identity. + *

+ * 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 contexts) throws WebOfTrustException; /** - * Returns the insert URI of the identity. + * Removes the given context from this identity. + *

+ * This method is only called by the {@link IdentityManager}. * - * @return The insert URI of the identity + * @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. + *

+ * This method is only called by the {@link IdentityManager}. + * + * @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. + *

+ * 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 properties) throws WebOfTrustException; + + /** + * Removes the property with the given name. + *

+ * 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 String getInsertUri() { - return insertUri; - } + public void removeProperty(String name) throws WebOfTrustException; } diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/PluginConnector.java b/src/main/java/net/pterodactylus/sone/freenet/wot/PluginConnector.java deleted file mode 100644 index 561f092..0000000 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/PluginConnector.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Sone - PluginConnector.java - Copyright © 2010 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 . - */ - -package net.pterodactylus.sone.freenet.wot; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import net.pterodactylus.util.collection.Pair; -import freenet.pluginmanager.FredPluginTalker; -import freenet.pluginmanager.PluginNotFoundException; -import freenet.pluginmanager.PluginRespirator; -import freenet.pluginmanager.PluginTalker; -import freenet.support.SimpleFieldSet; -import freenet.support.api.Bucket; - -/** - * Interface for talking to other plugins. Other plugins are identified by their - * name and a unique connection identifier. - * - * @author David ‘Bombe’ Roden - */ -public class PluginConnector implements FredPluginTalker { - - /** The plugin respirator. */ - private final PluginRespirator pluginRespirator; - - /** Connector listener managers for all plugin connections. */ - private final Map, ConnectorListenerManager> connectorListenerManagers = Collections.synchronizedMap(new HashMap, ConnectorListenerManager>()); - - /** - * Creates a new plugin connector. - * - * @param pluginRespirator - * The plugin respirator - */ - public PluginConnector(PluginRespirator pluginRespirator) { - this.pluginRespirator = pluginRespirator; - } - - // - // LISTENER MANAGEMENT - // - - /** - * Adds a connection listener for the given plugin connection. - * - * @param pluginName - * The name of the plugin - * @param identifier - * The identifier of the connection - * @param connectorListener - * The listener to add - */ - public void addConnectorListener(String pluginName, String identifier, ConnectorListener connectorListener) { - getConnectorListenerManager(pluginName, identifier).addListener(connectorListener); - } - - /** - * Removes a connection listener for the given plugin connection. - * - * @param pluginName - * The name of the plugin - * @param identifier - * The identifier of the connection - * @param connectorListener - * The listener to remove - */ - public void removeConnectorListener(String pluginName, String identifier, ConnectorListener connectorListener) { - getConnectorListenerManager(pluginName, identifier).removeListener(connectorListener); - } - - // - // ACTIONS - // - - /** - * Sends a request to the given plugin. - * - * @param pluginName - * The name of the plugin - * @param identifier - * The identifier of the connection - * @param fields - * The fields of the message - * @throws PluginException - * if the plugin can not be found - */ - public void sendRequest(String pluginName, String identifier, SimpleFieldSet fields) throws PluginException { - sendRequest(pluginName, identifier, fields, null); - } - - /** - * Sends a request to the given plugin. - * - * @param pluginName - * The name of the plugin - * @param identifier - * The identifier of the connection - * @param fields - * The fields of the message - * @param data - * The payload of the message (may be null) - * @throws PluginException - * if the plugin can not be found - */ - public void sendRequest(String pluginName, String identifier, SimpleFieldSet fields, Bucket data) throws PluginException { - getPluginTalker(pluginName, identifier).send(fields, data); - } - - // - // PRIVATE METHODS - // - - /** - * Returns the connection listener manager for the given plugin connection, - * creating a new one if none does exist yet. - * - * @param pluginName - * The name of the plugin - * @param identifier - * The identifier of the connection - * @return The connection listener manager - */ - private ConnectorListenerManager getConnectorListenerManager(String pluginName, String identifier) { - return getConnectorListenerManager(pluginName, identifier, true); - } - - /** - * Returns the connection listener manager for the given plugin connection, - * optionally creating a new one if none does exist yet. - * - * @param pluginName - * The name of the plugin - * @param identifier - * The identifier of the connection - * @param create - * {@code true} to create a new manager if there is none, - * {@code false} to return {@code null} in that case - * @return The connection listener manager, or {@code null} if none existed - * and {@code create} is {@code false} - */ - private ConnectorListenerManager getConnectorListenerManager(String pluginName, String identifier, boolean create) { - ConnectorListenerManager connectorListenerManager = connectorListenerManagers.get(new Pair(pluginName, identifier)); - if (create && (connectorListenerManager == null)) { - connectorListenerManager = new ConnectorListenerManager(this); - connectorListenerManagers.put(new Pair(pluginName, identifier), connectorListenerManager); - } - return connectorListenerManager; - } - - /** - * Returns the plugin talker for the given plugin connection. - * - * @param pluginName - * The name of the plugin - * @param identifier - * The identifier of the connection - * @return The plugin talker - * @throws PluginException - * if the plugin can not be found - */ - private PluginTalker getPluginTalker(String pluginName, String identifier) throws PluginException { - try { - return pluginRespirator.getPluginTalker(this, pluginName, identifier); - } catch (PluginNotFoundException pnfe1) { - throw new PluginException(pnfe1); - } - } - - // - // INTERFACE FredPluginTalker - // - - /** - * {@inheritDoc} - */ - @Override - public void onReply(String pluginName, String identifier, SimpleFieldSet params, Bucket data) { - ConnectorListenerManager connectorListenerManager = getConnectorListenerManager(pluginName, identifier, false); - if (connectorListenerManager == null) { - /* we don’t care about events for this plugin. */ - return; - } - connectorListenerManager.fireReceivedReply(params, data); - } - -} diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/PluginException.java b/src/main/java/net/pterodactylus/sone/freenet/wot/PluginException.java deleted file mode 100644 index 36cf49a..0000000 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/PluginException.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Sone - PluginException.java - Copyright © 2010 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 . - */ - -package net.pterodactylus.sone.freenet.wot; - -/** - * Exception that signals an error when communicating with a plugin. - * - * @author David ‘Bombe’ Roden - */ -public class PluginException extends Exception { - - /** - * Creates a new plugin exception. - */ - public PluginException() { - super(); - } - - /** - * Creates a new plugin exception. - * - * @param message - * The message of the exception - */ - public PluginException(String message) { - super(message); - } - - /** - * Creates a new plugin exception. - * - * @param cause - * The cause of the exception - */ - public PluginException(Throwable cause) { - super(cause); - } - - /** - * Creates a new plugin exception. - * - * @param message - * The message of the exception - * @param cause - * The cause of the exception - */ - public PluginException(String message, Throwable cause) { - super(message, cause); - } - -} diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/Trust.java b/src/main/java/net/pterodactylus/sone/freenet/wot/Trust.java new file mode 100644 index 0000000..975dd3f --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/Trust.java @@ -0,0 +1,82 @@ +/* + * Sone - Trust.java - Copyright © 2010 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 . + */ + +package net.pterodactylus.sone.freenet.wot; + +/** + * Container class for trust in the web of trust. + * + * @author David ‘Bombe’ Roden + */ +public class Trust { + + /** Explicitely assigned trust. */ + private final Integer explicit; + + /** Implicitely calculated trust. */ + private final Integer implicit; + + /** The distance from the owner of the trust tree. */ + private final Integer distance; + + /** + * Creates a new trust container. + * + * @param explicit + * The explicit trust + * @param implicit + * The implicit trust + * @param distance + * The distance + */ + public Trust(Integer explicit, Integer implicit, Integer distance) { + this.explicit = explicit; + this.implicit = implicit; + this.distance = distance; + } + + /** + * Returns the trust explicitely assigned to an identity. + * + * @return The explicitely assigned trust, or {@code null} if the identity + * is not in the own identity’s trust tree + */ + public Integer getExplicit() { + return explicit; + } + + /** + * Returns the implicitely assigned trust, or the calculated trust. + * + * @return The calculated trust, or {@code null} if the identity is not in + * the own identity’s trust tree + */ + public Integer getImplicit() { + return implicit; + } + + /** + * Returns the distance of the trusted identity from the trusting identity. + * + * @return The distance from the own identity, or {@code null} if the + * identity is not in the own identity’s trust tree + */ + public Integer getDistance() { + return distance; + } + +} diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustConnector.java b/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustConnector.java index becb178..5d85082 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustConnector.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustConnector.java @@ -25,6 +25,9 @@ import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; +import net.pterodactylus.sone.freenet.plugin.ConnectorListener; +import net.pterodactylus.sone.freenet.plugin.PluginConnector; +import net.pterodactylus.sone.freenet.plugin.PluginException; import net.pterodactylus.util.logging.Logging; import freenet.support.SimpleFieldSet; import freenet.support.api.Bucket; @@ -71,10 +74,10 @@ public class WebOfTrustConnector implements ConnectorListener { * Loads all own identities from the Web of Trust plugin. * * @return All own identity - * @throws PluginException + * @throws WebOfTrustException * if the own identities can not be loaded */ - public Set loadAllOwnIdentities() throws PluginException { + public Set loadAllOwnIdentities() throws WebOfTrustException { Reply reply = performRequest(SimpleFieldSetConstructor.create().put("Message", "GetOwnIdentities").get(), "OwnIdentities"); SimpleFieldSet fields = reply.getFields(); int ownIdentityCounter = -1; @@ -87,9 +90,9 @@ public class WebOfTrustConnector implements ConnectorListener { String requestUri = fields.get("RequestURI" + ownIdentityCounter); String insertUri = fields.get("InsertURI" + ownIdentityCounter); String nickname = fields.get("Nickname" + ownIdentityCounter); - OwnIdentity ownIdentity = new OwnIdentity(id, nickname, requestUri, insertUri); - ownIdentity.setContexts(parseContexts("Contexts" + ownIdentityCounter + ".", fields)); - ownIdentity.setProperties(parseProperties("Properties" + ownIdentityCounter + ".", fields)); + DefaultOwnIdentity ownIdentity = new DefaultOwnIdentity(this, id, nickname, requestUri, insertUri); + ownIdentity.setContextsPrivate(parseContexts("Contexts" + ownIdentityCounter + ".", fields)); + ownIdentity.setPropertiesPrivate(parseProperties("Properties" + ownIdentityCounter + ".", fields)); ownIdentities.add(ownIdentity); } return ownIdentities; @@ -133,9 +136,9 @@ public class WebOfTrustConnector implements ConnectorListener { } String nickname = fields.get("Nickname" + identityCounter); String requestUri = fields.get("RequestURI" + identityCounter); - Identity identity = new Identity(id, nickname, requestUri); - identity.setContexts(parseContexts("Contexts" + identityCounter + ".", fields)); - identity.setProperties(parseProperties("Properties" + identityCounter + ".", fields)); + DefaultIdentity identity = new DefaultIdentity(this, id, nickname, requestUri); + identity.setContextsPrivate(parseContexts("Contexts" + identityCounter + ".", fields)); + identity.setPropertiesPrivate(parseProperties("Properties" + identityCounter + ".", fields)); identities.add(identity); } return identities; @@ -216,6 +219,58 @@ public class WebOfTrustConnector implements ConnectorListener { } /** + * Returns the trust for the given identity assigned to it by the given own + * identity. + * + * @param ownIdentity + * The own identity + * @param identity + * The identity to get the trust for + * @return The trust for the given identity + * @throws PluginException + * if an error occured talking to the Web of Trust plugin + */ + public Trust getTrust(OwnIdentity ownIdentity, Identity identity) throws PluginException { + Reply getTrustReply = performRequest(SimpleFieldSetConstructor.create().put("Message", "GetIdentity").put("TreeOwner", ownIdentity.getId()).put("Identity", identity.getId()).get(), "Identity"); + String trust = getTrustReply.getFields().get("Trust"); + String score = getTrustReply.getFields().get("Score"); + String rank = getTrustReply.getFields().get("Rank"); + Integer explicit = null; + Integer implicit = null; + Integer distance = null; + try { + explicit = Integer.valueOf(trust); + } catch (NumberFormatException nfe1) { + /* ignore. */ + } + try { + implicit = Integer.valueOf(score); + distance = Integer.valueOf(rank); + } catch (NumberFormatException nfe1) { + /* ignore. */ + } + return new Trust(explicit, implicit, distance); + } + + /** + * Sets the trust for the given identity. + * + * @param ownIdentity + * The trusting identity + * @param identity + * The trusted identity + * @param trust + * The amount of trust (-100 thru 100) + * @param comment + * The comment or explanation of the trust value + * @throws PluginException + * if an error occured talking to the Web of Trust plugin + */ + public void setTrust(OwnIdentity ownIdentity, Identity identity, int trust, String comment) throws PluginException { + performRequest(SimpleFieldSetConstructor.create().put("Message", "SetTrust").put("Truster", ownIdentity.getId()).put("Trustee", identity.getId()).put("Value", String.valueOf(trust)).put("Comment", comment).get(), "TrustSet"); + } + + /** * Pings the Web of Trust plugin. If the plugin can not be reached, a * {@link PluginException} is thrown. * diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustException.java b/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustException.java new file mode 100644 index 0000000..f59b2a3 --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustException.java @@ -0,0 +1,67 @@ +/* + * Sone - WebOfTrustException.java - Copyright © 2010 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 . + */ + +package net.pterodactylus.sone.freenet.wot; + +/** + * Exception that signals an error processing web of trust identities, mostly + * when communicating with the web of trust plugin. + * + * @author David ‘Bombe’ Roden + */ +public class WebOfTrustException extends Exception { + + /** + * Creates a new web of trust exception. + */ + public WebOfTrustException() { + super(); + } + + /** + * Creates a new web of trust exception. + * + * @param message + * The message of the exception + */ + public WebOfTrustException(String message) { + super(message); + } + + /** + * Creates a new web of trust exception. + * + * @param cause + * The cause of the exception + */ + public WebOfTrustException(Throwable cause) { + super(cause); + } + + /** + * Creates a new web of trust exception. + * + * @param message + * The message of the exception + * @param cause + * The cause of the exception + */ + public WebOfTrustException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/src/main/java/net/pterodactylus/sone/main/SonePlugin.java b/src/main/java/net/pterodactylus/sone/main/SonePlugin.java index c5c8835..83fc71e 100644 --- a/src/main/java/net/pterodactylus/sone/main/SonePlugin.java +++ b/src/main/java/net/pterodactylus/sone/main/SonePlugin.java @@ -25,8 +25,8 @@ import java.util.logging.Logger; import net.pterodactylus.sone.core.Core; import net.pterodactylus.sone.core.FreenetInterface; import net.pterodactylus.sone.freenet.PluginStoreConfigurationBackend; +import net.pterodactylus.sone.freenet.plugin.PluginConnector; import net.pterodactylus.sone.freenet.wot.IdentityManager; -import net.pterodactylus.sone.freenet.wot.PluginConnector; import net.pterodactylus.sone.freenet.wot.WebOfTrustConnector; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.util.config.Configuration; diff --git a/src/main/java/net/pterodactylus/sone/template/SoneAccessor.java b/src/main/java/net/pterodactylus/sone/template/SoneAccessor.java index c9c5f48..c4eac6c 100644 --- a/src/main/java/net/pterodactylus/sone/template/SoneAccessor.java +++ b/src/main/java/net/pterodactylus/sone/template/SoneAccessor.java @@ -89,6 +89,9 @@ public class SoneAccessor extends ReflectionAccessor { return core.isNewSone(sone); } else if (member.equals("locked")) { return core.isLocked(sone); + } else if (member.equals("trust")) { + Sone currentSone = (Sone) dataProvider.getData("currentSone"); + return core.getTrust(currentSone, sone); } return super.get(dataProvider, object, member); } diff --git a/src/main/java/net/pterodactylus/sone/template/TrustAccessor.java b/src/main/java/net/pterodactylus/sone/template/TrustAccessor.java new file mode 100644 index 0000000..4dfd81e --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/template/TrustAccessor.java @@ -0,0 +1,54 @@ +/* + * Sone - TrustAccessor.java - Copyright © 2010 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 . + */ + +package net.pterodactylus.sone.template; + +import net.pterodactylus.sone.freenet.wot.Trust; +import net.pterodactylus.util.template.Accessor; +import net.pterodactylus.util.template.DataProvider; +import net.pterodactylus.util.template.ReflectionAccessor; + +/** + * {@link Accessor} implementation for {@link Trust} values, adding the + * following properties: + *

+ *
assigned
+ *
{@link Boolean} that indicates whether this trust relationship has an + * explicit value assigned to it.
+ *
+ * + * @author David ‘Bombe’ Roden + */ +public class TrustAccessor extends ReflectionAccessor { + + /** + * {@inheritDoc} + */ + @Override + public Object get(DataProvider dataProvider, Object object, String member) { + Trust trust = (Trust) object; + if ("assigned".equals(member)) { + return trust.getExplicit() != null; + } else if ("maximum".equals(member)) { + return ((trust.getExplicit() != null) && (trust.getExplicit() >= 100)) || ((trust.getImplicit() != null) && (trust.getImplicit() >= 100)); + } else if ("hasDistance".equals(member)) { + return (trust.getDistance() != null) && (trust.getDistance() != Integer.MAX_VALUE); + } + return super.get(dataProvider, object, member); + } + +} diff --git a/src/main/java/net/pterodactylus/sone/web/CreateSonePage.java b/src/main/java/net/pterodactylus/sone/web/CreateSonePage.java index 1c16d31..e5f176f 100644 --- a/src/main/java/net/pterodactylus/sone/web/CreateSonePage.java +++ b/src/main/java/net/pterodactylus/sone/web/CreateSonePage.java @@ -111,7 +111,6 @@ public class CreateSonePage extends SoneTemplatePage { return; } /* create Sone. */ - webInterface.getCore().getIdentityManager().addContext(selectedIdentity, "Sone"); Sone sone = webInterface.getCore().createSone(selectedIdentity); if (sone == null) { logger.log(Level.SEVERE, "Could not create Sone for OwnIdentity: %s", selectedIdentity); diff --git a/src/main/java/net/pterodactylus/sone/web/WebInterface.java b/src/main/java/net/pterodactylus/sone/web/WebInterface.java index d3ec1ee..c1c0653 100644 --- a/src/main/java/net/pterodactylus/sone/web/WebInterface.java +++ b/src/main/java/net/pterodactylus/sone/web/WebInterface.java @@ -40,6 +40,7 @@ import net.pterodactylus.sone.data.Reply; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.freenet.L10nFilter; import net.pterodactylus.sone.freenet.wot.Identity; +import net.pterodactylus.sone.freenet.wot.Trust; import net.pterodactylus.sone.main.SonePlugin; import net.pterodactylus.sone.notify.ListNotification; import net.pterodactylus.sone.template.CollectionAccessor; @@ -52,6 +53,7 @@ import net.pterodactylus.sone.template.ReplyAccessor; import net.pterodactylus.sone.template.RequestChangeFilter; import net.pterodactylus.sone.template.SoneAccessor; import net.pterodactylus.sone.template.SubstringFilter; +import net.pterodactylus.sone.template.TrustAccessor; import net.pterodactylus.sone.web.ajax.CreatePostAjaxPage; import net.pterodactylus.sone.web.ajax.CreateReplyAjaxPage; import net.pterodactylus.sone.web.ajax.DeletePostAjaxPage; @@ -159,6 +161,7 @@ public class WebInterface implements CoreListener { templateFactory.addAccessor(Reply.class, new ReplyAccessor(getCore(), templateFactory)); templateFactory.addAccessor(Identity.class, new IdentityAccessor(getCore())); templateFactory.addAccessor(NotificationManager.class, new NotificationManagerAccessor()); + templateFactory.addAccessor(Trust.class, new TrustAccessor()); templateFactory.addFilter("date", new DateFilter()); templateFactory.addFilter("l10n", new L10nFilter(getL10n())); templateFactory.addFilter("substring", new SubstringFilter()); diff --git a/src/main/resources/i18n/sone.en.properties b/src/main/resources/i18n/sone.en.properties index e080e4d..66d8f5c 100644 --- a/src/main/resources/i18n/sone.en.properties +++ b/src/main/resources/i18n/sone.en.properties @@ -159,6 +159,10 @@ View.Post.Reply.DeleteLink=Delete View.Post.LikeLink=Like View.Post.UnlikeLink=Unlike +View.Trust.Label=Trust: +View.Trust.IncreaseTrustLink=↑ +View.Trust.DecreaseTrustLink=↓ + WebInterface.DefaultText.StatusUpdate=What’s on your mind? WebInterface.DefaultText.Message=Write a Message… WebInterface.DefaultText.Reply=Write a Reply… diff --git a/src/main/resources/static/css/sone.css b/src/main/resources/static/css/sone.css index c978cf2..0ca86b0 100644 --- a/src/main/resources/static/css/sone.css +++ b/src/main/resources/static/css/sone.css @@ -181,6 +181,19 @@ textarea { min-height: 48px; } +#sone .trust { + font-size: 85%; + text-align: center; +} + +#sone .trust .explicit { + color: rgb(0, 128, 0); +} + +#sone .trust .implicit { + color: rgb(128, 128, 128); +} + #sone .post .author, #sone .post .recipient { display: inline; font-weight: bold; @@ -201,9 +214,10 @@ textarea { color: #666; } -#sone .post .delete, #sone .post .likes, #sone .post .like, #sone .post .unlike { +#sone .post .delete, #sone .post .likes, #sone .post .like, #sone .post .unlike, #sone .post .increase-trust, #sone .post .decrease-trust { display: inline; font: inherit; + margin: 0px; } #sone .post .likes.hidden { @@ -214,15 +228,16 @@ textarea { display: none; } -#sone .post .delete button, #sone .post .like button, #sone .post .unlike button { +#sone .post .delete button, #sone .post .like button, #sone .post .unlike button, #sone .post .increase-trust button, #sone .post .decrease-trust button { border: 0px; background: none; padding: 0px; color: rgb(28, 131, 191); font: inherit; + margin: 0px; } -#sone .post .delete button:hover, #sone .post .like button:hover, #sone .post .unlike button:hover { +#sone .post .delete button:hover, #sone .post .like button:hover, #sone .post .unlike button:hover, #sone .post .increase-trust button:hover, #sone .post .decrease-trust button:hover { border: 0px; background: none; padding: 0px; @@ -239,6 +254,19 @@ textarea { color: green; } +#sone .post .trust { + display: inline; +} + +#sone .post .trust:before { + content: ' · '; +} + +#sone .trust .explicit, #sone .trust .implicit { + font: inherit; + display: inline; +} + #sone .post .replies { clear: both; padding-top: 0.2ex; diff --git a/src/main/resources/templates/include/viewPost.html b/src/main/resources/templates/include/viewPost.html index cd6cc5c..8667bac 100644 --- a/src/main/resources/templates/include/viewPost.html +++ b/src/main/resources/templates/include/viewPost.html @@ -36,6 +36,30 @@ <%/if> + <%if !post.sone.current> +
+ <%= View.Trust.Label|l10n|html> + <%if post.sone.trust.assigned> +
<% post.sone.trust.explicit>
+ <%else> +
<% post.sone.trust.implicit><%if post.sone.trust.hasDistance> (<% post.sone.trust.distance>)<%/if>
+ <%/if> + <%if !post.sone.trust.maximum> +
+ + + + +
+ <%/if> +
+ + + + +
+
+ <%/if> <%if post.sone.current>
diff --git a/src/main/resources/templates/include/viewReply.html b/src/main/resources/templates/include/viewReply.html index f65a201..a9b308e 100644 --- a/src/main/resources/templates/include/viewReply.html +++ b/src/main/resources/templates/include/viewReply.html @@ -28,6 +28,30 @@
<%/if> + <%if !reply.sone.current> +
+ <%= View.Trust.Label|l10n|html> + <%if reply.sone.trust.assigned> +
<% reply.sone.trust.explicit>
+ <%else> +
<% reply.sone.trust.implicit><%if reply.sone.trust.hasDistance> (<% reply.sone.trust.distance>)<%/if>
+ <%/if> + <%if !reply.sone.trust.maximum> +
+ + + + +
+ <%/if> +
+ + + + +
+
+ <%/if> <%if reply.sone.current>