You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@roller.apache.org by sn...@apache.org on 2006/05/02 00:23:34 UTC

svn commit: r398712 [31/32] - in /incubator/roller/trunk/src/org/apache: ./ roller/ roller/business/ roller/business/hibernate/ roller/business/referrers/ roller/business/runnable/ roller/business/search/ roller/business/search/operations/ roller/busin...

Added: incubator/roller/trunk/src/org/apache/roller/util/MailUtil.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/util/MailUtil.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/util/MailUtil.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/util/MailUtil.java Mon May  1 15:23:02 2006
@@ -0,0 +1,316 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+*  contributor license agreements.  The ASF licenses this file to You
+* under the Apache License, Version 2.0 (the "License"); you may not
+* use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.  For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+package org.apache.roller.util;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import javax.mail.Message;
+import javax.mail.MessagingException;
+import javax.mail.SendFailedException;
+import javax.mail.Session;
+import javax.mail.Transport;
+import javax.mail.Address;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeMessage;
+
+
+public class MailUtil extends Object {
+   
+	private static Log mLogger = 
+		LogFactory.getFactory().getInstance(MailUtil.class);
+
+    // agangolli: Incorporated suggested changes from Ken Blackler.
+
+    /**
+     * This method is used to send a Message with a pre-defined
+     * mime-type.
+     * 
+     * @param from e-mail address of sender
+     * @param to e-mail address(es) of recipients
+     * @param subject subject of e-mail
+     * @param content the body of the e-mail
+     * @param mimeType type of message, i.e. text/plain or text/html
+     * @throws MessagingException the exception to indicate failure
+     */
+    public static void sendMessage
+    (
+    	Session session,
+        String from,
+        String[] to,
+        String[] cc,
+        String[] bcc,
+        String subject,
+        String content,
+        String mimeType
+    ) 
+    throws MessagingException
+    {
+        Message message = new MimeMessage(session);
+
+        // n.b. any default from address is expected to be determined by caller.
+        if (! StringUtils.isEmpty(from)) {
+			InternetAddress sentFrom = new InternetAddress(from);
+			message.setFrom(sentFrom);
+			if (mLogger.isDebugEnabled()) mLogger.debug("e-mail from: " + sentFrom);
+        }
+
+		if (to!=null)
+		{
+			InternetAddress[] sendTo = new InternetAddress[to.length];
+	
+			for (int i = 0; i < to.length; i++) 
+			{
+				sendTo[i] = new InternetAddress(to[i]);
+				if (mLogger.isDebugEnabled()) mLogger.debug("sending e-mail to: " + to[i]);
+			}
+			message.setRecipients(Message.RecipientType.TO, sendTo);
+		}
+
+		if (cc != null) 
+		{
+			InternetAddress[] copyTo = new InternetAddress[cc.length];
+
+			for (int i = 0; i < cc.length; i++) 
+			{
+				copyTo[i] = new InternetAddress(cc[i]);
+				if (mLogger.isDebugEnabled()) mLogger.debug("copying e-mail to: " + cc[i]);
+			}
+			message.setRecipients(Message.RecipientType.CC, copyTo);
+		}	        
+
+		if (bcc != null) 
+		{
+			InternetAddress[] copyTo = new InternetAddress[bcc.length];
+
+			for (int i = 0; i < bcc.length; i++) 
+			{
+				copyTo[i] = new InternetAddress(bcc[i]);
+				if (mLogger.isDebugEnabled()) mLogger.debug("blind copying e-mail to: " + bcc[i]);
+			}
+			message.setRecipients(Message.RecipientType.BCC, copyTo);
+		}	        
+        message.setSubject((subject == null) ? "(no subject)" : subject);
+        message.setContent(content, mimeType);
+        message.setSentDate(new java.util.Date()); 
+
+		// First collect all the addresses together.
+        Address[] remainingAddresses = message.getAllRecipients();
+        int nAddresses = remainingAddresses.length;
+        boolean bFailedToSome = false;
+        
+        SendFailedException sendex = new SendFailedException("Unable to send message to some recipients");
+        
+		// Try to send while there remain some potentially good addresses
+		do
+        {
+			// Avoid a loop if we are stuck
+			nAddresses = remainingAddresses.length;
+
+			try
+			{
+				// Send to the list of remaining addresses, ignoring the addresses attached to the message
+		        Transport.send(message,remainingAddresses);
+			}
+			catch(SendFailedException ex)
+			{
+				bFailedToSome=true;
+				sendex.setNextException(ex);
+				
+				// Extract the remaining potentially good addresses
+				remainingAddresses=ex.getValidUnsentAddresses();
+			}
+        } while (remainingAddresses!=null && remainingAddresses.length>0 && remainingAddresses.length!=nAddresses);
+        
+        if (bFailedToSome) throw sendex;
+    }
+
+    /**
+     * This method is used to send a Text Message.
+     * 
+     * @param from e-mail address of sender
+     * @param to e-mail addresses of recipients
+     * @param subject subject of e-mail
+     * @param content the body of the e-mail
+     * @throws MessagingException the exception to indicate failure
+     */
+    public static void sendTextMessage
+    (
+    	Session session,
+        String from,
+        String[] to,
+        String[] cc,
+        String[] bcc,
+        String subject,
+        String content
+    ) 
+    throws MessagingException
+    {
+        sendMessage(session, from, to, cc, bcc, subject, content, "text/plain; charset=utf-8");
+    }
+    
+	/**
+	 * This method overrides the sendTextMessage to specify
+	 * one receiver and mulitple cc recipients.
+	 * 
+	 * @param from e-mail address of sender
+	 * @param to e-mail addresses of recipients
+	 * @param subject subject of e-mail
+	 * @param content the body of the e-mail
+	 * @throws MessagingException the exception to indicate failure
+	 */
+	public static void sendTextMessage
+	(
+		Session session,
+		String from,
+		String to,
+		String[] cc,
+        String[] bcc,
+		String subject,
+		String content
+	) 
+	throws MessagingException
+	{
+        String[] recipient = null;
+		if (to!=null) recipient = new String[] {to};
+
+		sendMessage(session, from, recipient, cc, bcc, subject, content, "text/plain; charset=utf-8");
+	}
+	
+    /**
+	 * This method overrides the sendTextMessage to specify
+	 * only one receiver and cc recipients, rather than 
+	 * an array of recipients.
+     * 
+     * @param from e-mail address of sender
+     * @param to e-mail address of recipient
+     * @param cc e-mail address of cc recipient
+     * @param subject subject of e-mail
+     * @param content the body of the e-mail
+     * @throws MessagingException the exception to indicate failure
+     */
+    public static void sendTextMessage
+    (
+    	Session session,
+        String from,
+        String to,
+        String cc,
+        String bcc,
+        String subject,
+        String content
+    ) 
+    throws MessagingException
+    {
+        String[] recipient = null;
+        String[] copy = null;
+        String[] bcopy = null;
+
+		if (to!=null) recipient = new String[] {to};
+		if (cc!=null) copy = new String[] {cc};
+		if (bcc!=null) bcopy = new String[] {bcc};
+
+        sendMessage(session, from, recipient, copy, bcopy, subject, content, "text/plain; charset=utf-8");
+    }
+    
+    /**
+     * This method is used to send a HTML Message
+     * 
+     * @param from e-mail address of sender
+     * @param to e-mail address(es) of recipients
+     * @param subject subject of e-mail
+     * @param content the body of the e-mail
+     * @throws MessagingException the exception to indicate failure
+     */
+    public static void sendHTMLMessage
+    (
+    	Session session,
+        String from,
+        String[] to,
+        String[] cc,
+        String[] bcc,
+        String subject,
+        String content
+    ) 
+    throws MessagingException
+    {
+        sendMessage(session, from, to, cc, bcc, subject, content, "text/html; charset=utf-8");
+    }
+    
+    /**
+     * This method overrides the sendHTMLMessage to specify
+     * only one sender, rather than an array of senders.
+     * 
+     * @param from e-mail address of sender
+     * @param to e-mail address of recipients
+     * @param subject subject of e-mail
+     * @param content the body of the e-mail
+     * @throws MessagingException the exception to indicate failure
+     */
+	public static void sendHTMLMessage
+    (
+    	Session session,
+        String from,
+        String to,
+        String cc,
+        String bcc,
+        String subject,
+        String content
+    ) 
+    throws MessagingException
+    {
+        String[] recipient = null;
+        String[] copy = null;
+        String[] bcopy = null;
+
+		if (to!=null) recipient = new String[] {to};
+		if (cc!=null) copy = new String[] {cc};
+		if (bcc!=null) bcopy = new String[] {bcc};
+
+        sendMessage(session, from, recipient, copy, bcopy, subject, content, "text/html; charset=utf-8");
+    }
+    
+	/**
+	 * This method overrides the sendHTMLMessage to specify
+	 * one receiver and mulitple cc recipients.
+	 * 
+	 * @param from e-mail address of sender
+	 * @param to e-mail address of recipient
+	 * @param cc e-mail addresses of recipients
+	 * @param subject subject of e-mail
+	 * @param content the body of the e-mail
+	 * @throws MessagingException the exception to indicate failure
+	 */
+	public static void sendHTMLMessage
+	(
+		Session session,
+		String from,
+		String to,
+		String[] cc,
+		String[] bcc,
+		String subject,
+		String content
+	) 
+	throws MessagingException
+	{
+        String[] recipient = null;
+		if (to!=null) recipient = new String[] {to};
+
+		sendMessage(session, from, recipient, cc, bcc, subject, content, "text/html; charset=utf-8");
+	}
+}
+

