Commit Diff


commit - 0c5b0816e0f53de20dcc2e73b291d557ded56219
commit + fcc72cc40e3d82cc30b6c370d4070f7e98ff6e7e
blob - d21e7b44c33ac6b1fa5464c825d510259f04d86f (mode 644)
blob + /dev/null
--- src/org/snipsnap/app/Application.java
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * This file is part of "SnipSnap Wiki/Weblog".
- *
- * Copyright (c) 2002 Stephan J. Schmidt, Matthias L. Jugel
- * All Rights Reserved.
- *
- * Please visit http://snipsnap.org/ for updates and contact.
- *
- * --LICENSE NOTICE--
- * 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- * --LICENSE NOTICE--
- */
-package org.snipsnap.app;
-
-import org.radeox.util.logging.Logger;
-import org.snipsnap.config.Configuration;
-import org.snipsnap.config.ConfigurationProxy;
-import org.snipsnap.container.Components;
-import org.snipsnap.user.AuthenticationService;
-import org.snipsnap.user.User;
-import org.snipsnap.user.UserManagerFactory;
-import org.snipsnap.util.ApplicationAwareMap;
-
-import javax.servlet.http.HttpSession;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-/**
- * The application object contains information about current users and other
- * session specific information.
- * @author Stephan J. Schmidt
- * @version $Id$
- */
-public class Application {
-  public final static String OID = "_applicationOid";
-  public final static String URL = "_url";
-
-  private static ApplicationAwareMap currentUsers =
-    new ApplicationAwareMap(HashMap.class, HashMap.class);
-
-  private static ThreadLocal instance = new ThreadLocal() {
-    protected synchronized Object initialValue() {
-      return new Application();
-    }
-  };
-
-  // TODO make this an application-aware map to get old functionality
-  private Map objectStore = new HashMap();
-  private User user;
-  private Configuration config;
-  private List log = new ArrayList();
-  // TODO use private NotificationService notification;
-  private Map params;
-
-  public static Application get() {
-    Application app = (Application) instance.get();
-    if (null == app) {
-      app = new Application();
-      instance.set(app);
-    }
-    return app;
-  }
-
-  public static Application forceGet() {
-    instance.set(null);
-    return get();
-  }
-
-  public static void set(Application application) {
-    instance.set(application);
-  }
-
-  public void clearLog() {
-    log = new ArrayList();
-  }
-
-  public List getLog() {
-    return log;
-  }
-
-  public void log(String output) {
-    log.add(output);
-  }
-
-  public long start() {
-    return System.currentTimeMillis();
-  }
-
-  public void stop(long start, String output) {
-    Logger.log(Logger.PERF, output + " - " + (System.currentTimeMillis() - start));
-  }
-
-  public User getUser() {
-    return user;
-  }
-
-  public void setUser(User user) {
-    this.user = user;
-  }
-
-  public Map getParameters() {
-    return params;
-  }
-
-  public void setParameters(Map parameters) {
-    this.params = parameters;
-  }
-
-  public void setUser(User user, HttpSession session) {
-    if (this.user == user) {
-      return;
-    }
-
-    if (this.user != null) {
-      Application.removeCurrentUser(session);
-    }
-    setUser(user);
-    Application.addCurrentUser(user, session);
-    if(user.isGuest() || user.isNonUser()) {
-      session.setMaxInactiveInterval(120);
-    }
-    return;
-  }
-
-  public static synchronized void addCurrentUser(User user, HttpSession session) {
-//    Logger.debug("Binding user to session: "+user+": "+session);
-    currentUsers.getMap().put(session, user);
-  }
-
-  public static List getCurrentUsers() {
-    List users = new ArrayList();
-    Iterator iterator = currentUsers.getMap().values().iterator();
-    while (iterator.hasNext()) {
-      User user = (User) iterator.next();
-      if (!(user.isGuest() || user.isNonUser() || users.contains(user))) {
-        users.add(user);
-      }
-    }
-    return users;
-  }
-
-  public static List getCurrentNonUsers() {
-    List users = new ArrayList();
-    Iterator iterator = currentUsers.getMap().values().iterator();
-    while (iterator.hasNext()) {
-      User user = (User) iterator.next();
-      if (user.isNonUser() && !users.contains(user) && !"IGNORE".equals(user.getEmail())) {
-        users.add(user);
-      }
-    }
-    return users;
-  }
-
-  public static int getGuestCount() {
-    int count = 0;
-    Iterator iterator = currentUsers.getMap().values().iterator();
-    while (iterator.hasNext()) {
-      User user = (User) iterator.next();
-      if (user.isGuest() && !user.isNonUser()) {
-        count++;
-      }
-    }
-    return count;
-  }
-
-  public static synchronized void removeCurrentUser(HttpSession session) {
-    if (null == currentUsers || null == session) {
-      return;
-    }
-
-    String appOid = (String) Application.get().getObject(Application.OID);
-    Map currentUsersMap = null;
-    if (null != appOid) {
-      currentUsersMap = currentUsers.getMap(appOid);
-    } else {
-      currentUsersMap = currentUsers.findMap(session);
-    }
-
-    if (null != currentUsersMap && currentUsersMap.containsKey(session)) {
-      User user = (User) currentUsersMap.get(session);
-      AuthenticationService service = (AuthenticationService) Components.getComponent(AuthenticationService.class);
-
-      if (service.isAuthenticated(user)) {
-        Logger.debug("Removing authenticated user from session: " + user);
-        user.setLastLogout(user.getLastAccess());
-        // we ensure we remove the correct user by setting the OID from the user object
-        Application.get().storeObject(Application.OID, user.getApplication());
-        UserManagerFactory.getInstance().systemStore(user);
-      } else {
-        Logger.debug("Removing unauthenticated user from session: " + user);
-      }
-      currentUsersMap.remove(session);
-    } else {
-      Logger.warn("Unable to remove current user from session '" + session + "'");
-    }
-  }
-
-  public void storeObject(String key, Object value) {
-    objectStore.put(key, value);
-  }
-
-  public Object getObject(String key) {
-    return objectStore.get(key);
-  }
-
-  public void setConfiguration(Configuration config) {
-    this.config = config;
-  }
-
-  public Configuration getConfiguration() {
-    if (null == config) {
-      config = ConfigurationProxy.getInstance();
-    }
-    return config;
-  }
-}
blob - 1c6a2c586a7bbd7d211ba4ab9476506d21388ecc
blob + 448ae5af68d1582ad4caac6b57bbca708f7bb794
--- src/org/snipsnap/container/PicoContainer.java
+++ src/org/snipsnap/container/PicoContainer.java
@@ -2,49 +2,45 @@ package org.snipsnap.container;
 
 import dynaop.Aspects;
 import dynaop.Pointcuts;
-
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.ArrayList;
-import java.util.List;
-
-import snipsnap.api.snip.SnipSpace;
+import org.nanocontainer.dynaop.DynaopComponentAdapterFactory;
+import org.picocontainer.defaults.DefaultComponentAdapterFactory;
+import org.picocontainer.defaults.DefaultPicoContainer;
+import org.radeox.util.Service;
+import org.snipsnap.app.ApplicationManager;
+import org.snipsnap.app.ApplicationStorage;
+import org.snipsnap.app.JDBCApplicationStorage;
+import org.snipsnap.app.PropertyFileApplicationStorage;
+import org.snipsnap.components.IndexerService;
+import org.snipsnap.components.LuceneIndexerService;
+import org.snipsnap.components.SearchService;
+import org.snipsnap.config.ConfigurationProxy;
+import org.snipsnap.config.Globals;
+import org.snipsnap.feeder.BasicFeederRepository;
+import org.snipsnap.feeder.FeederRepository;
+import org.snipsnap.interceptor.custom.MissingInterceptor;
+import org.snipsnap.interceptor.custom.SnipSpaceACLInterceptor;
+import org.snipsnap.jdbc.LazyDataSource;
+import org.snipsnap.notification.MessageService;
+import org.snipsnap.render.PlainTextRenderEngine;
+import org.snipsnap.render.SnipRenderEngine;
+import org.snipsnap.security.AccessController;
+import org.snipsnap.security.DefaultAccessController;
 import org.snipsnap.snip.SnipSpaceImpl;
-import org.snipsnap.snip.label.LabelManager;
 import org.snipsnap.snip.attachment.storage.AttachmentStorage;
 import org.snipsnap.snip.attachment.storage.FileAttachmentStorage;
+import org.snipsnap.snip.label.LabelManager;
 import org.snipsnap.snip.storage.*;
-import org.snipsnap.interceptor.custom.MissingInterceptor;
-import org.snipsnap.interceptor.custom.SnipSpaceACLInterceptor;
-import org.snipsnap.config.ConfigurationProxy;
-import org.snipsnap.config.Globals;
+import org.snipsnap.user.*;
 import org.snipsnap.versioning.*;
 import org.snipsnap.versioning.cookbook.CookbookDifferenceService;
-import org.snipsnap.app.ApplicationStorage;
-import org.snipsnap.app.PropertyFileApplicationStorage;
-import org.snipsnap.app.JDBCApplicationStorage;
-import org.snipsnap.app.ApplicationManager;
-import org.snipsnap.jdbc.LazyDataSource;
-import org.snipsnap.user.*;
-import org.snipsnap.security.AccessController;
-import org.snipsnap.security.DefaultAccessController;
-import org.snipsnap.render.SnipRenderEngine;
-import org.snipsnap.render.PlainTextRenderEngine;
 import org.snipsnap.xmlrpc.*;