Added: incubator/roller/trunk/src/org/apache/roller/util/OldRollerConfig.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/util/OldRollerConfig.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/util/OldRollerConfig.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/util/OldRollerConfig.java Mon May  1 15:23:02 2006
@@ -0,0 +1,18 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+*  contributor license agreements.  The ASF licenses this file to You
+* under the Apache License, Version 2.0 (the "License"); you may not
+* use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.  For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+package org.apache.roller.util;

import java.beans.IntrospectionException;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.betwixt.io.BeanReader;
import org.apache.commons.betwixt.io.BeanWriter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.roller.RollerException;
import org.apache.roller.pojos.RollerConfigData;

import org.xml.sax.SAXException;


/**
 * Configuration object for Roller.  Reads and writes roller-config.xml.
 * This file is a relic of the old days, back when we used to store the Roller
 * configuration in an XML file. In Roller 0.9.9 and later, this file only 
 * exis
 ts to allow use to read only roller-config.xml files on startup and
 * copy them into the database. 
 */
public class OldRollerConfig implements java.io.Serializable
{
    static final long serialVersionUID = -6625873343838437510L;
    
    private static Log mLogger =
        LogFactory.getFactory().getInstance( OldRollerConfig.class );

    /**
     * Absolute URL for site, for cases where infered absolute URL doesn't
     * work.
     */
    protected String mAbsoluteURL = null;

    /** Should Roller cache return RSS pages. */
    protected boolean mRssUseCache = false;

    /** Duration to cache RSS pages (in seconds). */
    protected int mRssCacheTime = 3000;

    /** Does Roller allow the creation of new users. */
    protected boolean mNewUserAllowed = false;

    /** List of usernames with Admin priviledges. */
    protected List mAdminUsers = new ArrayList();

    /** Where to get data for creating new users (new-user.xml). */
    protected String mNewUserData = "
 /templates";

    /** Where to get Themes presented to new users. */
    protected String mNewUserThemes = "/themes";

    /** List of "editor pages" for the Weblog entry editor. */
    protected List mEditorPages = new ArrayList();

    /** Dis/enble RSS aggregation capabilities. */
    protected boolean mEnableAggregator = false;

    /** Are file uploads enabled. */
    protected boolean mUploadEnabled = false;

    /** The maximum size of each user's upload directory. */
    protected Float mUploadMaxDirMB = new Float( "2" );

    /** The maximum size allowed per uploaded file. */
    protected Float mUploadMaxFileMB = new Float( ".5" );

    /**
     * List of permitted file extensions (not including the "dot"). This
     * attribute is mutually exclusive with uploadForbid.
     */
    protected List mUploadAllow = new ArrayList();

    /**
     * List of forbidden file extensions (not including the "dot"). This
     * attribute is mutually exclusive with uploadAllow.
 
     */
    protected List mUploadForbid = new ArrayList();

    /**
     * Directory where uploaded files will be stored. May end with a slash.
     * Optional, this value will default to RollerContext.USER_RESOURCES.  If
     * specified, should be a full path on the system harddrive or relative to
     * the WebApp.
     */
    protected String mUploadDir = "";

    /**
     * The path from which the webserver will serve upload files. This values
     * must not end in a slash.
     */
    protected String uploadPath = "/resources";
    protected boolean mMemDebug = false;

    /**
     * Determines if the Comment page will "autoformat" comments.  That is,
     * replace carriage-returns with <br />.
     */
    protected boolean mAutoformatComments = false;

    /** Determines if the Comment page will escape html in comments. */
    protected boolean mEscapeCommentHtml = false;

    /** Determines if e-mailing comments is enabled. */
    protected boolean mEmailComments =
  false;

    /** Enable linkback extraction. */
    protected boolean mEnableLinkback = false;

    /** Name of this site */
    protected String mSiteName = "Roller-based Site";

    /** Description of this site */
    protected String mSiteDescription = "Roller-based Site";

    /** Site administrator's email address */
    protected String mEmailAddress = "";

    /** Lucene index directory */
    protected String mIndexDir =
        "${user.home}" + File.separator + "roller-index";

    /**
     * Flag for encrypting passwords
     */
    protected boolean mEncryptPasswords = false;
    
    /** Algorithm for encrypting passwords */
    protected String mAlgorithm = "SHA";
    
    public OldRollerConfig()
    {
    }

    public OldRollerConfig( RollerConfigData rConfig )
    {
        this.setAbsoluteURL( rConfig.getAbsoluteURL() );
        this.setRssUseCache( rConfig.getRssUseCache().booleanValue() );
        this.setRssCacheTime( rConfig.getRssCacheTime().intValue()
  );
        this.setNewUserAllowed( rConfig.getNewUserAllowed().booleanValue() );
        this.setNewUserThemes( rConfig.getUserThemes() );
        this.setEditorPages( rConfig.getEditorPagesList() );
        this.setEnableAggregator( rConfig.getEnableAggregator().booleanValue() );
        this.setUploadEnabled( rConfig.getUploadEnabled().booleanValue() );
        this.setUploadMaxDirMB( new Float( rConfig.getUploadMaxDirMB()
                                                  .doubleValue() ) );
        this.setUploadMaxFileMB( new Float( rConfig.getUploadMaxFileMB()
                                                   .doubleValue() ) );
        this.setUploadAllow( Arrays.asList( rConfig.uploadAllowArray() ) );
        this.setUploadForbid( Arrays.asList( rConfig.uploadForbidArray() ) );
        this.setUploadDir( rConfig.getUploadDir() );
        this.setUploadPath( rConfig.getUploadPath() );
        this.setMemDebug( rConfig.getMemDebug().booleanValue() );
        this.setA
 utoformatComments( rConfig.getAutoformatComments()
                                           .booleanValue() );
        this.setEscapeCommentHtml( rConfig.getEscapeCommentHtml()
                                          .booleanValue() );
        this.setEmailComments( rConfig.getEmailComments().booleanValue() );
        this.setEnableLinkback( rConfig.getEnableLinkback().booleanValue() );
        this.setSiteName( rConfig.getSiteName() );
        this.setSiteDescription( rConfig.getSiteDescription() );
        this.setEmailAddress( rConfig.getEmailAddress() );
        this.setIndexDir( rConfig.getIndexDir() );
        this.setEncryptPasswords( rConfig.getEncryptPasswords().booleanValue() );
        this.setAlgorithm( rConfig.getAlgorithm() );
    }