-import org.snipsnap.notification.MessageService;
-import org.snipsnap.notification.jmdns.JmDnsService;
-import org.snipsnap.feeder.FeederRepository;
-import org.snipsnap.feeder.BasicFeederRepository;
-import org.snipsnap.components.LuceneIndexerService;
-import org.snipsnap.components.IndexerService;
-import org.snipsnap.components.SearchService;
-import org.nanocontainer.dynaop.DynaopComponentAdapterFactory;
-import org.picocontainer.defaults.DefaultComponentAdapterFactory;
-import org.picocontainer.defaults.DefaultPicoContainer;
-import org.picocontainer.MutablePicoContainer;
-import org.radeox.util.Service;
+import snipsnap.api.snip.SnipSpace;
 
 import javax.sql.DataSource;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
 
 public class PicoContainer implements Container {
     private static org.picocontainer.MutablePicoContainer container;
blob - 14da440b774daedb7d642b01416097568a3b001a (mode 644)
blob + /dev/null
--- src/org/snipsnap/serialization/LabelContext.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package org.snipsnap.serialization;
-
-import org.snipsnap.snip.Snip;
-import org.snipsnap.snip.label.Label;
-
-/**
- * A class holding context information about a Label. Subclasses can add all sorts of things so that
- * LabelSerializers can make use of it.
- *
- * @author gis
- */
-
-public class LabelContext {
-  public Label label;
-  public Snip snip;
-
-  public LabelContext() {
-  }
-
-  public LabelContext(Snip snip, Label label) {
-    this.snip = snip;
-    this.label = label;
-  }
-
-  public Snip getSnip() {
-    return snip;
-  }
-
-  public Label getLabel() {
-    return label;
-  }
-}
blob - a5e071d4ea59e2bbff3119d3d87c3b75cea43c67 (mode 644)
blob + /dev/null
--- src/org/snipsnap/snip/Snip.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * This file is part of "SnipSnap Wiki/Weblog".
- *
- * Copyright (c) 2002 Stephan J. Schmidt, Matthias L. Jugel
- * All Rights Reserved.
- *
- * Please visit http://snipsnap.org/ for updates and contact.
- *
- * --LICENSE NOTICE--
- * 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- * --LICENSE NOTICE--
- */
-
-package org.snipsnap.snip;
-
-import org.snipsnap.serialization.Appendable;
-import org.snipsnap.snip.attachment.Attachments;
-import org.snipsnap.snip.label.Labels;
-import org.snipsnap.user.Permissions;
-import org.snipsnap.user.User;
-import org.snipsnap.render.macro.list.Linkable;
-import org.snipsnap.render.macro.list.Nameable;
-
-import javax.servlet.http.HttpServletRequest;
-import java.sql.Timestamp;
-import java.util.List;
-import java.io.IOException;
-
-/**
- * Interface for snips
- *
- * @author  Stephan J. Schmidt
- * @version $Id$
- */
-
-public interface Snip extends Linkable, gabriel.components.context.Ownable, Nameable, Appendable {
-  public void handle(HttpServletRequest request);
-
-  // HACK: looks like java beans framework does not find Nameable
-  public String getName();
-
-  public Access getAccess();
-
-  public Modified getModified();
-
-  /**
-   * Returns true, when the snip is a weblog.
-   * Currently only test against 'start'.
-   * Should be extendet to test a "weblog"-label
-   *
-   * @return true, if the snip is a weblog
-   */
-  public boolean isWeblog();
-
-  /**
-   * Conveniance function for JSP
-   *
-   * @return true, if snip is not a weblog
-   */
-  public boolean isNotWeblog();
-
-  public int getVersion();
-
-  public void setVersion(int version);
-
-  public void addPermission(String permission, String role);
-
-  public void setPermissions(Permissions permissions);
-
-  public Permissions getPermissions();
-
-  public void setApplication(String applicationOid);
-
-  public String getApplication();
-
-  public String getOUser();
-
-  public void setOUser(User oUser);
-
-  public void setOUser(String oUser);
-
-  public Attachments getAttachments();
-
-  public void setAttachments(Attachments attachments);
-
-  public Labels getLabels();
-
-  public void setLabels(Labels labels);
-
-  public Links getBackLinks();
-
-  public Links getSnipLinks();
-
-  public void setBackLinks(Links backLinks);
-
-  public void setSnipLinks(Links snipLinks);
-
-  public int getViewCount();
-
-  public void setViewCount(int count);
-
-  public int incViewCount();
-
-  public Timestamp getCTime();
-
-  public void setCTime(Timestamp cTime);
-
-  public Timestamp getMTime();
-
-  public void setMTime(Timestamp mTime);
-
-  public String getCUser();
-
-  public void setCUser(User cUser);
-
-  public void setCUser(String cUser);
-
-  public String getMUser();
-
-  public void setMUser(User mUser);
-
-  public void setMUser(String mUser);
-
-  public List getChildren();
-
-  public void setCommentedSnip(Snip comment);
-
-  public Snip getCommentedSnip();
-
-  public boolean isComment();
-
-  public Comments getComments();
-
-  public List getChildrenDateOrder();
-
-  public List getChildrenModifiedOrder();
-
-  /**
-   * Add a child snip. Sets the parent of
-   * the child to this snip and <b>stores</b> the
-   * child because of the new parent.
-   *
-   * @param snip Snip to add as child
-   */
-  public void addSnip(Snip snip);
-
-  /**
-   * Removes child snip from this nsip
-   *
-   * @param snip Child to remove
-   */
-  public void removeSnip(Snip snip);
-
-  public void setParentName(String name);
-
-  public String getParentName();
-
-  public void setCommentedName(String name);
-
-  public String getCommentedName();
-
-  public Snip getParent();
-
-  public void setDirectParent(Snip parentSnip);
-
-  public void setParent(Snip parentSnip);
-
-  /**
-   * Return a short version of the name.
-   * Useful for vertical snip listings, where
-   * the snips should not be to long.
-   * End of snip name will be replaced with "..."
-   *
-   * @return Short name of snip
-   */
-  public String getShortName();
-
-  /**
-   * Return an encoded version of the name,
-   * especially spaces replaced with "+"
-   *
-   * @return encoded name of snip
-   */
-  public String getNameEncoded();
-
-  public void setName(String name);
-
-  public String getContent();
-
-  public void setContent(String content);
-
-  public String getAttachmentString();
-
-  public String toXML();
-
-  public String getXMLContent();
-
-  public SnipPath getPath() throws IOException;
-
-  public String getTitle();
-
-  public Snip copy(String newName);
-}
blob - a1bb1caf05e8d7b42e5250784117e4243d43320d (mode 644)
blob + /dev/null
--- src/org/snipsnap/snip/SnipLink.java
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * This file is part of "SnipSnap Wiki/Weblog".
- *
- * Copyright (c) 2002 Stephan J. Schmidt, Matthias L. Jugel
- * All Rights Reserved.
- *
- * Please visit http://snipsnap.org/ for updates and contact.
- *
- * --LICENSE NOTICE--
- * 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- * --LICENSE NOTICE--
- */
-
-package org.snipsnap.snip;
-
-import org.radeox.util.logging.Logger;
-import org.radeox.util.Encoder;
-import org.radeox.util.i18n.ResourceManager;
-import org.snipsnap.app.Application;
-import org.snipsnap.config.Configuration;
-import org.snipsnap.util.URLEncoderDecoder;
-import org.snipsnap.snip.name.NameFormatter;
-import org.snipsnap.snip.name.PathRemoveFormatter;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.io.Writer;
-import java.util.Arrays;
-import java.util.List;
-import java.text.MessageFormat;
-
-/**
- *  Generates links for snips
- *
- * @author stephan
- * @version $Id$
- */
-
-public class SnipLink {
-
-  public static NameFormatter formatter = new PathRemoveFormatter();
-
-  /**
-   * Append a URL String that contains a base a name-to-be-encoded and an optional anchor target.
-   * @param writer the writer to append to
-   * @param base the url base
-   * @param name the name (to be encoded)
-   * @param target the anchor target
-   */
-  public static Writer appendUrlWithBase(Writer writer, String base, String name, String target)
-    throws IOException {
-    writer.write(base);
-    writer.write("/");
-    writer.write(encode(name));
-    if(target != null) {
-      writer.write("#");
-      writer.write(target);
-    }
-    return writer;
-  }
-
-  public static Writer appendUrl(Writer writer, String name, String target) throws IOException {
-    return appendUrlWithBase(writer, getSpaceRoot(), name, target);
-  }
-
-  public static Writer appendUrl(Writer writer, String name) throws IOException {
-    return appendUrlWithBase(writer, getSpaceRoot(), name, null);
-  }
-
-  public static Writer appendCommentsUrl(Writer writer, String name, String target) throws IOException {
-    return appendUrlWithBase(writer, getCommentsRoot(), name, target);
-  }
-
-  /**
-   * Append a create link for the specified name.
-   */
-  public static Writer appendCreateLink(Writer writer, String name) throws IOException {
-    writer.write(makeCreateLink(name));
-    return writer;
-  }
-
-  public static StringBuffer appendCreateLink(StringBuffer buffer, String name) {
-    return buffer.append(makeCreateLink(name));
-  }
-
-  private static String makeCreateLink(String name) {
-    MessageFormat formatter = new MessageFormat(ResourceManager.getString("i18n.messages", "sniplink.create"),
-                                                ResourceManager.getLocale("i18n.messages"));
-
-    StringBuffer link = new StringBuffer();
-    link.append("<a href=\"");
-    link.append(getExecRoot());
-    link.append("/new?name=");
-    link.append(encode(name));
-    link.append("\">").append(Encoder.escape(name)).append("</a>");
-
-    return formatter.format(new Object[]{link.toString()});
-  }
-
-  public static String createLink(String name) {
-    StringBuffer buffer = new StringBuffer();
-    return appendLink(buffer, name, name).toString();
-  }
-
-  public static String createLink(String name, String view) {
-    StringBuffer buffer = new StringBuffer();
-    return appendLink(buffer, name, view).toString();
-  }
-
-  public static String createLink(String root, String name, String view) {
-    StringBuffer buffer = new StringBuffer();
-    return appendLinkWithRoot(buffer, root, encode(name), view).toString();
-  }
-
-  public static Writer appendLink(Writer writer, Snip snip) throws IOException {
-    return appendLink(writer, snip.getName());
-  }
-
-  public static StringBuffer appendLink(StringBuffer buffer, Snip snip) {
-    return appendLink(buffer, snip.getName());
-  }
-
-  public static Writer appendLink(Writer writer, String name) throws IOException {
-    StringBuffer buffer = new StringBuffer();
-    appendLink(buffer, name, name);
-    writer.write(buffer.toString());
-    return writer;
-  }
-
-  public static StringBuffer appendLink(StringBuffer buffer, String name) {
-    return appendLink(buffer, name, name);
-  }
-
-  public static Writer appendLink(Writer writer, String name, String view) throws IOException {
-    return appendLinkWithRoot(writer, getSpaceRoot(), encode(name), view);
-  }
-
-  public static StringBuffer appendLink(StringBuffer buffer, String name, String view, String target) {
-    return appendLinkWithRoot(buffer, getSpaceRoot(), encode(name) + "#" + target, view);
-  }
-
-  public static StringBuffer appendLink(StringBuffer buffer, String name, String view) {
-    return appendLinkWithRoot(buffer, getSpaceRoot(), encode(name), view);
-  }
-
-  public static Writer appendLinkWithRoot(Writer writer, String root, String name, String view) throws IOException {
-    writer.write("<a href=\"");
-    writer.write(root);
-    writer.write("/");
-    writer.write(name);
-    writer.write("\">");
-    view = formatter.format(view);
-    writer.write(Encoder.escape(view));
-    writer.write("</a>");
-    return writer;
-  }
-
-  /**
-   * Create a link with a root and a special view. The name will not be url encoded!
-   */
-  public static StringBuffer appendLinkWithRoot(StringBuffer buffer, String root, String name, String view) {
-    buffer.append("<a href=\"");
-    buffer.append(root);
-    buffer.append("/");
-    buffer.append(name);
-    buffer.append("\">");
-    view = formatter.format(view);
-    buffer.append(Encoder.escape(view));
-    buffer.append("</a>");
-    return buffer;
-  }
-
-//  private static String absoluteLink(String path) {
-//    Configuration config = Application.get().getConfiguration();
-//    String contextPath = config.getPath();
-//    String prefix = config.getPrefix();
-//    return (contextPath != null ? contextPath : "")  +
-//      (prefix != null && !"/".equals(prefix) ? prefix + "/" : "") + path;
-//  }
-
-  public static String getImageRoot() {
-    return "theme/images";
-  }
-
-  public static String getSpaceRoot() {
-    return "space";
-  }
-
-  public static String getExecRoot() {
-    return "exec";
-  }
-
-  public static String getCommentsRoot() {
-    return "comments";
-  }
-
-  private static List extensions = Arrays.asList(new String[]{"png", "jpg", "jpeg", "gif"});
-
-  public static Writer appendImage(Writer writer, String name, String alt) throws IOException {
-    return appendImageWithRoot(writer, getImageRoot(), name, alt, "png", null);
-  }
-
-  public static Writer appendImage(Writer writer, String name, String alt, String ext) throws IOException {
-    return appendImageWithRoot(writer, getImageRoot(), name, alt, ext, null);
-  }
-
-  public static Writer appendImage(Writer writer, Snip snip, String name, String alt, String ext, String position) throws IOException {
-    return appendImageWithRoot(writer, getSpaceRoot()+"/"+snip.getNameEncoded(), name, alt, ext, position);
-  }
-
-  /**
-   * Append and image tag to a string buffer. Additionally takes an alternative text to display
-   * if the browser cannot display the image.
-   * @param writer the writer to append to
-   * @param root the root path for images
-   * @param name the image name
-   * @param alt an alternative text
-   * @return the string buffer
-   */
-  public static Writer appendImageWithRoot(Writer writer, String root, String name,
-                                           String alt, String ext, String position)
-      throws IOException {
-    // extract extension or leave as is, default is to append .png
-    int dotIndex = name.lastIndexOf('.');
-    if (dotIndex != -1) {
-      String imageExt = name.substring(dotIndex + 1);
-      if (extensions.contains(imageExt.toLowerCase())) {
-        ext = imageExt;
-        name = name.substring(0, dotIndex);
-      }
-    }
-    if (null == ext) {
-      ext = "png";
-    }
-
-    writer.write("<img src=\"");
-    writer.write(root);
-    writer.write("/");
-    writer.write(name);
-    writer.write(".");
-    writer.write(ext);
-    writer.write("\"");
-    if (alt != null) {
-      writer.write(" alt=\"");
-      writer.write(alt);
-      writer.write("\"");
-    } else {
-      writer.write(" alt=\"");
-      writer.write(name);
-      writer.write("\"");
-    }
-    if (position != null) {
-      writer.write(" class=\"");
-      writer.write(position);
-      writer.write("\"");
-    }
-    writer.write(" border=\"0\"/>");
-    return writer;
-  }
-
-  // TODO 1.4 buffer.append(URLEncoder.encode(key, "iso-8859-1"));
-  public static String encode(String s) {
-    try {
-      Configuration config = Application.get().getConfiguration();
-      String encodedSpace = config.getEncodedSpace();
-      if(null != encodedSpace && encodedSpace.length() > 0) {
-        return URLEncoderDecoder.encode(s, config.getEncoding()).replace(' ', encodedSpace.charAt(0));
-      } else {
-        return URLEncoderDecoder.encode(s, config.getEncoding());
-      }
-    } catch (UnsupportedEncodingException e) {
-      Logger.log(Logger.FATAL, "unsupported encoding: " + e);
-      return s;
-    }
-  }
-
-  public static String decode(String s) {
-    try {
-      Configuration config = Application.get().getConfiguration();
-      String encodedSpace = config.getEncodedSpace();
-      if (null != encodedSpace && encodedSpace.length() > 0) {
-        s = s.replace(encodedSpace.charAt(0), ' ');
-      }
-      return URLEncoderDecoder.decode(s, config.getEncoding());
-    } catch (UnsupportedEncodingException e) {
-      Logger.log(Logger.FATAL, "unsupported encoding: " + e);
-      return s;
-    }
-  }
-
-  public static String cutLength(String url, int len) {
-    if (url != null && len > 3 && url.length() > len) {
-      return url.substring(0, len - 3) + "...";
-    }
-    return url;
-  }
-
-}
blob - 3d1c29b1e91d59e2c115febd87c4b1d69a415375 (mode 644)
blob + /dev/null
--- src/org/snipsnap/snip/SnipSpace.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*                                  n
- * This file is part of "SnipSnap Wiki/Weblog".
- *
- * Copyright (c) 2002 Stephan J. Schmidt, Matthias L. Jugel
- * All Rights Reserved.
- *
- * Please visit http://snipsnap.org/ for updates and contact.
- *
- * --LICENSE NOTICE--
- * 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- * --LICENSE NOTICE--
- */
-package org.snipsnap.snip;
-
-import org.apache.lucene.search.Hits;
-
-import java.sql.Timestamp;
-import java.util.List;
-
-/**
- * SnipSpace interface handles all the operations with snips like
- * loading, storing, searching et.c
- *
- * @author Stephan J. Schmidt
- * @version $Id$
- */
-
-public interface SnipSpace  {
-  public String getETag();
-
-  // A snip is changed by the user (created, stored)
-  public void changed(Snip snip);
-
-  public void init();
-
-  public void setETag();
-
-  public int getSnipCount();
-
-  public List getChanged();
-
-  public List getChanged(int count);
-
-  public List getAll();
-
-  public List getSince(Timestamp date);
-
-  public List getByDate(String nameSpace, String start, String end);
-
-  /**
-   * A list of Snips, ordered by "hotness", currently
-   * viewcount.
-   *
-   * @param count number of snips in the result
-   * @return List of snips, ordered by hotness
-   */
-  public List getHot(int count);
-
-  public List getComments(Snip snip);
-
-  public List getByUser(String login);
-
-  public List getChildren(Snip snip);
-
-  public List getChildrenDateOrder(Snip snip, int count);
-
-  public List getChildrenModifiedOrder(Snip snip, int count);
-
-  public void reIndex();
-
-  public Hits search(String queryString);
-
-  public Blog getBlog();
-
-  public Blog getBlog(String name);
-
-  public boolean exists(String name);
-
-  public Snip[] match(String pattern);
-
-  public Snip[] match(String start, String end);
-
-  public Snip load(String name);
-
-  public void systemStore(List snips);
-
-  public void store(Snip snip);
-
-  /**
-   * Method with with wich the system can store snips.
-   * This methode does not change the mTime, the mUser,
-   * reindex the snip or add the snip to the modified list
-   *
-   * @param snip The snip to store
-   */
-  public void systemStore(Snip snip);
-
-  /**
-   * Delays the storage of a snip for some time. Some information
-   * in a snip are changeg every view. To not store a snip every
-   * time it is viewed, delay the store and wait until some changes
-   * are cummulated. Should only be used, when the loss of the
-   * changes is tolerable.
-   *
-   * @param snip Snip to delay for storage
-   */
-  public void delayedStore(Snip snip);
-
-  /**
-   * Create a new snip with the specified content.
-   * @param name the name of the new snip
-   * @param content initial content
-   * @return the new copied snip
-   */
-  public Snip create(String name, String content);
-
-  public void remove(Snip snip);
-}
\ No newline at end of file
blob - efe69d5e1e546054f2cfbce60d031980557ac747 (mode 644)
blob + /dev/null
--- src/org/snipsnap/snip/SnipSpaceFactory.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * This file is part of "SnipSnap Wiki/Weblog".
- *
- * Copyright (c) 2002 Stephan J. Schmidt, Matthias L. Jugel
- * All Rights Reserved.
- *
- * Please visit http://snipsnap.org/ for updates and contact.
- *
- * --LICENSE NOTICE--
- * 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- * --LICENSE NOTICE--
- */
-
-package org.snipsnap.snip;
-
-import org.snipsnap.container.Components;
-
-
-/**
- * SnipSpaceFactory returns SnipSpace instances
- *
- * @author Stephan J. Schmidt
- * @version $Id$
- */
-
-public class SnipSpaceFactory {
-  public static synchronized SnipSpace getInstance() {
-    return (SnipSpace) Components.getComponent(SnipSpace.class);
-  }
-
-  public static synchronized void removeInstance() {
-  }
-}
blob - 72942454d293415cb7e04c9bde1bf6e632dea8b0 (mode 644)
blob + /dev/null
--- src/org/snipsnap/snip/label/Label.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * This file is part of "SnipSnap Wiki/Weblog".
- *
- * Copyright (c) 2002 Stephan J. Schmidt, Matthias L. Jugel
- * All Rights Reserved.
- *
- * Please visit http://snipsnap.org/ for updates and contact.
- *
- * --LICENSE NOTICE--
- * 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- * --LICENSE NOTICE--
- */
-
-package org.snipsnap.snip.label;
-
-import org.snipsnap.snip.Snip;
-import org.snipsnap.serialization.LabelContext;
-
-import java.util.Map;
-
-/**
- * Label is attached to Snips
- * @author Stephan J. Schmidt
- * @version $Id$
- */
-public interface Label extends Indexable, LifeCycle {
-  // public String serialize();
-
-  // public void deserialize(String label);
-
-  public String getListProxy();
-
-  public String getInputProxy();
-
-  public void handleInput(Map input);
-
-  public String getType();
-
-  public String getName();
-
-  public String getValue();
-
-  public void setName(String name);
-
-  public void setValue(String value);
-
-  public void setSnip(Snip snip);
-
-  public Snip getSnip();
-
-  public LabelContext getContext();
-}
blob - 61e0716573246c460b3b511054057fb8937f088f (mode 644)
blob + /dev/null
--- src/org/snipsnap/snip/label/Labels.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * This file is part of "SnipSnap Wiki/Weblog".
- *
- * Copyright (c) 2002 Stephan J. Schmidt, Matthias L. Jugel
- * All Rights Reserved.
- *
- * Please visit http://snipsnap.org/ for updates and contact.
- *
- * --LICENSE NOTICE--
- * 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- * --LICENSE NOTICE--
- */
-
-package org.snipsnap.snip.label;
-
-import org.snipsnap.util.StringUtil;
-import org.snipsnap.snip.Snip;
-import org.snipsnap.container.Components;
-import org.snipsnap.app.Application;
-
-import java.util.*;
-
-/**
- * Stores Label information for a snip
- *
- * @author stephan
- * @version $Id$
- */
-
-public class Labels {
-  private Map labels;
-  private String cache;
-
-  public Labels() {
-    this.labels = new HashMap();
-  }
-
-  public Labels(Snip snip, String labelString) {
-    cache = labelString;
-    deserialize(snip, labelString);
-  }
-
-  public void addLabel(Label label) {
-    // TODO: check if label with same name exists
-    // additional parameter 'overwrite' or exception or return value?
-    // (decision should to be made by user)
-    cache = null;
-    Map map = (Map) this.labels.get(label.getName());
-    if (map == null) {
-      map = new HashMap();
-      this.labels.put(label.getName(), map);
-    }
-    map.put(label.getValue(), label);
-  }
-
-  public void addLabel(String name, String value) {
-    // TODO: check if label with same name exists
-    // additional parameter 'overwrite' or exception or return value?
-    // (decision should to be made by user)
-    cache = null;
-    Label label = createDefaultLabel(name, value);
-    addLabel(label);
-  }
-
-  public Label getLabel(String name) {
-    Map map = (Map) this.labels.get(name);
-    if (map == null) return null;
-    Iterator it = map.values().iterator();
-    return it.hasNext() ? (Label) it.next() : null;
-  }
-
-  public Label getLabel(String name, String value) {
-    Map map = (Map) this.labels.get(name);
-    if (map == null) return null;
-    return (Label) map.get(value);
-  }
-
-  public Collection getAll() {
-    Collection result = new ArrayList();
-
-    Iterator iterator = this.labels.values().iterator();
-    while (iterator.hasNext()) {
-      Map map = (Map) iterator.next();
-      result.addAll(map.values());
-    }
-    return result;
-  }
-
-  public Collection getLabels(String type) {
-    ArrayList result = new ArrayList();
-    if (null == type) {
-      return result;
-    }
-
-    Iterator iterator = this.labels.values().iterator();
-    while (iterator.hasNext()) {
-      Map map = (Map) iterator.next();
-      Iterator it = map.values().iterator();
-      while (it.hasNext()) {
-        Label label = (Label) it.next();
-        if (null != label && type.equals(label.getType())) {
-          result.add(label);
-        }
-      }
-    }
-    return result;
-  }
-
-  public void removeLabel(String name, String value) {
-    cache = null;
-    Map map = (Map) labels.get(name);
-    if (map != null) {
-      Label label = (Label) map.get(value);
-      label.remove();
-      map.remove(value);
-    }
-  }
-
-  private Label createDefaultLabel(String name, String value) {
-    Label label = ((LabelManager) Components.getComponent(LabelManager.class)).getDefaultLabel();
-    label.setName(name);
-    label.setValue(value);
-    return label;
-  }
-
-  private Label createLabel(String type, String name, String value) {
-    // TODO: ? throw an exception (e.g. LabelTypeUnkownException ) ?
-    Label label = ((LabelManager) Components.getComponent(LabelManager.class)).getLabel(type);
-    if (label != null) {
-      label.setName(name);
-      label.setValue(value);
-    }
-    return label;
-  }
-
-  private void deserialize(Snip snip, String labelString) {
-    labels = new HashMap();
-    if (null == labelString || "".equals(labelString)) {
-      return;
-    }
-
-    StringTokenizer tokenizer = new StringTokenizer(labelString, "|");
-    while (tokenizer.hasMoreTokens()) {
-      String labelToken = tokenizer.nextToken();
-      String[] data = StringUtil.split(labelToken, ":");
-      //System.out.println("Data="+data);
-      if (data.length == 3) {
-        Label label = createLabel(data[0], data[1], data[2]);
-        label.setSnip(snip);
-        addLabel(label);
-      } else {
-        System.err.println("Labels: Broken Label: '" + labelToken + "' ignored");
-      }
-    }
-    return;
-  }
-
-  private String serialize() {
-    if (null == this.labels || this.labels.isEmpty()) {
-      return "";
-    }
-
-    StringBuffer linkBuffer = new StringBuffer();
-    Iterator iterator = this.labels.entrySet().iterator();
-    while (iterator.hasNext()) {
-      Map.Entry entry = (Map.Entry) iterator.next();
-      String name = (String) entry.getKey();
-      Map map = (Map) entry.getValue();
-      Iterator it = map.values().iterator();
-      while (it.hasNext()) {
-        Label label = (Label) it.next();
-        String type = label.getType();
-        String value = label.getValue();
-        linkBuffer.append(type);
-        linkBuffer.append(":");
-        linkBuffer.append(name);
-        linkBuffer.append(":");
-        linkBuffer.append(value);
-
-        linkBuffer.append("|");
-      }
-    }
-    //System.out.println("serialize = "+linkBuffer.toString());
-    // remove last '|'
-    if (linkBuffer.length() > 0) {
-      linkBuffer.setLength(linkBuffer.length() - 1);
-    }
-    return linkBuffer.toString();
-  }
-
-  public String toString() {
-    // always force serialization to ensure changed labels are reflected
-    return (cache = serialize());
-  }
-}
blob - 6f9e5fdf8abb8d818176423c82fe9395b87c2101 (mode 644)
blob + /dev/null
--- src/org/snipsnap/user/User.java
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * This file is part of "SnipSnap Wiki/Weblog".
- *
- * Copyright (c) 2002 Stephan J. Schmidt, Matthias L. Jugel
- * All Rights Reserved.
- *
- * Please visit http://snipsnap.org/ for updates and contact.
- *
- * --LICENSE NOTICE--
- * 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- * --LICENSE NOTICE--
- */
-package org.snipsnap.user;
-
-import org.snipsnap.app.Application;
-import org.snipsnap.config.Configuration;
-import org.snipsnap.snip.SnipLink;
-import org.snipsnap.render.macro.list.Linkable;
-
-import java.sql.Timestamp;
-import java.util.Iterator;
-import java.util.Set;
-import java.util.HashSet;
-
-import gabriel.Subject;
-import gabriel.Principal;
-
-/**
- * User class.
- *
- * @author Stephan J. Schmidt
- * @version $Id$
- */
-public class User implements Linkable {
-  private Subject subject;
-
-  private String applicationOid;
-  private String login;
-  private String passwd;
-  private String email;
-  private String status;
-  private Roles roles;
-  private Principal user;
-
-  // @TODO: composite object
-  private Timestamp lastLogin, lastAccess, lastLogout;
-  // @TODO: -> Modified composite object
-  private Timestamp cTime, mTime;
-
-  private boolean guest = false;
-  private boolean nonUser = false;
-
-  public User() {
-    this("", "", "");
-  }
-
-  public User(String login, String passwd, String email) {
-    this.login = login;
-    setPasswd(passwd);
-    setEmail(email);
-    user = new Principal("User");
-  }
-
-  public Subject getSubject() {
-    if (null == subject) {
-      subject = new Subject(this.login);
-      Set principals = new HashSet();
-      // SECURITY PROBLEM, what if user CALLS himself "EDITOR"?
-      // So add "user::"
-      // Also probably add a "Developer" role for debugging
-      principals.add(new Principal("user::"+this.login));
-      Iterator iterator = getRoles().iterator();
-      while (iterator.hasNext()) {
-        String role = (String) iterator.next();
-        principals.add(new Principal(role));
-      }
-      if (! isGuest()) {
-        principals.add(user);
-      }
-      subject.setPrincipals(principals);
-    }
-    return subject;
-  }
-
-  public void setApplication(String applicationOid) {
-    this.applicationOid = applicationOid;
-  }
-
-  public String getApplication() {
-    return applicationOid;
-  }
-
-
-  public Timestamp getCTime() {
-    return cTime;
-  }
-
-  public void setCTime(Timestamp cTime) {
-    this.cTime = cTime;
-  }
-
-  public Timestamp getMTime() {
-    return mTime;
-  }
-
-  public void setMTime(Timestamp mTime) {
-    this.mTime = mTime;
-  }
-
-  /**
-   * LastAccess sets the time when the user
-   * last accessed SnipSnap. This is used
-   * to find snips since his last access.
-   */
-  public void lastAccess() {
-    this.lastAccess = new Timestamp(new java.util.Date().getTime());
-    //Logger.debug(this.login+" hashcode: "+((Object) this).hashCode());
-    //Logger.debug("Set lastAccess() "+this.login+" "+lastAccess);
-  }
-
-  public Timestamp getLastLogout() {
-    return lastLogout;
-  }
-
-  public void setLastLogout(Timestamp lastLogout) {
-    //Logger.debug(this.login+" hashcode: "+((Object) this).hashCode());
-    //Logger.debug("Set LastLogout() "+this.login+" "+lastLogout+" old: "+this.lastLogout);
-    this.lastLogout = lastLogout;
-  }
-
-  public Timestamp getLastAccess() {
-    return this.lastAccess;
-  }
-
-  public void setLastAccess(Timestamp lastAccess) {
-    this.lastAccess = lastAccess;
-  }
-
-  public Timestamp getLastLogin() {
-    return lastLogin;
-  }
-
-  public void lastLogin() {
-    setLastLogin(new Timestamp(new java.util.Date().getTime()));
-  }
-
-  public void setLastLogin(Timestamp lastLogin) {
-    this.lastLogin = lastLogin;
-  }
-
-  public void setStatus(String status) {
-    this.status = status;
-    return;
-  }
-
-  public String getStatus() {
-    if (null == status) {
-      status = "not set";
-    }
-    return status;
-  }
-
-  public void setEmail(String email) {
-    this.email = email;
-  }
-
-  public String getEmail() {
-    return email;
-  }
-
-  // Set passwd of user. Takes unecrypted
-  // passwd and then sets an encrypted version
-  public void setPasswd(String passwd) {
-    if (passwd != null && passwd.length() > 30) {
-      this.passwd = passwd;
-    } else {
-      this.passwd = Digest.getDigest(passwd);
-    }
-  }
-
-  public String getPasswd() {
-    return passwd;
-  }
-
-  /**
-   * WARNING: DO NOT USE THIS METHOD UNLESS YOU KNOW WHAT YOU DO.
-   *
-   * @param login
-   */
-  public void setLogin(String login) {
-    this.login = login;
-  }
-
-  public String getLogin() {
-    return login;
-  }
-
-  public void setRoles(Roles roles) {
-    this.roles = roles;
-    return;
-  }
-
-  public Roles getRoles() {
-    if (null == roles) {
-      roles = new Roles();
-    }
-    return roles;
-  }
-
-  public boolean isAdmin() {
-    Application app = Application.get();
-    Configuration config = app.getConfiguration();
-    return (config.getAdminLogin() != null && config.getAdminLogin().equals(login))
-        || getRoles().contains(Roles.ADMIN);
-  }
-
-  public void setGuest(boolean guest) {
-    this.guest = guest;
-  }
-
-  public boolean isGuest() {
-    return guest;
-  }
-
-  public void setNonUser(boolean nonUser) {
-    this.nonUser = nonUser;
-  }
-
-  public boolean isNonUser() {
-    return nonUser;
-  }
-
-  public int hashCode() {
-    return getLogin().hashCode();
-  }
-
-  public boolean equals(Object obj) {
-    if (obj instanceof User && obj != null && this.getLogin() != null) {
-      return this.getLogin().equals(((User) obj).getLogin());
-    }
-    return false;
-  }
-
-  public String toString() {
-    return "User[" + login + "," + (passwd != null ? "pass set" : "no pass") + "," + email + "," + status + "," + roles + "]";
-  }
-
-  public String getLink() {
-    if (isNonUser()) {
-      StringBuffer tmp = new StringBuffer();
-      tmp.append("<a href=\"");
-      tmp.append(getEmail());
-      tmp.append("\">");
-      tmp.append(getLogin());
-      tmp.append("</a>");
-      return tmp.toString();
-    } else if (isGuest()) {
-      return "Guest";
-    } else {
-      return SnipLink.createLink(getLogin());
-    }
-  }
-
-}
\ No newline at end of file
blob - /dev/null
blob + 157f755f1bc6f9b8ec4c1da4a5be751e902a9938 (mode 644)
--- /dev/null
+++ src/snipsnap/api/snip/Snip.java
@@ -0,0 +1,216 @@
+/*
+ * This file is part of "SnipSnap Wiki/Weblog".
+ *
+ * Copyright (c) 2002 Stephan J. Schmidt, Matthias L. Jugel
+ * All Rights Reserved.
+ *
+ * Please visit http://snipsnap.org/ for updates and contact.
+ *
+ * --LICENSE NOTICE--
+ * 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * --LICENSE NOTICE--
+ */
+
+package snipsnap.api.snip;
+
+import org.snipsnap.serialization.Appendable;
+import org.snipsnap.snip.attachment.Attachments;
+import snipsnap.api.label.Labels;
+import org.snipsnap.snip.*;
+import org.snipsnap.user.Permissions;
+import snipsnap.api.user.User;
+import org.snipsnap.render.macro.list.Linkable;
+import org.snipsnap.render.macro.list.Nameable;
+
+import javax.servlet.http.HttpServletRequest;
+import java.sql.Timestamp;
+import java.util.List;
+import java.io.IOException;
+
+/**
+ * Interface for snips
+ *
+ * @author  Stephan J. Schmidt
+ * @version $Id: Snip.java 1706 2004-07-08 08:53:20Z stephan $
+ */
+
+public interface Snip extends Linkable, gabriel.components.context.Ownable, Nameable, Appendable {
+  public void handle(HttpServletRequest request);
+
+  // HACK: looks like java beans framework does not find Nameable
+  public String getName();
+
+  public Access getAccess();
+
+  public Modified getModified();
+
+  /**
+   * Returns true, when the snip is a weblog.
+   * Currently only test against 'start'.
+   * Should be extendet to test a "weblog"-label
+   *
+   * @return true, if the snip is a weblog
+   */
+  public boolean isWeblog();
+
+  /**
+   * Conveniance function for JSP
+   *
+   * @return true, if snip is not a weblog
+   */
+  public boolean isNotWeblog();
+
+  public int getVersion();
+
+  public void setVersion(int version);
+
+  public void addPermission(String permission, String role);
+
+  public void setPermissions(Permissions permissions);
+
+  public Permissions getPermissions();
+
+  public void setApplication(String applicationOid);
+
+  public String getApplication();
+
+  public String getOUser();
+
+  public void setOUser(User oUser);
+
+  public void setOUser(String oUser);
+
+  public Attachments getAttachments();
+
+  public void setAttachments(Attachments attachments);
+
+  public Labels getLabels();
+
+  public void setLabels(Labels labels);
+
+  public Links getBackLinks();
+
+  public Links getSnipLinks();
+
+  public void setBackLinks(Links backLinks);
+
+  public void setSnipLinks(Links snipLinks);
+
+  public int getViewCount();
+
+  public void setViewCount(int count);
+
+  public int incViewCount();
+
+  public Timestamp getCTime();
+
+  public void setCTime(Timestamp cTime);
+
+  public Timestamp getMTime();
+
+  public void setMTime(Timestamp mTime);
+
+  public String getCUser();
+
+  public void setCUser(User cUser);
+
+  public void setCUser(String cUser);
+
+  public String getMUser();
+
+  public void setMUser(User mUser);
+
+  public void setMUser(String mUser);
+
+  public List getChildren();
+
+  public void setCommentedSnip(Snip comment);
+
+  public Snip getCommentedSnip();
+
+  public boolean isComment();
+
+  public Comments getComments();
+
+  public List getChildrenDateOrder();
+
+  public List getChildrenModifiedOrder();
+
+  /**
+   * Add a child snip. Sets the parent of
+   * the child to this snip and <b>stores</b> the
+   * child because of the new parent.
+   *
+   * @param snip Snip to add as child
+   */
+  public void addSnip(Snip snip);
+
+  /**
+   * Removes child snip from this nsip
+   *
+   * @param snip Child to remove
+   */
+  public void removeSnip(Snip snip);
+
+  public void setParentName(String name);
+
+  public String getParentName();
+
+  public void setCommentedName(String name);
+
+  public String getCommentedName();
+
+  public Snip getParent();
+
+  public void setDirectParent(Snip parentSnip);
+
+  public void setParent(Snip parentSnip);
+
+  /**
+   * Return a short version of the name.
+   * Useful for vertical snip listings, where
+   * the snips should not be to long.
+   * End of snip name will be replaced with "..."
+   *
+   * @return Short name of snip
+   */
+  public String getShortName();
+
+  /**
+   * Return an encoded version of the name,
+   * especially spaces replaced with "+"
+   *
+   * @return encoded name of snip
+   */
+  public String getNameEncoded();
+
+  public void setName(String name);
+
+  public String getContent();
+
+  public void setContent(String content);
+
+  public String getAttachmentString();
+
+  public String toXML();
+
+  public String getXMLContent();
+
+  public SnipPath getPath() throws IOException;
+
+  public String getTitle();
+
+  public Snip copy(String newName);
+}
blob - /dev/null
blob + 32a34e989faeb0cffaf41b9fcef8e67b7b2425b2 (mode 644)
--- /dev/null
+++ src/snipsnap/api/snip/SnipLink.java
@@ -0,0 +1,313 @@
+/*
+ * This file is part of "SnipSnap Wiki/Weblog".
+ *
+ * Copyright (c) 2002 Stephan J. Schmidt, Matthias L. Jugel
+ * All Rights Reserved.
+ *
+ * Please visit http://snipsnap.org/ for updates and contact.
+ *
+ * --LICENSE NOTICE--
+ * 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * --LICENSE NOTICE--
+ */
+
+package snipsnap.api.snip;
+
+import org.radeox.util.logging.Logger;
+import org.radeox.util.Encoder;
+import org.radeox.util.i18n.ResourceManager;
+import snipsnap.api.app.Application;
+import snipsnap.api.config.Configuration;
+import org.snipsnap.util.URLEncoderDecoder;
+import org.snipsnap.snip.name.NameFormatter;
+import org.snipsnap.snip.name.PathRemoveFormatter;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.util.Arrays;
+import java.util.List;
+import java.text.MessageFormat;
+
+import snipsnap.api.snip.*;
+import snipsnap.api.snip.Snip;
+
+/**
+ *  Generates links for snips
+ *
+ * @author stephan
+ * @version $Id: SnipLink.java 1606 2004-05-17 10:56:18Z leo $
+ */
+
+public class SnipLink {
+
+  public static NameFormatter formatter = new PathRemoveFormatter();
+
+  /**
+   * Append a URL String that contains a base a name-to-be-encoded and an optional anchor target.
+   * @param writer the writer to append to
+   * @param base the url base
+   * @param name the name (to be encoded)
+   * @param target the anchor target
+   */
+  public static Writer appendUrlWithBase(Writer writer, String base, String name, String target)
+    throws IOException {
+    writer.write(base);
+    writer.write("/");
+    writer.write(encode(name));
+    if(target != null) {
+      writer.write("#");
+      writer.write(target);
+    }
+    return writer;
+  }
+
+  public static Writer appendUrl(Writer writer, String name, String target) throws IOException {
+    return appendUrlWithBase(writer, getSpaceRoot(), name, target);
+  }
+
+  public static Writer appendUrl(Writer writer, String name) throws IOException {
+    return appendUrlWithBase(writer, getSpaceRoot(), name, null);
+  }
+
+  public static Writer appendCommentsUrl(Writer writer, String name, String target) throws IOException {
+    return appendUrlWithBase(writer, getCommentsRoot(), name, target);
+  }
+
+  /**
+   * Append a create link for the specified name.
+   */
+  public static Writer appendCreateLink(Writer writer, String name) throws IOException {
+    writer.write(makeCreateLink(name));
+    return writer;
+  }
+
+  public static StringBuffer appendCreateLink(StringBuffer buffer, String name) {
+    return buffer.append(makeCreateLink(name));
+  }
+
+  private static String makeCreateLink(String name) {
+    MessageFormat formatter = new MessageFormat(ResourceManager.getString("i18n.messages", "sniplink.create"),
+                                                ResourceManager.getLocale("i18n.messages"));
+
+    StringBuffer link = new StringBuffer();
+    link.append("<a href=\"");
+    link.append(getExecRoot());
+    link.append("/new?name=");
+    link.append(encode(name));
+    link.append("\">").append(Encoder.escape(name)).append("</a>");
+
+    return formatter.format(new Object[]{link.toString()});
+  }
+
+  public static String createLink(String name) {
+    StringBuffer buffer = new StringBuffer();
+    return appendLink(buffer, name, name).toString();
+  }
+
+  public static String createLink(String name, String view) {
+    StringBuffer buffer = new StringBuffer();
+    return appendLink(buffer, name, view).toString();
+  }
+
+  public static String createLink(String root, String name, String view) {
+    StringBuffer buffer = new StringBuffer();
+    return appendLinkWithRoot(buffer, root, encode(name), view).toString();
+  }
+
+  public static Writer appendLink(Writer writer, Snip snip) throws IOException {
+    return appendLink(writer, snip.getName());
+  }
+
+  public static StringBuffer appendLink(StringBuffer buffer, snipsnap.api.snip.Snip snip) {
+    return appendLink(buffer, snip.getName());
+  }
+
+  public static Writer appendLink(Writer writer, String name) throws IOException {
+    StringBuffer buffer = new StringBuffer();
+    appendLink(buffer, name, name);
+    writer.write(buffer.toString());
+    return writer;
+  }
+
+  public static StringBuffer appendLink(StringBuffer buffer, String name) {
+    return appendLink(buffer, name, name);
+  }
+
+  public static Writer appendLink(Writer writer, String name, String view) throws IOException {
+    return appendLinkWithRoot(writer, getSpaceRoot(), encode(name), view);
+  }
+
+  public static StringBuffer appendLink(StringBuffer buffer, String name, String view, String target) {
+    return appendLinkWithRoot(buffer, getSpaceRoot(), encode(name) + "#" + target, view);
+  }
+
+  public static StringBuffer appendLink(StringBuffer buffer, String name, String view) {
+    return appendLinkWithRoot(buffer, getSpaceRoot(), encode(name), view);
+  }
+
+  public static Writer appendLinkWithRoot(Writer writer, String root, String name, String view) throws IOException {
+    writer.write("<a href=\"");
+    writer.write(root);
+    writer.write("/");
+    writer.write(name);
+    writer.write("\">");
+    view = formatter.format(view);
+    writer.write(Encoder.escape(view));
+    writer.write("</a>");
+    return writer;
+  }
+
+  /**
+   * Create a link with a root and a special view. The name will not be url encoded!
+   */
+  public static StringBuffer appendLinkWithRoot(StringBuffer buffer, String root, String name, String view) {
+    buffer.append("<a href=\"");
+    buffer.append(root);
+    buffer.append("/");
+    buffer.append(name);
+    buffer.append("\">");
+    view = formatter.format(view);
+    buffer.append(Encoder.escape(view));
+    buffer.append("</a>");
+    return buffer;
+  }
+
+//  private static String absoluteLink(String path) {
+//    Configuration config = Application.get().getConfiguration();
+//    String contextPath = config.getPath();
+//    String prefix = config.getPrefix();
+//    return (contextPath != null ? contextPath : "")  +
+//      (prefix != null && !"/".equals(prefix) ? prefix + "/" : "") + path;
+//  }
+
+  public static String getImageRoot() {
+    return "theme/images";
+  }
+
+  public static String getSpaceRoot() {
+    return "space";
+  }
+
+  public static String getExecRoot() {
+    return "exec";
+  }
+
+  public static String getCommentsRoot() {
+    return "comments";
+  }
+
+  private static List extensions = Arrays.asList(new String[]{"png", "jpg", "jpeg", "gif"});
+
+  public static Writer appendImage(Writer writer, String name, String alt) throws IOException {
+    return appendImageWithRoot(writer, getImageRoot(), name, alt, "png", null);
+  }
+
+  public static Writer appendImage(Writer writer, String name, String alt, String ext) throws IOException {
+    return appendImageWithRoot(writer, getImageRoot(), name, alt, ext, null);
+  }
+
+  public static Writer appendImage(Writer writer, Snip snip, String name, String alt, String ext, String position) throws IOException {
+    return appendImageWithRoot(writer, getSpaceRoot()+"/"+snip.getNameEncoded(), name, alt, ext, position);
+  }
+
+  /**
+   * Append and image tag to a string buffer. Additionally takes an alternative text to display
+   * if the browser cannot display the image.
+   * @param writer the writer to append to
+   * @param root the root path for images
+   * @param name the image name
+   * @param alt an alternative text
+   * @return the string buffer
+   */
+  public static Writer appendImageWithRoot(Writer writer, String root, String name,
+                                           String alt, String ext, String position)
+      throws IOException {
+    // extract extension or leave as is, default is to append .png
+    int dotIndex = name.lastIndexOf('.');
+    if (dotIndex != -1) {
+      String imageExt = name.substring(dotIndex + 1);
+      if (extensions.contains(imageExt.toLowerCase())) {
+        ext = imageExt;
+        name = name.substring(0, dotIndex);
+      }
+    }
+    if (null == ext) {
+      ext = "png";
+    }
+
+    writer.write("<img src=\"");
+    writer.write(root);
+    writer.write("/");
+    writer.write(name);
+    writer.write(".");
+    writer.write(ext);
+    writer.write("\"");
+    if (alt != null) {
+      writer.write(" alt=\"");
+      writer.write(alt);
+      writer.write("\"");
+    } else {
+      writer.write(" alt=\"");
+      writer.write(name);
+      writer.write("\"");
+    }
+    if (position != null) {
+      writer.write(" class=\"");
+      writer.write(position);
+      writer.write("\"");
+    }
+    writer.write(" border=\"0\"/>");
+    return writer;
+  }
+
+  // TODO 1.4 buffer.append(URLEncoder.encode(key, "iso-8859-1"));
+  public static String encode(String s) {
+    try {
+      snipsnap.api.config.Configuration config = Application.get().getConfiguration();
+      String encodedSpace = config.getEncodedSpace();
+      if(null != encodedSpace && encodedSpace.length() > 0) {
+        return URLEncoderDecoder.encode(s, config.getEncoding()).replace(' ', encodedSpace.charAt(0));
+      } else {
+        return URLEncoderDecoder.encode(s, config.getEncoding());
+      }
+    } catch (UnsupportedEncodingException e) {
+      Logger.log(Logger.FATAL, "unsupported encoding: " + e);
+      return s;
+    }
+  }
+
+  public static String decode(String s) {
+    try {
+      snipsnap.api.config.Configuration config = Application.get().getConfiguration();
+      String encodedSpace = config.getEncodedSpace();
+      if (null != encodedSpace && encodedSpace.length() > 0) {
+        s = s.replace(encodedSpace.charAt(0), ' ');
+      }
+      return URLEncoderDecoder.decode(s, config.getEncoding());
+    } catch (UnsupportedEncodingException e) {
+      Logger.log(Logger.FATAL, "unsupported encoding: " + e);
+      return s;
+    }
+  }
+
+  public static String cutLength(String url, int len) {
+    if (url != null && len > 3 && url.length() > len) {
+      return url.substring(0, len - 3) + "...";
+    }
+    return url;
+  }
+
+}
blob - /dev/null
blob + cd2e969d7e0f8a569341b90112ce7ed2ae66801e (mode 644)
--- /dev/null
+++ src/snipsnap/api/snip/SnipSpaceFactory.java
@@ -0,0 +1,47 @@
+/*
+ * This file is part of "SnipSnap Wiki/Weblog".
+ *
+ * Copyright (c) 2002 Stephan J. Schmidt, Matthias L. Jugel
+ * All Rights Reserved.
+ *
+ * Please visit http://snipsnap.org/ for updates and contact.
+ *
+ * --LICENSE NOTICE--
+ * 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * --LICENSE NOTICE--
+ */
+
+package snipsnap.api.snip;
+
+import org.snipsnap.container.Components;
+import snipsnap.api.snip.*;
+import snipsnap.api.snip.SnipSpace;
+
+
+/**
+ * SnipSpaceFactory returns SnipSpace instances
+ *
+ * @author Stephan J. Schmidt
+ * @version $Id: SnipSpaceFactory.java 915 2003-08-06 12:39:12Z stephan $
+ */
+
+public class SnipSpaceFactory {
+  public static synchronized snipsnap.api.snip.SnipSpace getInstance() {
+    return (SnipSpace) Components.getComponent(SnipSpace.class);
+  }
+
+  public static synchronized void removeInstance() {
+  }
+}
blob - /dev/null
blob + 5e1478213b6c470ea01516528577d15615c46058 (mode 644)
--- /dev/null
+++ src/snipsnap/api/app/Application.java
@@ -0,0 +1,231 @@
+/*
+ * This file is part of "SnipSnap Wiki/Weblog".
+ *
+ * Copyright (c) 2002 Stephan J. Schmidt, Matthias L. Jugel
+ * All Rights Reserved.
+ *
+ * Please visit http://snipsnap.org/ for updates and contact.
+ *
+ * --LICENSE NOTICE--
+ * 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * --LICENSE NOTICE--
+ */
+package snipsnap.api.app;
+
+import org.radeox.util.logging.Logger;
+import snipsnap.api.config.Configuration;
+import org.snipsnap.config.ConfigurationProxy;
+import org.snipsnap.container.Components;
+import org.snipsnap.user.AuthenticationService;
+import snipsnap.api.user.User;
+import org.snipsnap.user.UserManagerFactory;
+import org.snipsnap.util.ApplicationAwareMap;
+
+import javax.servlet.http.HttpSession;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * The application object contains information about current users and other
+ * session specific information.
+ * @author Stephan J. Schmidt
+ * @version $Id: Application.java 1704 2004-07-07 07:47:05Z stephan $
+ */
+public class Application {
+  public final static String OID = "_applicationOid";
+  public final static String URL = "_url";
+
+  private static ApplicationAwareMap currentUsers =
+    new ApplicationAwareMap(HashMap.class, HashMap.class);
+
+  private static ThreadLocal instance = new ThreadLocal() {
+    protected synchronized Object initialValue() {
+      return new Application();
+    }
+  };
+
+  // TODO make this an application-aware map to get old functionality
+  private Map objectStore = new HashMap();
+  private snipsnap.api.user.User user;
+  private Configuration config;
+  private List log = new ArrayList();
+  // TODO use private NotificationService notification;
+  private Map params;
+
+  public static Application get() {
+    Application app = (Application) instance.get();
+    if (null == app) {
+      app = new Application();
+      instance.set(app);
+    }
+    return app;
+  }
+
+  public static Application forceGet() {
+    instance.set(null);
+    return get();
+  }
+
+  public static void set(Application application) {
+    instance.set(application);
+  }
+
+  public void clearLog() {
+    log = new ArrayList();
+  }
+
+  public List getLog() {
+    return log;
+  }
+
+  public void log(String output) {
+    log.add(output);
+  }
+
+  public long start() {
+    return System.currentTimeMillis();
+  }
+
+  public void stop(long start, String output) {
+    Logger.log(Logger.PERF, output + " - " + (System.currentTimeMillis() - start));
+  }
+
+  public snipsnap.api.user.User getUser() {
+    return user;
+  }
+
+  public void setUser(User user) {
+    this.user = user;
+  }
+
+  public Map getParameters() {
+    return params;
+  }
+
+  public void setParameters(Map parameters) {
+    this.params = parameters;
+  }
+
+  public void setUser(snipsnap.api.user.User user, HttpSession session) {
+    if (this.user == user) {
+      return;
+    }
+
+    if (this.user != null) {
+      Application.removeCurrentUser(session);
+    }
+    setUser(user);
+    Application.addCurrentUser(user, session);
+    if(user.isGuest() || user.isNonUser()) {
+      session.setMaxInactiveInterval(120);
+    }
+    return;
+  }
+
+  public static synchronized void addCurrentUser(snipsnap.api.user.User user, HttpSession session) {
+//    Logger.debug("Binding user to session: "+user+": "+session);
+    currentUsers.getMap().put(session, user);
+  }
+
+  public static List getCurrentUsers() {
+    List users = new ArrayList();
+    Iterator iterator = currentUsers.getMap().values().iterator();
+    while (iterator.hasNext()) {
+      snipsnap.api.user.User user = (snipsnap.api.user.User) iterator.next();
+      if (!(user.isGuest() || user.isNonUser() || users.contains(user))) {
+        users.add(user);
+      }
+    }
+    return users;
+  }
+
+  public static List getCurrentNonUsers() {
+    List users = new ArrayList();
+    Iterator iterator = currentUsers.getMap().values().iterator();
+    while (iterator.hasNext()) {
+      snipsnap.api.user.User user = (User) iterator.next();
+      if (user.isNonUser() && !users.contains(user) && !"IGNORE".equals(user.getEmail())) {
+        users.add(user);
+      }
+    }
+    return users;
+  }
+
+  public static int getGuestCount() {
+    int count = 0;
+    Iterator iterator = currentUsers.getMap().values().iterator();
+    while (iterator.hasNext()) {
+      User user = (User) iterator.next();
+      if (user.isGuest() && !user.isNonUser()) {
+        count++;
+      }
+    }
+    return count;
+  }
+
+  public static synchronized void removeCurrentUser(HttpSession session) {
+    if (null == currentUsers || null == session) {
+      return;
+    }
+
+    String appOid = (String) Application.get().getObject(Application.OID);
+    Map currentUsersMap = null;
+    if (null != appOid) {
+      currentUsersMap = currentUsers.getMap(appOid);
+    } else {
+      currentUsersMap = currentUsers.findMap(session);
+    }
+
+    if (null != currentUsersMap && currentUsersMap.containsKey(session)) {
+      snipsnap.api.user.User user = (snipsnap.api.user.User) currentUsersMap.get(session);
+      AuthenticationService service = (AuthenticationService) Components.getComponent(AuthenticationService.class);
+
+      if (service.isAuthenticated(user)) {
+        Logger.debug("Removing authenticated user from session: " + user);
+        user.setLastLogout(user.getLastAccess());
+        // we ensure we remove the correct user by setting the OID from the user object
+        Application.get().storeObject(Application.OID, user.getApplication());
+        UserManagerFactory.getInstance().systemStore(user);
+      } else {
+        Logger.debug("Removing unauthenticated user from session: " + user);
+      }
+      currentUsersMap.remove(session);
+    } else {
+      Logger.warn("Unable to remove current user from session '" + session + "'");
+    }
+  }
+
+  public void storeObject(String key, Object value) {
+    objectStore.put(key, value);
+  }
+
+  public Object getObject(String key) {
+    return objectStore.get(key);
+  }
+
+  public void setConfiguration(Configuration config) {
+    this.config = config;
+  }
+
+  public Configuration getConfiguration() {
+    if (null == config) {
+      config = ConfigurationProxy.getInstance();
+    }
+    return config;
+  }
+}
blob - /dev/null
blob + 02b27616f1bf843ba86b613b9ba367f3894d13bf (mode 644)
--- /dev/null
+++ src/snipsnap/api/config/Configuration.java
@@ -0,0 +1,238 @@
+/*
+ * This file is part of "SnipSnap Wiki/Weblog".
+ *
+ * Copyright (c) 2002 Stephan J. Schmidt, Matthias L. Jugel
+ * All Rights Reserved.
+ *
+ * Please visit http://snipsnap.org/ for updates and contact.
+ *
+ * --LICENSE NOTICE--
+ * 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * --LICENSE NOTICE--
+ */
+package snipsnap.api.config;
+
+import org.snipsnap.config.Globals;
+
+import java.util.Locale;
+import java.util.Properties;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+import java.io.File;
+
+/**
+ * Interface template for easy usage of the configuration.
+ * @author Matthias L. Jugel
+ * @version $Id: Configuration.java.tmpl 1606 2004-05-17 10:56:18Z leo $
+ */
+public interface Configuration extends Globals {
+  public final static String SNIPSNAP_CONFIG = "SnipSnap/config";
+  public final static String SNIPSNAP_CONFIG_API = "SnipSnap/config/apidocs";
+  public final static String SNIPSNAP_CONFIG_WIKI = "SnipSnap/config/interwiki";
+  public final static String SNIPSNAP_CONFIG_PING = "SnipSnap/config/weblogsping";
+  public final static String SNIPSNAP_CONFIG_ASIN = "SnipSnap/config/asinservices";
+  public final static String SNIPSNAP_CONFIG_BOOK = "SnipSnap/config/bookservices";
+  public final static String SNIPSNAP_CONFIG_ROBOTS = "SnipSnap/config/robots";
+  public final static String SNIPSNAP_CONFIG_ROBOTS_TXT = "SnipSnap/config/robots.txt";
+  public final static String SNIPSNAP_THEMES = "SnipSnap/themes";
+
+  public String get(String name);
+  public String get(String name, String defaultValue);
+  public void set(String name, String value);
+
+  public void load(InputStream stream) throws IOException;
+  public void store(OutputStream stream) throws IOException;
+
+  // get all properties
+  public Properties getProperties();
+  public String getDefault(String name);
+  public File getFileStore(String applicationOid);
+
+  public File getFilePath(String applicationOid);
+  public File getUserPath(String applicationOid);
+
+  public File getFilePath();
+  public File getIndexPath();
+
+  // LOCALE
+  Locale getLocale();
+
+  // URL HANDLING
+  String getUrl();
+  String getUrl(String target);
+  String getSnipUrl(String snipName);
+
+  // PERMISSIONS
+  boolean allow(String action);
+  boolean deny(String action);
+
+  // TODO remove/replace
+  boolean getAllowRegister();
+
+  // GENERICS
+  boolean isConfigured();
+
+  // EASY ACCESS
+  
+  // automatically created interface/constants stub from
+  // /Users/stephan/src/snipsnap/trunk/src/org/snipsnap/config/defaults.conf
+  // generated on 4/6/05 7:40 PM
+  // constant/getter for 'app.admin.email'
+  public final static String APP_ADMIN_EMAIL = "app.admin.email";
+  public String getAdminEmail();
+  public String setAdminEmail(String value);
+  // constant/getter for 'app.admin.login'
+  public final static String APP_ADMIN_LOGIN = "app.admin.login";
+  public String getAdminLogin();
+  public String setAdminLogin(String value);
+  // constant/getter for 'app.admin.password'
+  public final static String APP_ADMIN_PASSWORD = "app.admin.password";
+  public String getAdminPassword();
+  public String setAdminPassword(String value);
+  // constant/getter for 'app.configured'
+  public final static String APP_CONFIGURED = "app.configured";
+  public String getConfigured();
+  public String setConfigured(String value);
+  // constant/getter for 'app.country'
+  public final static String APP_COUNTRY = "app.country";
+  public String getCountry();
+  public String setCountry(String value);
+  // constant/getter for 'app.encodedSpace'
+  public final static String APP_ENCODEDSPACE = "app.encodedSpace";
+  public String getEncodedSpace();
+  public String setEncodedSpace(String value);
+  // constant/getter for 'app.feature.referrer.show'
+  public final static String APP_FEATURE_REFERRER_SHOW = "app.feature.referrer.show";
+  public String getFeatureReferrerShow();
+  public String setFeatureReferrerShow(String value);
+  // constant/getter for 'app.feature.sniplinks.show'
+  public final static String APP_FEATURE_SNIPLINKS_SHOW = "app.feature.sniplinks.show";
+  public String getFeatureSniplinksShow();
+  public String setFeatureSniplinksShow(String value);
+  // constant/getter for 'app.geoCoordinates'
+  public final static String APP_GEOCOORDINATES = "app.geoCoordinates";
+  public String getGeoCoordinates();
+  public String setGeoCoordinates(String value);
+  // constant/getter for 'app.language'
+  public final static String APP_LANGUAGE = "app.language";
+  public String getLanguage();
+  public String setLanguage(String value);
+  // constant/getter for 'app.logo'
+  public final static String APP_LOGO = "app.logo";
+  public String getLogo();
+  public String setLogo(String value);
+  // constant/getter for 'app.mail.blog.password'
+  public final static String APP_MAIL_BLOG_PASSWORD = "app.mail.blog.password";
+  public String getMailBlogPassword();
+  public String setMailBlogPassword(String value);
+  // constant/getter for 'app.mail.domain'
+  public final static String APP_MAIL_DOMAIN = "app.mail.domain";
+  public String getMailDomain();
+  public String setMailDomain(String value);
+  // constant/getter for 'app.mail.host'
+  public final static String APP_MAIL_HOST = "app.mail.host";
+  public String getMailHost();
+  public String setMailHost(String value);
+  // constant/getter for 'app.mail.pop3.host'
+  public final static String APP_MAIL_POP3_HOST = "app.mail.pop3.host";
+  public String getMailPop3Host();
+  public String setMailPop3Host(String value);
+  // constant/getter for 'app.mail.pop3.interval'
+  public final static String APP_MAIL_POP3_INTERVAL = "app.mail.pop3.interval";
+  public String getMailPop3Interval();
+  public String setMailPop3Interval(String value);
+  // constant/getter for 'app.mail.pop3.password'
+  public final static String APP_MAIL_POP3_PASSWORD = "app.mail.pop3.password";
+  public String getMailPop3Password();
+  public String setMailPop3Password(String value);
+  // constant/getter for 'app.mail.pop3.user'
+  public final static String APP_MAIL_POP3_USER = "app.mail.pop3.user";
+  public String getMailPop3User();
+  public String setMailPop3User(String value);
+  // constant/getter for 'app.name'
+  public final static String APP_NAME = "app.name";
+  public String getName();
+  public String setName(String value);
+  // constant/getter for 'app.perm.createSnip'
+  public final static String APP_PERM_CREATESNIP = "app.perm.createSnip";
+  public String getPermCreateSnip();
+  public String setPermCreateSnip(String value);
+  // constant/getter for 'app.perm.externalImages'
+  public final static String APP_PERM_EXTERNALIMAGES = "app.perm.externalImages";
+  public String getPermExternalImages();
+  public String setPermExternalImages(String value);
+  // constant/getter for 'app.perm.multiplePosts'
+  public final static String APP_PERM_MULTIPLEPOSTS = "app.perm.multiplePosts";
+  public String getPermMultiplePosts();
+  public String setPermMultiplePosts(String value);
+  // constant/getter for 'app.perm.notification'
+  public final static String APP_PERM_NOTIFICATION = "app.perm.notification";
+  public String getPermNotification();
+  public String setPermNotification(String value);
+  // constant/getter for 'app.perm.register'
+  public final static String APP_PERM_REGISTER = "app.perm.register";
+  public String getPermRegister();
+  public String setPermRegister(String value);
+  // constant/getter for 'app.perm.weblogsPing'
+  public final static String APP_PERM_WEBLOGSPING = "app.perm.weblogsPing";
+  public String getPermWeblogsPing();
+  public String setPermWeblogsPing(String value);
+  // constant/getter for 'app.prefix'
+  public final static String APP_PREFIX = "app.prefix";
+  public String getPrefix();
+  public String setPrefix(String value);
+  // constant/getter for 'app.real.autodetect'
+  public final static String APP_REAL_AUTODETECT = "app.real.autodetect";
+  public String getRealAutodetect();
+  public String setRealAutodetect(String value);
+  // constant/getter for 'app.real.host'
+  public final static String APP_REAL_HOST = "app.real.host";
+  public String getRealHost();
+  public String setRealHost(String value);
+  // constant/getter for 'app.real.path'
+  public final static String APP_REAL_PATH = "app.real.path";
+  public String getRealPath();
+  public String setRealPath(String value);
+  // constant/getter for 'app.real.port'
+  public final static String APP_REAL_PORT = "app.real.port";
+  public String getRealPort();
+  public String setRealPort(String value);
+  // constant/getter for 'app.real.protocol'
+  public final static String APP_REAL_PROTOCOL = "app.real.protocol";
+  public String getRealProtocol();
+  public String setRealProtocol(String value);
+  // constant/getter for 'app.start.snip'
+  public final static String APP_START_SNIP = "app.start.snip";
+  public String getStartSnip();
+  public String setStartSnip(String value);
+  // constant/getter for 'app.tagline'
+  public final static String APP_TAGLINE = "app.tagline";
+  public String getTagline();
+  public String setTagline(String value);
+  // constant/getter for 'app.theme'
+  public final static String APP_THEME = "app.theme";
+  public String getTheme();
+  public String setTheme(String value);
+  // constant/getter for 'app.timezone'
+  public final static String APP_TIMEZONE = "app.timezone";
+  public String getTimezone();
+  public String setTimezone(String value);
+  // constant/getter for 'app.weblogDateFormat'
+  public final static String APP_WEBLOGDATEFORMAT = "app.weblogDateFormat";
+  public String getWeblogDateFormat();
+  public String setWeblogDateFormat(String value);
+
+}
blob - /dev/null
blob + b64861761fa109a202cf2a2b4ece3c60537e857c (mode 644)
--- /dev/null
+++ src/snipsnap/api/label/Label.java
@@ -0,0 +1,65 @@
+/*
+ * This file is part of "SnipSnap Wiki/Weblog".
+ *
+ * Copyright (c) 2002 Stephan J. Schmidt, Matthias L. Jugel
+ * All Rights Reserved.
+ *
+ * Please visit http://snipsnap.org/ for updates and contact.
+ *
+ * --LICENSE NOTICE--
+ * 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * --LICENSE NOTICE--
+ */
+
+package snipsnap.api.label;
+
+import snipsnap.api.snip.Snip;
+import org.snipsnap.snip.label.Indexable;
+import org.snipsnap.snip.label.LifeCycle;
+
+import java.util.Map;
+
+/**
+ * Label is attached to Snips
+ * @author Stephan J. Schmidt
+ * @version $Id: Label.java 1263 2003-12-12 08:58:25Z stephan $
+ */
+public interface Label extends Indexable, LifeCycle {
+  // public String serialize();
+
+  // public void deserialize(String label);
+
+  public String getListProxy();
+
+  public String getInputProxy();
+
+  public void handleInput(Map input);
+
+  public String getType();
+
+  public String getName();
+
+  public String getValue();
+
+  public void setName(String name);
+
+  public void setValue(String value);
+
+  public void setSnip(snipsnap.api.snip.Snip snip);
+
+  public snipsnap.api.snip.Snip getSnip();
+
+  public snipsnap.api.label.LabelContext getContext();
+}
blob - /dev/null
blob + 4ef8505fe7a510b8d263e970ba94541edef1ba71 (mode 644)
--- /dev/null
+++ src/snipsnap/api/label/LabelContext.java
@@ -0,0 +1,32 @@
+package snipsnap.api.label;
+
+import snipsnap.api.snip.Snip;
+import snipsnap.api.label.Label;
+
+/**
+ * A class holding context information about a Label. Subclasses can add all sorts of things so that
+ * LabelSerializers can make use of it.
+ *
+ * @author gis
+ */
+
+public class LabelContext {
+  public snipsnap.api.label.Label label;
+  public snipsnap.api.snip.Snip snip;
+
+  public LabelContext() {
+  }
+
+  public LabelContext(snipsnap.api.snip.Snip snip, snipsnap.api.label.Label label) {
+    this.snip = snip;
+    this.label = label;
+  }
+
+  public snipsnap.api.snip.Snip getSnip() {
+    return snip;     
+  }
+
+  public Label getLabel() {
+    return label;
+  }
+}
blob - /dev/null
blob + 4dd31c39620336a11cf45748a9c62d3166ef5773 (mode 644)
--- /dev/null
+++ src/snipsnap/api/label/Labels.java
@@ -0,0 +1,208 @@
+/*
+ * This file is part of "SnipSnap Wiki/Weblog".
+ *
+ * Copyright (c) 2002 Stephan J. Schmidt, Matthias L. Jugel
+ * All Rights Reserved.
+ *
+ * Please visit http://snipsnap.org/ for updates and contact.
+ *
+ * --LICENSE NOTICE--
+ * 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * --LICENSE NOTICE--
+ */
+
+package snipsnap.api.label;
+
+import org.snipsnap.util.StringUtil;
+import snipsnap.api.snip.Snip;
+import org.snipsnap.container.Components;
+import org.snipsnap.snip.label.LabelManager;
+import snipsnap.api.app.Application;
+
+import java.util.*;
+
+/**
+ * Stores Label information for a snip
+ *
+ * @author stephan
+ * @version $Id: Labels.java 1609 2004-05-18 13:28:38Z stephan $
+ */
+
+public class Labels {
+  private Map labels;
+  private String cache;
+
+  public Labels() {
+    this.labels = new HashMap();
+  }
+
+  public Labels(Snip snip, String labelString) {
+    cache = labelString;
+    deserialize(snip, labelString);
+  }
+
+  public void addLabel(Label label) {
+    // TODO: check if label with same name exists
+    // additional parameter 'overwrite' or exception or return value?
+    // (decision should to be made by user)
+    cache = null;
+    Map map = (Map) this.labels.get(label.getName());
+    if (map == null) {
+      map = new HashMap();
+      this.labels.put(label.getName(), map);
+    }
+    map.put(label.getValue(), label);
+  }
+
+  public void addLabel(String name, String value) {
+    // TODO: check if label with same name exists
+    // additional parameter 'overwrite' or exception or return value?
+    // (decision should to be made by user)
+    cache = null;
+    snipsnap.api.label.Label label = createDefaultLabel(name, value);
+    addLabel(label);
+  }
+
+  public Label getLabel(String name) {
+    Map map = (Map) this.labels.get(name);
+    if (map == null) return null;
+    Iterator it = map.values().iterator();
+    return it.hasNext() ? (snipsnap.api.label.Label) it.next() : null;
+  }
+
+  public snipsnap.api.label.Label getLabel(String name, String value) {
+    Map map = (Map) this.labels.get(name);
+    if (map == null) return null;
+    return (snipsnap.api.label.Label) map.get(value);
+  }
+
+  public Collection getAll() {
+    Collection result = new ArrayList();
+
+    Iterator iterator = this.labels.values().iterator();
+    while (iterator.hasNext()) {
+      Map map = (Map) iterator.next();
+      result.addAll(map.values());
+    }
+    return result;
+  }
+
+  public Collection getLabels(String type) {
+    ArrayList result = new ArrayList();
+    if (null == type) {
+      return result;
+    }
+
+    Iterator iterator = this.labels.values().iterator();
+    while (iterator.hasNext()) {
+      Map map = (Map) iterator.next();
+      Iterator it = map.values().iterator();
+      while (it.hasNext()) {
+        snipsnap.api.label.Label label = (Label) it.next();
+        if (null != label && type.equals(label.getType())) {
+          result.add(label);
+        }
+      }
+    }
+    return result;
+  }
+
+  public void removeLabel(String name, String value) {
+    cache = null;
+    Map map = (Map) labels.get(name);
+    if (map != null) {
+      snipsnap.api.label.Label label = (Label) map.get(value);
+      label.remove();
+      map.remove(value);
+    }
+  }
+
+  private Label createDefaultLabel(String name, String value) {
+    snipsnap.api.label.Label label = ((LabelManager) Components.getComponent(LabelManager.class)).getDefaultLabel();
+    label.setName(name);
+    label.setValue(value);
+    return label;
+  }
+
+  private snipsnap.api.label.Label createLabel(String type, String name, String value) {
+    // TODO: ? throw an exception (e.g. LabelTypeUnkownException ) ?
+    snipsnap.api.label.Label label = ((LabelManager) Components.getComponent(LabelManager.class)).getLabel(type);
+    if (label != null) {
+      label.setName(name);
+      label.setValue(value);
+    }
+    return label;
+  }
+
+  private void deserialize(snipsnap.api.snip.Snip snip, String labelString) {
+    labels = new HashMap();
+    if (null == labelString || "".equals(labelString)) {
+      return;
+    }
+
+    StringTokenizer tokenizer = new StringTokenizer(labelString, "|");
+    while (tokenizer.hasMoreTokens()) {
+      String labelToken = tokenizer.nextToken();
+      String[] data = StringUtil.split(labelToken, ":");
+      //System.out.println("Data="+data);
+      if (data.length == 3) {
+        snipsnap.api.label.Label label = createLabel(data[0], data[1], data[2]);
+        label.setSnip(snip);
+        addLabel(label);
+      } else {
+        System.err.println("Labels: Broken Label: '" + labelToken + "' ignored");
+      }
+    }
+    return;
+  }
+
+  private String serialize() {
+    if (null == this.labels || this.labels.isEmpty()) {
+      return "";
+    }
+
+    StringBuffer linkBuffer = new StringBuffer();
+    Iterator iterator = this.labels.entrySet().iterator();
+    while (iterator.hasNext()) {
+      Map.Entry entry = (Map.Entry) iterator.next();
+      String name = (String) entry.getKey();
+      Map map = (Map) entry.getValue();
+      Iterator it = map.values().iterator();
+      while (it.hasNext()) {
+        snipsnap.api.label.Label label = (snipsnap.api.label.Label) it.next();
+        String type = label.getType();
+        String value = label.getValue();
+        linkBuffer.append(type);
+        linkBuffer.append(":");
+        linkBuffer.append(name);
+        linkBuffer.append(":");
+        linkBuffer.append(value);
+
+        linkBuffer.append("|");
+      }
+    }
+    //System.out.println("serialize = "+linkBuffer.toString());
+    // remove last '|'
+    if (linkBuffer.length() > 0) {
+      linkBuffer.setLength(linkBuffer.length() - 1);
+    }
+    return linkBuffer.toString();
+  }
+
+  public String toString() {
+    // always force serialization to ensure changed labels are reflected
+    return (cache = serialize());
+  }
+}
blob - /dev/null
blob + 48ba6da30c7fde28d7c5704a75d088921d01a3a2 (mode 644)
--- /dev/null
+++ src/snipsnap/api/user/User.java
@@ -0,0 +1,278 @@
+/*
+ * This file is part of "SnipSnap Wiki/Weblog".
+ *
+ * Copyright (c) 2002 Stephan J. Schmidt, Matthias L. Jugel
+ * All Rights Reserved.
+ *
+ * Please visit http://snipsnap.org/ for updates and contact.
+ *
+ * --LICENSE NOTICE--
+ * 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * --LICENSE NOTICE--
+ */
+package snipsnap.api.user;
+
+import snipsnap.api.app.Application;
+import snipsnap.api.config.Configuration;
+import snipsnap.api.snip.SnipLink;
+import org.snipsnap.render.macro.list.Linkable;
+import org.snipsnap.user.Roles;
+import org.snipsnap.user.Digest;
+
+import java.sql.Timestamp;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.HashSet;
+
+import gabriel.Subject;
+import gabriel.Principal;
+
+/**
+ * User class.
+ *
+ * @author Stephan J. Schmidt
+ * @version $Id: User.java 1754 2004-09-16 09:16:06Z stephan $
+ */
+public class User implements Linkable {
+  private Subject subject;
+
+  private String applicationOid;
+  private String login;
+  private String passwd;
+  private String email;
+  private String status;
+  private Roles roles;
+  private Principal user;
+
+  // @TODO: composite object
+  private Timestamp lastLogin, lastAccess, lastLogout;
+  // @TODO: -> Modified composite object
+  private Timestamp cTime, mTime;
+
+  private boolean guest = false;
+  private boolean nonUser = false;
+
+  public User() {
+    this("", "", "");
+  }
+
+  public User(String login, String passwd, String email) {
+    this.login = login;
+    setPasswd(passwd);
+    setEmail(email);
+    user = new Principal("User");
+  }
+
+  public Subject getSubject() {
+    if (null == subject) {
+      subject = new Subject(this.login);
+      Set principals = new HashSet();
+      // SECURITY PROBLEM, what if user CALLS himself "EDITOR"?
+      // So add "user::"
+      // Also probably add a "Developer" role for debugging
+      principals.add(new Principal("user::"+this.login));
+      Iterator iterator = getRoles().iterator();
+      while (iterator.hasNext()) {
+        String role = (String) iterator.next();
+        principals.add(new Principal(role));
+      }
+      if (! isGuest()) {
+        principals.add(user);
+      }
+      subject.setPrincipals(principals);
+    }
+    return subject;
+  }
+
+  public void setApplication(String applicationOid) {
+    this.applicationOid = applicationOid;
+  }
+
+  public String getApplication() {
+    return applicationOid;
+  }
+
+
+  public Timestamp getCTime() {
+    return cTime;
+  }
+
+  public void setCTime(Timestamp cTime) {
+    this.cTime = cTime;
+  }
+
+  public Timestamp getMTime() {
+    return mTime;
+  }
+
+  public void setMTime(Timestamp mTime) {
+    this.mTime = mTime;
+  }
+
+  /**
+   * LastAccess sets the time when the user
+   * last accessed SnipSnap. This is used
+   * to find snips since his last access.
+   */
+  public void lastAccess() {
+    this.lastAccess = new Timestamp(new java.util.Date().getTime());
+    //Logger.debug(this.login+" hashcode: "+((Object) this).hashCode());
+    //Logger.debug("Set lastAccess() "+this.login+" "+lastAccess);
+  }
+
+  public Timestamp getLastLogout() {
+    return lastLogout;
+  }
+
+  public void setLastLogout(Timestamp lastLogout) {
+    //Logger.debug(this.login+" hashcode: "+((Object) this).hashCode());
+    //Logger.debug("Set LastLogout() "+this.login+" "+lastLogout+" old: "+this.lastLogout);
+    this.lastLogout = lastLogout;
+  }
+
+  public Timestamp getLastAccess() {
+    return this.lastAccess;
+  }
+
+  public void setLastAccess(Timestamp lastAccess) {
+    this.lastAccess = lastAccess;
+  }
+
+  public Timestamp getLastLogin() {
+    return lastLogin;
+  }
+
+  public void lastLogin() {
+    setLastLogin(new Timestamp(new java.util.Date().getTime()));
+  }
+
+  public void setLastLogin(Timestamp lastLogin) {
+    this.lastLogin = lastLogin;
+  }
+
+  public void setStatus(String status) {
+    this.status = status;
+    return;
+  }
+
+  public String getStatus() {
+    if (null == status) {
+      status = "not set";
+    }
+    return status;
+  }
+
+  public void setEmail(String email) {
+    this.email = email;
+  }
+
+  public String getEmail() {
+    return email;
+  }
+
+  // Set passwd of user. Takes unecrypted
+  // passwd and then sets an encrypted version
+  public void setPasswd(String passwd) {
+    if (passwd != null && passwd.length() > 30) {
+      this.passwd = passwd;
+    } else {
+      this.passwd = Digest.getDigest(passwd);
+    }
+  }
+
+  public String getPasswd() {
+    return passwd;
+  }
+
+  /**
+   * WARNING: DO NOT USE THIS METHOD UNLESS YOU KNOW WHAT YOU DO.
+   *
+   * @param login
+   */
+  public void setLogin(String login) {
+    this.login = login;
+  }
+
+  public String getLogin() {
+    return login;
+  }
+
+  public void setRoles(Roles roles) {
+    this.roles = roles;
+    return;
+  }
+
+  public Roles getRoles() {
+    if (null == roles) {
+      roles = new Roles();
+    }
+    return roles;
+  }
+
+  public boolean isAdmin() {
+    Application app = snipsnap.api.app.Application.get();
+    snipsnap.api.config.Configuration config = app.getConfiguration();
+    return (config.getAdminLogin() != null && config.getAdminLogin().equals(login))
+        || getRoles().contains(Roles.ADMIN);
+  }
+
+  public void setGuest(boolean guest) {
+    this.guest = guest;
+  }
+
+  public boolean isGuest() {
+    return guest;
+  }
+
+  public void setNonUser(boolean nonUser) {
+    this.nonUser = nonUser;
+  }
+
+  public boolean isNonUser() {
+    return nonUser;
+  }
+
+  public int hashCode() {
+    return getLogin().hashCode();
+  }
+
+  public boolean equals(Object obj) {
+    if (obj instanceof User && obj != null && this.getLogin() != null) {
+      return this.getLogin().equals(((User) obj).getLogin());
+    }
+    return false;
+  }
+
+  public String toString() {
+    return "User[" + login + "," + (passwd != null ? "pass set" : "no pass") + "," + email + "," + status + "," + roles + "]";
+  }
+
+  public String getLink() {
+    if (isNonUser()) {
+      StringBuffer tmp = new StringBuffer();
+      tmp.append("<a href=\"");
+      tmp.append(getEmail());
+      tmp.append("\">");
+      tmp.append(getLogin());
+      tmp.append("</a>");
+      return tmp.toString();
+    } else if (isGuest()) {
+      return "Guest";
+    } else {
+      return snipsnap.api.snip.SnipLink.createLink(getLogin());
+    }
+  }
+
+}
\ No newline at end of file