    //-------------------------------------- begin requisite getters & setters
    public String getAbsoluteURL()
    {
        return mAbsoluteURL;
    }

    public void setAbsoluteURL( String string )
    {
        mAbsolute
 URL = string;
    }

    public boolean getRssUseCache()
    {
        return mRssUseCache;
    }

    public void setRssUseCache( boolean use )
    {
        mRssUseCache = use;
    }

    public int getRssCacheTime()
    {
        return mRssCacheTime;
    }

    public void setRssCacheTime( int cacheTime )
    {
        mRssCacheTime = cacheTime;
    }

    public boolean getNewUserAllowed()
    {
        return mNewUserAllowed;
    }

    public void setNewUserAllowed( boolean use )
    {
        mNewUserAllowed = use;
    }

    public List getAdminUsers()
    {
        return mAdminUsers;
    }

    /**
     * @param _adminUsers
     */
    public void setAdminUsers( List _adminUsers )
    {
        mAdminUsers = _adminUsers;
    }

    /**
     * @param ignore
     */
    public void addAdminUsers( String ignore )
    {
        mAdminUsers.add( ignore );
    }

    public String getNewUserData()
    {
        return mNewUserData;
    }

    /**
     * @param str
     
 */
    public void setNewUserData( String str )
    {
        mNewUserData = str;
    }

    public String getNewUserThemes()
    {
        return mNewUserThemes;
    }

    /**
     * @param str
     */
    public void setNewUserThemes( String str )
    {
        mNewUserThemes = str;
    }

    public List getEditorPages()
    {
        return mEditorPages;
    }

    /**
     * @param _editorPages
     */
    public void setEditorPages( List _editorPages )
    {
        mEditorPages = _editorPages;
    }

    /**
     * @param ignore
     */
    public void addEditorPages( String ignore )
    {
        mEditorPages.add( ignore );
    }

    public boolean getEnableAggregator()
    {
        return mEnableAggregator;
    }

    public void setEnableAggregator( boolean use )
    {
        mEnableAggregator = use;
    }

    public boolean getUploadEnabled()
    {
        return mUploadEnabled;
    }

    public void setUploadEnabled( boolean use )
    {
        mUploadEnabl
 ed = use;
    }

    public Float getUploadMaxDirMB()
    {
        return mUploadMaxDirMB;
    }

    public void setUploadMaxDirMB( Float use )
    {
        mUploadMaxDirMB = use;
    }

    public Float getUploadMaxFileMB()
    {
        return mUploadMaxFileMB;
    }

    public void setUploadMaxFileMB( Float use )
    {
        mUploadMaxFileMB = use;
    }

    public List getUploadAllow()
    {
        return mUploadAllow;
    }

    /**
     * @param _uploadAllow
     */
    public void setUploadAllow( List _uploadAllow )
    {
        mUploadAllow = _uploadAllow;
    }

    /**
     * @param ignore
     */
    public void addUploadAllow( String ignore )
    {
        mUploadAllow.add( ignore );
    }

    public List getUploadForbid()
    {
        return mUploadForbid;
    }

    /**
     * @param _uploadForbid
     */
    public void setUploadForbid( List _uploadForbid )
    {
        mUploadForbid = _uploadForbid;
    }

    /**
     * @param ignore
     */
    
 public void addUploadForbid( String ignore )
    {
        mUploadForbid.add( ignore );
    }

    public String getUploadDir()
    {
        return mUploadDir;
    }

    /**
     * @param str
     */
    public void setUploadDir( String str )
    {
        mUploadDir = str;
    }

    public String getUploadPath()
    {
        return uploadPath;
    }

    /**
     * @param str
     */
    public void setUploadPath( String str )
    {
        uploadPath = str;
    }

    public boolean getMemDebug()
    {
        return mMemDebug;
    }

    /**
     * Set memory debugging on or off.
     *
     * @param memDebug The mMemDebug to set
     */
    public void setMemDebug( boolean memDebug )
    {
        mMemDebug = memDebug;
    }

    public boolean getAutoformatComments()
    {
        return mAutoformatComments;
    }

    /**
     * @param value
     */
    public void setAutoformatComments( boolean value )
    {
        mAutoformatComments = value;
    }

    public b
 oolean getEscapeCommentHtml()
    {
        return mEscapeCommentHtml;
    }

    /**
     * @param value
     */
    public void setEscapeCommentHtml( boolean value )
    {
        mEscapeCommentHtml = value;
    }

    /**
     * @return boolean
     */
    public boolean getEmailComments()
    {
        return mEmailComments;
    }

    /**
     * Sets the emailComments.
     *
     * @param emailComments The emailComments to set
     */
    public void setEmailComments( boolean emailComments )
    {
        this.mEmailComments = emailComments;
    }

    /**
     * Enable linkback.
     *
     * @return
     */
    public boolean isEnableLinkback()
    {
        return mEnableLinkback;
    }

    /**
     * Enable linkback.
     *
     * @param b
     */
    public void setEnableLinkback( boolean b )
    {
        mEnableLinkback = b;
    }

    /**
     * @return
     */
    public String getSiteDescription()
    {
        return mSiteDescription;
    }

    /**
     * 
 @return
     */
    public String getSiteName()
    {
        return mSiteName;
    }

    /**
     * @param string
     */
    public void setSiteDescription( String string )
    {
        mSiteDescription = string;
    }

    /**
     * @param string
     */
    public void setSiteName( String string )
    {
        mSiteName = string;
    }

    /**
     * @return
     */
    public String getEmailAddress()
    {
        return mEmailAddress;
    }

    /**
     * @param emailAddress
     */
    public void setEmailAddress( String emailAddress )
    {
        mEmailAddress = emailAddress;
    }

    /**
     * @return the index directory
     */
    public String getIndexDir()
    {
        return mIndexDir;
    }

    /**
     * @param indexDir new index directory
     */
    public void setIndexDir( String indexDir )
    {
        mIndexDir = indexDir;
    }

    public boolean getEncryptPasswords()
    {
        return mEncryptPasswords;
    }

    public void setEncry
 ptPasswords( boolean use )
    {
        mEncryptPasswords = use;
    }
    
    /**
     * @return the algorithm for encrypting passwords
     */
    public String getAlgorithm()
    {
        return mAlgorithm;
    }

    /**
     * @param algorithm, the new algorithm
     */
    public void setAlgorithm( String algorithm )
    {
        mAlgorithm = algorithm;
    }
    
    //---------------------------------------- end requisite getters & setters

    /**
     * Convenience method for getAdminUsers.
     *
     * @return
     */
    public String[] adminUsersArray()
    {
        if ( mAdminUsers == null )
        {
            mAdminUsers = new ArrayList();
        }

        return (String[]) mAdminUsers.toArray( new String[mAdminUsers.size()] );
    }

    /**
     * Convenience method for getEditorPages.
     *
     * @return
     */
    public String[] editorPagesArray()
    {
        if ( mEditorPages == null )
        {
            mEditorPages = new ArrayList();
 
        }

        return (String[]) mEditorPages.toArray( new String[mEditorPages.size()] );
    }

    /**
     * Convenience method for getUploadAllow.
     *
     * @return
     */
    public String[] uploadAllowArray()
    {
        if ( mUploadAllow == null )
        {
            mUploadAllow = new ArrayList();
        }

        return (String[]) mUploadAllow.toArray( new String[mUploadAllow.size()] );
    }

    /**
     * Convenience method for getUploadForbid.
     *
     * @return
     */
    public String[] uploadForbidArray()
    {
        if ( mUploadForbid == null )
        {
            mUploadForbid = new ArrayList();
        }

        return (String[]) mUploadForbid.toArray( new String[mUploadForbid.size()] );
    }

    public void updateValues( OldRollerConfig child )
    {
        this.mAbsoluteURL = child.getAbsoluteURL();
        this.mRssUseCache = child.getRssUseCache();
        this.mRssCacheTime = child.getRssCacheTime();
        this.mNewUserAl
 lowed = child.getNewUserAllowed();
        this.mAdminUsers = child.getAdminUsers();
        this.mNewUserData = child.getNewUserData();
        this.mNewUserThemes = child.getNewUserThemes();
        this.mEditorPages = child.getEditorPages();
        this.mEnableAggregator = child.getEnableAggregator();
        this.mUploadEnabled = child.getUploadEnabled();
        this.mUploadMaxDirMB = child.getUploadMaxDirMB();
        this.mUploadMaxFileMB = child.getUploadMaxFileMB();
        this.mUploadAllow = child.getUploadAllow();
        this.mUploadForbid = child.getUploadForbid();
        this.mUploadDir = child.getUploadDir();
        this.uploadPath = child.getUploadPath();
        this.mMemDebug = child.getMemDebug();
        this.mAutoformatComments = child.getAutoformatComments();
        this.mEscapeCommentHtml = child.getEscapeCommentHtml();
        this.mEmailComments = child.getEmailComments();
        this.mEnableLinkback = child.isEnableLinkback();
        this.mSi
 teName = child.getSiteName();
        this.mSiteDescription = child.getSiteDescription();
        this.mEmailAddress = child.getEmailAddress();
        this.mIndexDir = child.getIndexDir();
        this.mEncryptPasswords = child.getEncryptPasswords();
        this.mAlgorithm = child.getAlgorithm();
    }

    /**
     * nice output for debugging
     *
     * @return
     */
    public String toString()
    {
        StringBuffer buf = new StringBuffer();

        buf.append( "RollerConfig \n" );

        Class clazz = getClass();

        Field[] fields = clazz.getDeclaredFields();

        try
        {
            AccessibleObject.setAccessible( fields, true );

            for ( int i = 0; i < fields.length; i++ )
            {
                buf.append( "\t[" + fields[i].getName() + "=" +
                            fields[i].get( this ) + "], \n" );
            }
        }
        catch ( Exception e )
        {
            // ignored!
        }

        return buf.to
 String();
    }

    /**
     * Read the RollerConfig from a file, as specified by a String path.
     *
     * @param path
     *
     * @return
     */
    public static OldRollerConfig readConfig( String path )
    {
        InputStream in = null;

        try
        {
            in = new FileInputStream( path );
            return OldRollerConfig.readConfig( in );
        }
        catch ( Exception e )
        {
            System.out.println( "Exception reading RollerConfig: " +
                                e.getMessage() );
        }
        finally
        {
            try
            {
                if ( in != null )
                {
                    in.close();
                }
            }

            catch ( java.io.IOException ioe )
            {
                System.err.println( "RollerConfig.writeConfig() unable to close InputStream" );
            }
        }

        return new OldRollerConfig();
    }

    /**
     * Read the RollerConfig f
 rom a file, as specified by an InputStream.
     *
     * @param in
     *
     * @return
     *
     * @throws RuntimeException
     */
    public static OldRollerConfig readConfig( InputStream in )
    {
        try
        {
            BeanReader reader = new BeanReader();
            reader.setDebug(99);
            reader.registerBeanClass( OldRollerConfig.class );
            return (OldRollerConfig) reader.parse( in );
        }

        catch ( IOException e )
        {
            throw new RuntimeException( "FATAL ERROR reading RollerConfig inputstream.",
                                        e );
        }

        catch ( SAXException e )
        {
            throw new RuntimeException( "FATAL ERROR parsing RollerConfig, file is corrupted?",
                                        e );
        }

        catch ( IntrospectionException e )
        {
            throw new RuntimeException( "FATAL ERROR introspecting RollerConfig bean.",
                        
                 e );
        }
    }

    /**
     * Write RollerConfig to file, as specified by a String path.
     *
     * @param path
     *
     * @throws RollerException
     */
    public void writeConfig( String path ) throws RollerException
    {
        FileOutputStream out = null;

        try
        {
            out = new FileOutputStream( path );
            writeConfig( out );
        }
        catch ( FileNotFoundException e )
        {
            throw new RollerException( "ERROR file not found: " + path, e );
        }
        finally
        {
            try
            {
                if ( out != null )
                {
                    out.close();
                }
            }
            catch ( java.io.IOException ioe )
            {
                System.err.println( "RollerConfig.writeConfig() unable to close OutputStream" );
            }
        }
    }

    /**
     * Write RollerConfig to file, as specified by an OutputStream.
     *
 
     * @param out
     *
     * @throws RollerException
     */
    public void writeConfig( OutputStream out ) throws RollerException
    {
        BeanWriter writer = new BeanWriter( out );
        writer.enablePrettyPrint();
        writer.setIndent( "    " );
        writer.setWriteIDs( false );

        try
        {
            writer.write( this );
        }
        catch ( IOException e )
        {
            throw new RollerException( "ERROR writing to roller-config.xml stream.",
                                       e );
        }
        catch ( SAXException e )
        {
            throw new RollerException( "ERROR writing to roller-config.xml stream.",
                                       e );
        }
        catch ( IntrospectionException e )
        {
            throw new RollerException( "ERROR introspecting RollerConfig bean.",
                                       e );
        }
    }

    /**
     * test stuff
     *
     * @param args
     */
  
   public static void main( String[] args )
    {
        String basedir = System.getProperty( "basedir" );
        String path = "build/roller/WEB-INF/roller-config.xml";
        path = new java.io.File( basedir, path ).getAbsolutePath();
        if ( ( args.length > 0 ) && args[0].equals( "read" ) )
        {
            OldRollerConfig.readConfig( path );
        }
        else if ( ( args.length > 0 ) && args[0].equals( "write" ) ) // write
        {
            path = "build/roller/WEB-INF/roller-config-test.xml";
            path = new java.io.File( basedir, path ).getAbsolutePath();
            OldRollerConfig bean = new OldRollerConfig();

            try
            {
                bean.writeConfig( path );
            }
            catch ( Exception e )
            {
                mLogger.error( "Unexpected exception", e );
            }
        }
        else // both
        {
            OldRollerConfig bean = OldRollerConfig.readConfig( path );
            pa
 th = "build/roller/WEB-INF/roller-config-test.xml";
            path = new java.io.File( basedir, path ).getAbsolutePath();

            try
            {
                bean.writeConfig( path );
            }
            catch ( Exception e )
            {
                mLogger.error( "Unexpected exception", e );
            }
        }

        System.out.println( "RollerConfig.main completed" );
    }
}
\ No newline at end of file

Added: incubator/roller/trunk/src/org/apache/roller/util/PojoUtil.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/util/PojoUtil.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/util/PojoUtil.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/util/PojoUtil.java Mon May  1 15:23:02 2006
@@ -0,0 +1,43 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+*  contributor license agreements.  The ASF licenses this file to You
+* under the Apache License, Version 2.0 (the "License"); you may not
+* use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.  For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+package org.apache.roller.util;
+
+/**
+ * This class contains helper methods
+ * for Roller pojos (only?)
+**/
+public abstract class PojoUtil
+{
+    public static boolean equals(boolean lEquals, Object a, Object b)
+    {
+        if (a == null)
+        {
+            lEquals = lEquals && (b == null);
+        }
+        else
+        {
+            lEquals = lEquals && a.equals(b);
+        }
+        return lEquals;
+    }
+
+    public static int addHashCode(int result, Object a)
+    {
+		return (37 * result) + ((a != null) ? a.hashCode() : 0);
+	}
+}
\ No newline at end of file

Added: incubator/roller/trunk/src/org/apache/roller/util/PropertyExpander.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/util/PropertyExpander.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/util/PropertyExpander.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/util/PropertyExpander.java Mon May  1 15:23:02 2006
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  The ASF licenses this file to You
+ * under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+
+package org.apache.roller.util;
+
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Property expansion utility.  This utility provides static methods to expand properties appearing in strings.
+ *
+ * @author <a href="mailto:anil@busybuddha.org">Anil Gangolli</a> (Portions based on code from David Graff submitted for
+ *         ROL-613)
+ * @since Roller 1.3
+ */
+public class PropertyExpander
+{
+    private PropertyExpander()
+    {
+    }
+
+    // The pattern for a system property.  Matches ${property.name}, with the interior matched reluctantly.
+    private static final Pattern EXPANSION_PATTERN =
+        Pattern.compile("(\\$\\{([^}]+?)\\})", java.util.regex.Pattern.MULTILINE);
+
+    /**
+     * Expand property expressions in the input.  Expands property expressions of the form <code>${propertyname}</code>
+     * in the input, replacing each such expression with the value associated to the respective key
+     * <code>propertyname</code> in the supplied map.  If for a given expression, the property is undefined (has null
+     * value) in the map supplied, that expression is left unexpanded in the resulting string.
+     * <p/>
+     * Note that expansion is not recursive.  If the value of one property contains another expression, the expression
+     * appearing in the value will not be expanded further.
+     *
+     * @param input the input string.  This may be null, in which case null is returned.
+     * @param props the map of property values to use for expansion.  This map should have <code>String</code> keys and
+     *              <code>String</code> values.  Any object of class {@link java.util.Properties} works here, as will
+     *              other implementations of such maps.
+     * @return the result of replacing property expressions with the values of the corresponding properties from the
+     *         supplied property map, null if the input string is null.
+     */
+    public static String expandProperties(String input, Map props)
+    {
+        if (input == null) return null;
+
+        Matcher matcher = EXPANSION_PATTERN.matcher(input);
+
+        StringBuffer expanded = new StringBuffer(input.length());
+        while (matcher.find())
+        {
+            String propName = matcher.group(2);
+            String value = (String) props.get(propName);
+            // if no value is found, use a value equal to the original expression
+            if (value == null) value = matcher.group(0);
+            // Fake a literal replacement since Matcher.quoteReplacement() is not present in 1.4.
+            matcher.appendReplacement(expanded, "");
+            expanded.append(value);
+        }
+        matcher.appendTail(expanded);
+
+        return expanded.toString();
+    }
+
+    /**
+     * Expand system properties in the input string.  This is equivalent to calling <code>expandProperties(input,
+     * System.getProperties())</code>.
+     *
+     * @param input
+     * @return the result of replacing property expressions with the values of the corresponding system properties.
+     * @see System#getProperties()
+     */
+    public static String expandSystemProperties(String input)
+    {
+        return expandProperties(input, System.getProperties());
+    }
+}

Added: incubator/roller/trunk/src/org/apache/roller/util/RandomGUID.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/util/RandomGUID.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/util/RandomGUID.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/util/RandomGUID.java Mon May  1 15:23:02 2006
@@ -0,0 +1,247 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+*  contributor license agreements.  The ASF licenses this file to You
+* under the Apache License, Version 2.0 (the "License"); you may not
+* use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.  For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+package org.apache.roller.util;
+/*
+ * RandomGUID from http://www.javaexchange.com/aboutRandomGUID.html
+ * @version 1.2.1 11/05/02
+ * @author Marc A. Mnich
+ *
+ * From www.JavaExchange.com, Open Software licensing
+ *
+ * 11/05/02 -- Performance enhancement from Mike Dubman.  
+ *             Moved InetAddr.getLocal to static block.  Mike has measured
+ *             a 10 fold improvement in run time.
+ * 01/29/02 -- Bug fix: Improper seeding of nonsecure Random object
+ *             caused duplicate GUIDs to be produced.  Random object
+ *             is now only created once per JVM.
+ * 01/19/02 -- Modified random seeding and added new constructor
+ *             to allow secure random feature.
+ * 01/14/02 -- Added random function seeding with JVM run time
+ *
+ */
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.Random;
+
+/*
+ * In the multitude of java GUID generators, I found none that
+ * guaranteed randomness.  GUIDs are guaranteed to be globally unique
+ * by using ethernet MACs, IP addresses, time elements, and sequential
+ * numbers.  GUIDs are not expected to be random and most often are
+ * easy/possible to guess given a sample from a given generator.
+ * SQL Server, for example generates GUID that are unique but
+ * sequencial within a given instance.
+ *
+ * GUIDs can be used as security devices to hide things such as
+ * files within a filesystem where listings are unavailable (e.g. files
+ * that are served up from a Web server with indexing turned off).
+ * This may be desireable in cases where standard authentication is not
+ * appropriate. In this scenario, the RandomGUIDs are used as directories.
+ * Another example is the use of GUIDs for primary keys in a database
+ * where you want to ensure that the keys are secret.  Random GUIDs can
+ * then be used in a URL to prevent hackers (or users) from accessing
+ * records by guessing or simply by incrementing sequential numbers.
+ *
+ * There are many other possiblities of using GUIDs in the realm of
+ * security and encryption where the element of randomness is important.
+ * This class was written for these purposes but can also be used as a
+ * general purpose GUID generator as well.
+ *
+ * RandomGUID generates truly random GUIDs by using the system's
+ * IP address (name/IP), system time in milliseconds (as an integer),
+ * and a very large random number joined together in a single String
+ * that is passed through an MD5 hash.  The IP address and system time
+ * make the MD5 seed globally unique and the random number guarantees
+ * that the generated GUIDs will have no discernable pattern and
+ * cannot be guessed given any number of previously generated GUIDs.
+ * It is generally not possible to access the seed information (IP, time,
+ * random number) from the resulting GUIDs as the MD5 hash algorithm
+ * provides one way encryption.
+ *
+ * ----> Security of RandomGUID: <-----
+ * RandomGUID can be called one of two ways -- with the basic java Random
+ * number generator or a cryptographically strong random generator
+ * (SecureRandom).  The choice is offered because the secure random
+ * generator takes about 3.5 times longer to generate its random numbers
+ * and this performance hit may not be worth the added security
+ * especially considering the basic generator is seeded with a
+ * cryptographically strong random seed.
+ *
+ * Seeding the basic generator in this way effectively decouples
+ * the random numbers from the time component making it virtually impossible
+ * to predict the random number component even if one had absolute knowledge
+ * of the System time.  Thanks to Ashutosh Narhari for the suggestion
+ * of using the static method to prime the basic random generator.
+ *
+ * Using the secure random option, this class compies with the statistical
+ * random number generator tests specified in FIPS 140-2, Security
+ * Requirements for Cryptographic Modules, secition 4.9.1.
+ *
+ * I converted all the pieces of the seed to a String before handing
+ * it over to the MD5 hash so that you could print it out to make
+ * sure it contains the data you expect to see and to give a nice
+ * warm fuzzy.  If you need better performance, you may want to stick
+ * to byte[] arrays.
+ *
+ * I believe that it is important that the algorithm for
+ * generating random GUIDs be open for inspection and modification.
+ * This class is free for all uses.
+ *
+ *
+ * - Marc
+ */
+
+public class RandomGUID extends Object {
+
+    public String valueBeforeMD5 = "";
+    public String valueAfterMD5 = "";
+    private static Random myRand;
+    private static SecureRandom mySecureRand;
+
+    private static String s_id;
+
+    /*
+     * Static block to take care of one time secureRandom seed.
+     * It takes a few seconds to initialize SecureRandom.  You might
+     * want to consider removing this static block or replacing
+     * it with a "time since first loaded" seed to reduce this time.
+     * This block will run only once per JVM instance.
+     */
+
+    static {
+        mySecureRand = new SecureRandom();
+        long secureInitializer = mySecureRand.nextLong();
+        myRand = new Random(secureInitializer);
+        try {
+            s_id = InetAddress.getLocalHost().toString();
+        } catch (UnknownHostException e) {
+            e.printStackTrace();
+        }
+
+    }
+
+
+    /*
+     * Default constructor.  With no specification of security option,
+     * this constructor defaults to lower security, high performance.
+     */
+    public RandomGUID() {
+        getRandomGUID(false);
+    }
+
+    /*
+     * Constructor with security option.  Setting secure true
+     * enables each random number generated to be cryptographically
+     * strong.  Secure false defaults to the standard Random function seeded
+     * with a single cryptographically strong random number.
+     */
+    public RandomGUID(boolean secure) {
+        getRandomGUID(secure);
+    }
+
+    /*
+     * Method to generate the random GUID
+     */
+    private void getRandomGUID(boolean secure) {
+        MessageDigest md5 = null;
+        StringBuffer sbValueBeforeMD5 = new StringBuffer();
+
+        try {
+            md5 = MessageDigest.getInstance("MD5");
+        } catch (NoSuchAlgorithmException e) {
+            System.out.println("Error: " + e);
+        }
+
+        try {
+            long time = System.currentTimeMillis();
+            long rand = 0;
+
+            if (secure) {
+                rand = mySecureRand.nextLong();
+            } else {
+                rand = myRand.nextLong();
+            }
+
+            // This StringBuffer can be a long as you need; the MD5
+            // hash will always return 128 bits.  You can change
+            // the seed to include anything you want here.
+            // You could even stream a file through the MD5 making
+            // the odds of guessing it at least as great as that
+            // of guessing the contents of the file!
+            sbValueBeforeMD5.append(s_id);
+            sbValueBeforeMD5.append(":");
+            sbValueBeforeMD5.append(Long.toString(time));
+            sbValueBeforeMD5.append(":");
+            sbValueBeforeMD5.append(Long.toString(rand));
+
+            valueBeforeMD5 = sbValueBeforeMD5.toString();
+            md5.update(valueBeforeMD5.getBytes());
+
+            byte[] array = md5.digest();
+            StringBuffer sb = new StringBuffer();
+            for (int j = 0; j < array.length; ++j) {
+                int b = array[j] & 0xFF;
+                if (b < 0x10) sb.append('0');
+                sb.append(Integer.toHexString(b));
+            }
+
+            valueAfterMD5 = sb.toString();
+
+        } catch (Exception e) {
+            System.out.println("Error:" + e);
+        }
+    }
+
+
+    /*
+     * Convert to the standard format for GUID
+     * (Useful for SQL Server UniqueIdentifiers, etc.)
+     * Example: C2FEEEAC-CFCD-11D1-8B05-00600806D9B6
+     */
+    public String toString() {
+        String raw = valueAfterMD5.toUpperCase();
+        StringBuffer sb = new StringBuffer();
+        sb.append(raw.substring(0, 8));
+        sb.append("-");
+        sb.append(raw.substring(8, 12));
+        sb.append("-");
+        sb.append(raw.substring(12, 16));
+        sb.append("-");
+        sb.append(raw.substring(16, 20));
+        sb.append("-");
+        sb.append(raw.substring(20));
+
+        return sb.toString();
+    }
+
+    /*
+     * Demonstraton and self test of class
+     */
+    public static void main(String args[]) {
+        for (int i=0; i< 100; i++) {
+            RandomGUID myGUID = new RandomGUID();
+            System.out.println("Seeding String=" + myGUID.valueBeforeMD5);
+            System.out.println("rawGUID=" + myGUID.valueAfterMD5);
+            System.out.println("RandomGUID=" + myGUID.toString());
+        }
+    }
+}

Added: incubator/roller/trunk/src/org/apache/roller/util/RegexUtil.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/util/RegexUtil.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/util/RegexUtil.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/util/RegexUtil.java Mon May  1 15:23:02 2006
@@ -0,0 +1,49 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+*  contributor license agreements.  The ASF licenses this file to You
+* under the Apache License, Version 2.0 (the "License"); you may not
+* use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.  For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+/*
+ * Created on Nov 8, 2003
+ *
+ */
+package org.apache.roller.util;
+import org.apache.commons.codec.binary.Hex;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+

/**
 * @author lance
 */
public class RegexUtil
{
    public static final Pattern mailtoPattern = Pattern.compile("mailto:([a-zA-Z0-9\\.]+@[a-zA-Z0-9\\.]+\\.[a-zA-Z0-9]+)");
    public static final Pattern emailPattern = Pattern.compile("\\b[a-zA-Z0-9\\.]+(@)([a-zA-Z0-9\\.]+)(\\.)([a-zA-Z0-9]+)\\b");
    
    public static String encodeEmail(String str)
    {
        // obfuscate mailto's: turns them into hex encoded,
        // so that browsers can still understand the mailto link
        Matcher mailtoMatch = mailtoPattern.matcher(str);
        while (mailtoMatch.find())
        {
            String email = mailtoMatch.group(1);
            //System.out.println("email=" + email);
            String hexed = encode(email);
            str = str.replaceFirst("mailto:"+email, "mailto:"+hexed);
        }
        
        return obfuscateEmail(str);
    }

    /**
     * obfuscate plaintext emails: makes them
     * "human-readable" - still too easy for
     * machines to pars
 e however.
     * 
     * @param str
     * @return
     */
    public static String obfuscateEmail(String str)
    {
        Matcher emailMatch = emailPattern.matcher(str);
        while (emailMatch.find())
        {
            String at = emailMatch.group(1);
            //System.out.println("at=" + at);
            str = str.replaceFirst(at, "-AT-");
            
            String dot = emailMatch.group(2) + emailMatch.group(3) + emailMatch.group(4);
            String newDot = emailMatch.group(2) + "-DOT-" + emailMatch.group(4);
            //System.out.println("dot=" + dot);
            str = str.replaceFirst(dot, newDot);
        }
        return str;
    }
+    
+    /**
+     * Return the specified match "groups" from the pattern.
+     * For each group matched a String will be entered in the ArrayList.
+     * 
+     * @param pattern The Pattern to use.
+     * @param match The String to match against.
+     * @param group The group number to return in case of a match.
+     * @return
+     */
+    public static ArrayList getMatches(Pattern pattern, String match, int group)
+    {
+        ArrayList matches = new ArrayList();
+        Matcher matcher = pattern.matcher(match);
+        while (matcher.find()) 
+        {
+            matches.add( matcher.group(group) );
+        }
+        return matches;
+    }

	/**
     * Thanks to the folks at Blojsom (http://sf.net/projects/blojsom)
     * for showing me what I was doing wrong with the Hex class.
     * 
	 * @param email
	 * @return
	 */
	public static String encode(String email)
	{
        StringBuffer result = new StringBuffer();
        try {
            char[] hexString = Hex.encodeHex(email.getBytes("UTF8"));
            for (int i = 0; i < hexString.length; i++) {
                if (i % 2 == 0) {
                    result.append("%");
                }
                result.append(hexString[i]);
            }
        } catch (UnsupportedEncodingException e) {
            return email;
        }

        return result.toString();
	}
}
\ No newline at end of file

Added: incubator/roller/trunk/src/org/apache/roller/util/RollerMessages.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/util/RollerMessages.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/util/RollerMessages.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/util/RollerMessages.java Mon May  1 15:23:02 2006
@@ -0,0 +1,121 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+*  contributor license agreements.  The ASF licenses this file to You
+* under the Apache License, Version 2.0 (the "License"); you may not
+* use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.  For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+package org.apache.roller.util;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Holds collection of error messages and collection of status messages.
+ * @author David M Johnson
+ */
+public class RollerMessages
+{
+    private List mErrors = new ArrayList();
+    private List mMessages = new ArrayList();
+    
+    public RollerMessages() 
+    {
+    }
+    public void addError(String key)
+    {
+        mErrors.add(new RollerMessage(key, null));
+    }
+    public void addError(String key, String arg)
+    {
+        mErrors.add(new RollerMessage(key, new String[]{arg}));
+    }
+    public void addError(String key, String[] args)
+    {
+        mErrors.add(new RollerMessage(key, args));
+    }
+    public void addMessage(String key)
+    {
+        mMessages.add(new RollerMessage(key, null));
+    }
+    public void addMessage(String key, String arg)
+    {
+        mMessages.add(new RollerMessage(key, new String[]{arg}));
+    }
+    public void addMessage(String key, String[] args)
+    {
+        mMessages.add(new RollerMessage(key, args));
+    }
+    public Iterator getErrors()
+    {
+        return mErrors.iterator();
+    }
+    public Iterator getMessages()
+    {
+        return mMessages.iterator();
+    }
+    public int getErrorCount() 
+    {
+        return mErrors.size();
+    }
+    public int getMessageCount() 
+    {
+        return mMessages.size();
+    }
+    public String toString() 
+    {
+        StringBuffer sb = new StringBuffer();
+        Iterator msgs = mMessages.iterator();
+        while (msgs.hasNext())
+        {
+            RollerMessage msg = (RollerMessage) msgs.next();
+            sb.append(msg.getKey());
+            sb.append(" : ");
+        }
+        Iterator errs = mErrors.iterator();
+        while (errs.hasNext())
+        {
+            RollerMessage msg = (RollerMessage) errs.next();
+            sb.append(msg.getKey());
+            sb.append(" : ");
+        }
+        return sb.toString();
+    }
+    public static class RollerMessage
+    {
+        private String mKey;
+        private String[] mArgs;
+        public RollerMessage(String key, String[] args)
+        {
+            mKey = key;
+            mArgs = args;
+        }
+        public String[] getArgs()
+        {
+            return mArgs;
+        }
+        public void setArgs(String[] args)
+        {
+            mArgs = args;
+        }
+        public String getKey()
+        {
+            return mKey;
+        }
+        public void setKey(String key)
+        {
+            mKey = key;
+        }
+    }
+}

Added: incubator/roller/trunk/src/org/apache/roller/util/SpamChecker.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/util/SpamChecker.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/util/SpamChecker.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/util/SpamChecker.java Mon May  1 15:23:02 2006
@@ -0,0 +1,91 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+*  contributor license agreements.  The ASF licenses this file to You
+* under the Apache License, Version 2.0 (the "License"); you may not
+* use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.  For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+package org.apache.roller.util;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+import java.util.regex.Pattern;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.roller.config.RollerConfig;
+import org.apache.roller.config.RollerRuntimeConfig;
+import org.apache.roller.pojos.CommentData;
+import org.apache.roller.pojos.RefererData;
+import org.apache.roller.pojos.WebsiteData;
+
+/**
+ * Checks comment, trackbacks and referrers for spam.
+ * @author Lance Lavandowska
+ * @author Dave Johnson
+ */
+public class SpamChecker { 
+    private static Log mLogger = LogFactory.getLog(SpamChecker.class);
+    
+    /** Test comment, applying all blacklists, if configured */
+    public static boolean checkComment(CommentData comment) {
+        if (RollerConfig.getBooleanProperty("site.blacklist.enable.comments")) {
+            return testComment(comment);
+        }
+        return false;
+    }
+    
+    /** Test trackback comment, applying all blacklists, if configured */
+    public static boolean checkTrackback(CommentData comment) {
+        if (RollerConfig.getBooleanProperty("site.blacklist.enable.trackbacks")) {
+            return testComment(comment);
+        }
+        return false;
+    }
+
+    /** Test referrer URL, applying blacklist and website blacklist only if configured */
+    public static boolean checkReferrer(WebsiteData website, String referrerURL) {
+        if (RollerConfig.getBooleanProperty("site.blacklist.enable.referrers")) {
+            List stringRules = new ArrayList();
+            List regexRules = new ArrayList();
+            Blacklist.populateSpamRules(
+                website.getBlacklist(), stringRules, regexRules, null);
+            if (RollerRuntimeConfig.getProperty("spam.blacklist") != null) {
+                Blacklist.populateSpamRules(
+                    RollerRuntimeConfig.getProperty("spam.blacklist"), stringRules, regexRules, null);
+            }
+            return Blacklist.matchesRulesOnly(referrerURL, stringRules, regexRules);
+        }
+        return false;
+    }
+
+    /** Test comment against built in blacklist, site blacklist and website blacklist */
+    private static boolean testComment(CommentData c) {
+        boolean ret = false;
+        List stringRules = new ArrayList();
+        List regexRules = new ArrayList();
+        WebsiteData website = c.getWeblogEntry().getWebsite();
+        Blacklist.populateSpamRules(
+            website.getBlacklist(), stringRules, regexRules, 
+            RollerRuntimeConfig.getProperty("spam.blacklist"));
+        Blacklist blacklist = Blacklist.getBlacklist();
+        if (   blacklist.isBlacklisted(c.getUrl(),     stringRules, regexRules)
+            || blacklist.isBlacklisted(c.getEmail(),   stringRules, regexRules)
+            || blacklist.isBlacklisted(c.getName(),    stringRules, regexRules)
+            || blacklist.isBlacklisted(c.getContent(), stringRules, regexRules)) {
+            ret = true;
+        }
+        return ret;
+    }        
+}
+

Added: incubator/roller/trunk/src/org/apache/roller/util/StringUtils.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/util/StringUtils.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/util/StringUtils.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/util/StringUtils.java Mon May  1 15:23:02 2006
@@ -0,0 +1,73 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+*  contributor license agreements.  The ASF licenses this file to You
+* under the Apache License, Version 2.0 (the "License"); you may not
+* use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.  For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+/*
+ * Created on Jun 3, 2004
+ */
+package org.apache.roller.util;
+
+/**
+ * @author lance.lavandowska
+ */
+public class StringUtils
+{
+    public static boolean isEmpty(String str)
+    {
+        if (str == null) return true;
+        return "".equals(str.trim());
+    }
+    
+    public static boolean isNotEmpty(String str)
+    {
+        return !isEmpty(str);
+    }
+    
+    public static String[] split(String str1, String str2)
+    {
+       return org.apache.commons.lang.StringUtils.split(str1, str2);
+    }
+    
+    public static String replace(String src, String target, String rWith)
+    {
+        return org.apache.commons.lang.StringUtils.replace(src, target, rWith);
+    }
+    
+    public static String replace(String src, String target, String rWith, int maxCount)
+    {
+        return org.apache.commons.lang.StringUtils.replace(src, target, rWith, maxCount);
+    }
+    
+    public static boolean equals(String str1, String str2) 
+    {
+        return org.apache.commons.lang.StringUtils.equals(str1, str2);
+    }
+    
+    public static boolean isAlphanumeric(String str)
+    {
+        return org.apache.commons.lang.StringUtils.isAlphanumeric(str);
+    }
+    
+    public static String[] stripAll(String[] strs) 
+    {
+        return org.apache.commons.lang.StringUtils.stripAll(strs);
+    }
+    
+    public static String left(String str, int length)
+    {
+        return org.apache.commons.lang.StringUtils.left(str, length);
+    }
+}

Added: incubator/roller/trunk/src/org/apache/roller/util/Technorati.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/util/Technorati.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/util/Technorati.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/util/Technorati.java Mon May  1 15:23:02 2006
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2005 David M Johnson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.roller.util;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import org.jdom.Document;
+import org.jdom.Element;
+import org.jdom.input.SAXBuilder;
+import org.jdom.xpath.XPath;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/** Simple Technorati wrapper for Java. @author David M Johnson */
+public class Technorati {
+    private String mKey = null;
+
+    public Technorati(String key) {
+        mKey = key;
+    }
+    
+    public Technorati(String key, String proxy, int proxyPort) {
+        this(key);
+        System.setProperty("proxySet", "true");
+        System.setProperty("http.proxyHost", proxy);
+        System.setProperty("http.proxyPort", Integer.toString(proxyPort)); 
+    }
+
+    /** Looks for key in classpath using "/technorati.license" */
+    public Technorati() throws IOException {
+        InputStream is = getClass().getResourceAsStream("/technorati.license");
+        BufferedReader br = new BufferedReader(new InputStreamReader(is));
+        mKey = br.readLine();       
+    }
+
+    public Technorati(String proxy, int proxyPort) throws Exception {
+        this();
+        System.setProperty("proxySet", "true");
+        System.setProperty("http.proxyHost", proxy);
+        System.setProperty("http.proxyPort", Integer.toString(proxyPort)); 
+    }
+    
+    public Result getLinkCosmos(String url) throws Exception {
+        return new Result("http://api.technorati.com/cosmos",url,"links");
+    }
+
+    public Result getWeblogCosmos(String url) throws Exception {
+        return new Result("http://api.technorati.com/cosmos",url,"weblog");
+    }
+
+    public Result getBloginfo(String url) throws Exception {
+        return new Result("http://api.technorati.com/bloginfo",url,null);
+    }
+
+    public Result getOutbound(String url) throws Exception {
+        return new Result("http://api.technorati.com/outbound",url,null);
+    }
+
+    /** Technorati result with header info and collection of weblog items */
+    public class Result {
+        private Weblog mWeblog = null;
+        private Collection mWeblogs = new ArrayList();
+
+        protected Result(String apiUrl, String url, String type) throws Exception {
+            Map args = new HashMap();
+            args.put("url", url);
+            args.put("type", type);
+            args.put("format", "xml");
+            args.put("key", mKey);
+
+            int start = 0;
+            boolean repeat = true;
+            XPath itemsPath = XPath.newInstance("/tapi/document/item/weblog");            
+
+            while (repeat) {
+                 Document doc = getRawResults(apiUrl,args);               
+                Element elem = doc.getRootElement();                          
+                String error = getString(elem,"/tapi/document/result/error");
+                if ( error != null ) throw new Exception(error);
+                if (mWeblog == null) {
+                    XPath p = XPath.newInstance("/tapi/document/result/weblog");
+                    Element w = (Element) p.selectSingleNode(doc);
+                    mWeblog = new Weblog(w);
+                }
+                int count=0;
+                Iterator iter = itemsPath.selectNodes(doc).iterator();
+                while (iter.hasNext()) {
+                    Element element = (Element) iter.next();
+                    Weblog w = new Weblog(element);
+                    mWeblogs.add(w);
+                    count++;
+                }
+                if ( count < 20 ) { 
+                    repeat = false;
+                }
+                else {
+                    start += 20;
+                    args.put("start",new Integer(start));
+                }
+            }
+        }
+
+        public Weblog getWeblog() {return mWeblog;}
+        public Collection getWeblogs() {return mWeblogs;}
+    }
+
+    /** Technorati weblog representation */
+    public class Weblog {
+        private String mName = null;
+        private String mUrl = null;
+        private String mRssurl = null;
+        private String mLastupdate = null;
+        private String mNearestpermalink = null;
+        private String mExcerpt = null;
+        private int mInboundlinks = 0;
+        private int mInboundblogs = 0;
+
+        public Weblog(Element elem) throws Exception {
+            mName = getString(elem,"name");
+            mUrl = getString(elem,"url");
+            mRssurl = getString(elem,"rssurl");
+            mLastupdate = getString(elem,"lastupdate");
+            mNearestpermalink = getString(elem,"nearestpermalink");
+            mExcerpt = getString(elem,"excerpt");
+            try { 
+                mInboundlinks = getInt(elem,"inboundlinks");
+            } catch (Exception ignored) {}
+            try { 
+                mInboundblogs = getInt(elem,"inboundblogs");
+            } catch (Exception ignored) {}
+        }
+
+        public String getName() {return mName;}
+        public String getUrl() {return mUrl;}
+        public String getRssurl() {return mRssurl;}
+        public int getInboundblogs() {return mInboundblogs;}
+        public int getInboundlinks() {return mInboundlinks;}
+        public String getLastupdate() {return mLastupdate;}
+        public String getNearestpermalink() {return mNearestpermalink;}
+        public String getExcerpt() {return mExcerpt;}
+    }
+    
+    protected Document getRawResults(String urlString, Map args) throws Exception {
+        int count = 0;
+        Iterator keys = args.keySet().iterator();
+        while (keys.hasNext()) {
+            String sep = count++==0 ? "?" : "&";
+            String name = (String)keys.next();
+            if ( args.get(name) != null ) {
+                urlString += sep + name + "=" + args.get(name);                         
+            }
+        }
+        URL url = new URL(urlString);
+        URLConnection conn = url.openConnection();
+        conn.connect();
+        SAXBuilder builder = new SAXBuilder();
+        return builder.build(conn.getInputStream());
+    }
+    
+    protected String getString(Element elem, String path) throws Exception {
+        XPath xpath = XPath.newInstance(path);
+        Element e = (Element)xpath.selectSingleNode(elem);
+        return e!=null ? e.getText() : null;
+    }
+    
+    protected int getInt(Element elem, String path) throws Exception {
+        XPath xpath = XPath.newInstance(path);
+        Element e = (Element)xpath.selectSingleNode(elem);
+        return e!=null ? Integer.parseInt(e.getText()) : 0;
+    }
+}

Added: incubator/roller/trunk/src/org/apache/roller/util/TimeZoneComparator.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/util/TimeZoneComparator.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/util/TimeZoneComparator.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/util/TimeZoneComparator.java Mon May  1 15:23:02 2006
@@ -0,0 +1,19 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+*  contributor license agreements.  The ASF licenses this file to You
+* under the Apache License, Version 2.0 (the "License"); you may not
+* use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.  For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+package org.apache.roller.util;
+import java.util.TimeZone;
import java.util.Comparator;
import java.io.Serializable;

public class TimeZoneComparator implements Comparator, Serializable
{
    public int compare(Object obj1, Object obj2)
    {
        if (obj1 instanceof TimeZone && obj2 instanceof TimeZone)
        {
            TimeZone zone1 = (TimeZone)obj1;
            TimeZone zone2 = (TimeZone)obj2;
            int compName = zone1.getDisplayName().compareTo(zone2.getDisplayName());
            if (compName == 0)
            {
				return zone1.getID().compareTo(zone2.getID());
			}
            return compName;
        }
        return 0;
    }

    /* Do Comparators need to implement equals()? -Lance
    public boolean equals(Object obj)
    {
        if (obj instanceof TimeZoneComparator)
        {
            if (obj.equals(this)) return true;
        }
        return false;
    }
    */
}
\ No newline at end of file