/*------------------------------------------------------------------------------- 
 * JFormMail.java
 *-------------------------------------------------------------------------------
 *-[JFormMail]
 * Author		 : Sunil Amber
 * First Release : 17th May 2002
 * Version ID	 : $JFormMail, v1.1, 22/06/2003, 18:00:00 Sunil.K.S$
 * JFormMail URL : http://www.sunilamber.com/ssm/jformmail/
 * Mirror        : http://thunder.prohosting.com/~manufc/jformmail/
 *
 * JFormMail is a universal WWW form to E-mail gateway.
 * It is similar to Matt's popular FormMail.pl script. 
 * The only difference is that mine is written in Java.
 *
 * Please see changes and features in Changelog.txt
 *
 *-------------------------------------------------------------------------------
 * -[Copyright / Redistribution / Terms Of Usage]-
 * Copyright 2002-2003 Sunil Amber <sunilamber[AT]hotmail.com>
 * Homepage: http://www.sunilamber.com/
 *
 * This software is free as long the above mentioned copyright
 * and comments are kept intact. By using this software you agree 
 * to indemnify Sunil Amber from any liability that might arise from its use.
 * 
 * Selling the code for this program without prior written consent is
 * strictly forbidden.
 *                                                                            
 * Obtain permission before redistributing this software over the Internet or 
 * in any other medium.	In all cases copyright and header must remain intact.
 *-------------------------------------------------------------------------------
 */
package manufc;

import java.io.*;
import java.util.*;
import java.net.*;
import java.text.*;
import javax.servlet.*;
import java.util.regex.*;
import javax.servlet.http.*;

// Mail component classes
import javax.mail.*;
import javax.mail.internet.*;
import javax.activation.*;
import java.util.Properties;

public class JFormMail extends HttpServlet 
{
	String _load_config_error_ = null;
	final String _config_file_ = "JFormMail.ini";
	final String _file_separator_ = System.getProperty("file.separator");
	final boolean _debug_ = false;

	String _CONFIG_SMTP_HOST_;
	Vector _CONFIG_REFERERS_ = new Vector();
	Vector _CONFIG_ENV_ = new Vector();
	Vector _CONFIG_RECIPIENTS_ = new Vector();
	
	//Ver 1.1: Implemented a C like data structure encapsulated in an inner class
	//Reference to this class is pass to all methods requring access to its variables.
	class Data
	{	
		protected String timeStamp;
		protected Hashtable safeFormConfig, formConfig, form, env;
		protected Vector formConfigRequired, formConfigEnvReport, formConfigPrintConfig, formConfigRecipients;
		protected Vector fieldOrder;

		protected HttpServletResponse response;
		protected HttpServletRequest request;
	};

	public void init(ServletConfig config)
		throws ServletException
	{		
		super.init(config);

		try
		{	
			Properties props = new Properties();
			props.load(new FileInputStream(new File("/members/h6N59JFntj5iUKHBLhmB972ISghNVxrn"+_file_separator_+_config_file_)));
			
			// Get the SMTP Host value. Assign default if value not provided.
			if (props.getProperty("smtp.host") != null & !props.getProperty("smtp.host").equals(""))
				_CONFIG_SMTP_HOST_ = props.getProperty("smtp.host");
			else
				_CONFIG_SMTP_HOST_ = "127.0.0.1";
					
			// Get the valid referers list.
			if (props.getProperty("valid.referers") != null & !props.getProperty("valid.referers").equals(""))
			{
				StringTokenizer st = new StringTokenizer(props.getProperty("valid.referers"),",");
				while (st.hasMoreTokens()) {
				  _CONFIG_REFERERS_.add(st.nextToken().trim());
				}
			}
			
			// Get the allowed environmental variables list.
			if (props.getProperty("valid.env") != null & !props.getProperty("valid.env").equals(""))
			{
				StringTokenizer st = new StringTokenizer(props.getProperty("valid.env"),",");
				while (st.hasMoreTokens()) {
				  _CONFIG_ENV_.add(st.nextToken().trim());
				}
			}
			
			// Get the allowed ricipients list.
			if (props.getProperty("valid.recipients") != null & !props.getProperty("valid.recipients").equals(""))
			{
				StringTokenizer st = new StringTokenizer(props.getProperty("valid.recipients"),",");
				while (st.hasMoreTokens()) {
				  _CONFIG_RECIPIENTS_.add(st.nextToken().trim());
				}
			}
		}
		catch (FileNotFoundException fnfex)
		{
			_load_config_error_ = "Error loading " + _config_file_ + " file.";
			if (_debug_) fnfex.printStackTrace();
		}
		catch (Exception ex)
		{
			_load_config_error_ = "Unknown error: " + ex.getMessage();
			if (_debug_) ex.printStackTrace();
		}
	}

	public void doGet(HttpServletRequest request, HttpServletResponse response)
		throws IOException, ServletException
	{	
		// New instance of Data class called for evey request.
		Data _data_ = new Data();
		
		// Linking the request and response variables to global objects for 
		// later reference.
		_data_.response = response;
		_data_.request = request;

		PrintWriter out = response.getWriter();

		if (_load_config_error_ != null)
		{
			response.setContentType("text/html");
			out.println("There was an error initializing the configuration file "+_config_file_+"<br>");
			out.println(_load_config_error_);
		}
		else
		{
			try
			{    
				//Check Referer. Throw exception if check failed.
				checkReferer(_data_);

				//Retrieve Date/Time stamp for later use. 
				SimpleDateFormat dateFormat = new SimpleDateFormat("EEEE, MMM d, yyyy 'at' HH:mm:ss Z");
				_data_.timeStamp = dateFormat.format(new Date());
			
				//Parse Form Contents
				parseForm(_data_);

				//Check Required Fields
				checkForm(_data_);

				//Send E-Mail
				sendEmail(_data_);

				//Return HTML Page or Redirect User
				returnHtml(_data_);
			}
			catch (Exception e)
			{
				response.setContentType("text/html");
				out.println(e.getMessage());
				if (_debug_) e.printStackTrace();
			}
		}
	}
 
	public void doPost(HttpServletRequest request, HttpServletResponse response)
		throws IOException, ServletException
	{	
		doGet(request,response);
	}

	private void checkReferer(Data _data_)
		throws Exception
	{
		String refererHost;
		boolean flawed = true;
		URL referer;
		
		try
		{
			referer = new URL(_data_.request.getHeader("Referer"));
			refererHost = referer.getHost();			
		}
		catch (MalformedURLException mue) { refererHost = "";}

		if (!(refererHost == null || refererHost.equals("")))
		{
			for (Enumeration e = _CONFIG_REFERERS_.elements(); e.hasMoreElements(); )
			{
				if (refererHost.equalsIgnoreCase((String)e.nextElement()))
				{
					flawed = false;
					break;
				}
			}
		}

		if (flawed)	
		{
			String errorInfo[] = {_data_.request.getHeader("Referer"),refererHost};
			throw new Exception(returnError(_data_,"bad_referer",errorInfo).toString());
		}
	}
	
	private void parseForm(Data _data_)
		throws Exception
	{
		String formElement, formEnvVariable;
		Vector formConfigEnvReport = new Vector();

		_data_.form = new Hashtable();
		_data_.formConfig = new Hashtable();

		_data_.fieldOrder = new Vector();
		_data_.formConfigRecipients = new Vector();
		_data_.formConfigRequired = new Vector();
		_data_.formConfigEnvReport = new Vector();
		_data_.formConfigPrintConfig = new Vector();

		// Define the configuration associative array. 
		_data_.formConfig.put("recipient","");		_data_.formConfig.put("subject","");
		_data_.formConfig.put("email","");			_data_.formConfig.put("realname","");
		_data_.formConfig.put("redirect","");		_data_.formConfig.put("bgcolor","");
		_data_.formConfig.put("background","");		_data_.formConfig.put("link_color","");
		_data_.formConfig.put("vlink_color","");	_data_.formConfig.put("text_color","");
		_data_.formConfig.put("alink_color","");	_data_.formConfig.put("title","");
		_data_.formConfig.put("sort","");			_data_.formConfig.put("print_config","");
		_data_.formConfig.put("required","");		_data_.formConfig.put("env_report","");	
		_data_.formConfig.put("return_link_title","");_data_.formConfig.put("return_link_url","");
		_data_.formConfig.put("print_blank_fields","");_data_.formConfig.put("missing_fields_redirect","");
	
		// If the field name is part of the "_data_.formConfig" table, the value of the field is
		// associated with the respective configuration variable.
		// Otherwise, all other field values are stored in a seperate variable.
		// Remove all leading & trailing spaces before storing values.
		for (Enumeration e = _data_.request.getParameterNames(); e.hasMoreElements(); )
		{
			formElement = (String)e.nextElement();

			if (_data_.formConfig.containsKey(formElement))
			{
				_data_.formConfig.put(formElement,_data_.request.getParameter(formElement).trim());
			}
			else
			{
				for (int i = 0; i<_data_.request.getParameterValues(formElement).length; i++)
				{
					//If the element already exist, just append it,
					if (_data_.form.get(formElement) != null && !_data_.form.get(formElement).equals(""))
					{
						_data_.form.put(formElement,_data_.form.get(formElement) + ", " + _data_.request.getParameterValues(formElement)[i].trim());
					}

					//Otherwise, put the value in a new hash element altogether.
					else
					{
						_data_.form.put(formElement,_data_.request.getParameterValues(formElement)[i].trim());
						_data_.fieldOrder.add(formElement);
					}
				}
			}
		}

		// Seperate the configuration variables and place them in vectors
		// Remove all leading and trailing whitespaces/lines.		

		// Parse the required list
		if (!_data_.formConfig.get("required").equals(""))
		{
			StringTokenizer st = new StringTokenizer((String)_data_.formConfig.get("required"),",");
			while (st.hasMoreTokens()) {
			  _data_.formConfigRequired.add(st.nextToken().trim());
			}
		}

		// Parse the env_report list
		if (!_data_.formConfig.get("env_report").equals(""))
		{
			StringTokenizer st = new StringTokenizer((String)_data_.formConfig.get("env_report"),",");
			while (st.hasMoreTokens()) {
			  formConfigEnvReport.add(st.nextToken().trim());
			}
			
			// Since, environemental variables are requested, initialize the _data_.env table.
			_data_.env = getEnvVariables(_data_.request);
		}

		// Parse the print_config list
		if (!_data_.formConfig.get("print_config").equals(""))
		{
			StringTokenizer st = new StringTokenizer((String)_data_.formConfig.get("print_config"),",");
			while (st.hasMoreTokens()) {
			  _data_.formConfigPrintConfig.add(st.nextToken().trim());
			}
		}

		// Parse the recipients' list
		if (!_data_.formConfig.get("recipient").equals(""))
		{
			StringTokenizer st = new StringTokenizer((String)_data_.formConfig.get("recipient"),",");
			while (st.hasMoreTokens()) {
				_data_.formConfigRecipients.add(new InternetAddress(st.nextToken().trim()));
			}
		}
			
		// Allow only environmental vaiables listed in the configuration file to be used.
		for (Enumeration e1 = formConfigEnvReport.elements(); e1.hasMoreElements(); )
		{
			formEnvVariable = (String)e1.nextElement();
			for (Enumeration e2 = _CONFIG_ENV_.elements(); e2.hasMoreElements(); )
			{				
				if (formEnvVariable.equalsIgnoreCase((String)e2.nextElement()))
				{
					_data_.formConfigEnvReport.add(formEnvVariable);
				}
			}
		}

		// If a sort order is specified, sort the form fields based on that.
		Pattern p = Pattern.compile("^order:.*,.*");
		Matcher m = p.matcher(((String)_data_.formConfig.get("sort")));
		String sortedFields[];

		if (m.find())
		{	
			// Remove the previous field order first !!
			_data_.fieldOrder.clear();

			_data_.formConfig.put("sort",((String)_data_.formConfig.get("sort")).replaceFirst("^order:",""));
			_data_.formConfig.put("sort",((String)_data_.formConfig.get("sort")).replaceAll("(\\s+|\\n)?,(\\s+|\\n)?",","));
			_data_.formConfig.put("sort",((String)_data_.formConfig.get("sort")).replaceAll("(\\s+)?\\n+(\\s+)?",""));

			sortedFields = ((String)_data_.formConfig.get("sort")).split(",");
			for (int i=0; i<sortedFields.length; i++) _data_.fieldOrder.add(sortedFields[i]);
		}
		else
		{
			if (((String)_data_.formConfig.get("sort")).equals("alphabetic"))
			Collections.sort(_data_.fieldOrder);
		}

		// Cleaning up some rubbish never harms (though Java itself works fulltime as a cleaner).
		formElement = null;
		formEnvVariable = null;
		sortedFields = null;
	}

	private void checkForm(Data _data_)
		throws Exception
	{
		boolean validRecipient;
		String emailDomain = "", tempConfigRecipient, tempFormRecipient, tempRequiredField;
		Vector errors = new Vector();

		// The following insures that there were no newlines in any fields which 
		// will be used in the header. This closes the door to a possible security flaw.
		if (Pattern.compile("\r|\n").matcher((String)_data_.formConfig.get("subject")+(String)_data_.formConfig.get("email")+(String)_data_.formConfig.get("realname")+(String)_data_.formConfig.get("recipient")).find())
		throw new Exception(returnError(_data_,"invalid_headers",null).toString());

		if (_data_.formConfigRecipients.size() == 0)
		{
			throw new Exception(returnError(_data_,"no_recipient",null).toString());
		}
		else
		{
			// Enumerate each and every recipient email address provided
			for (Enumeration e1 = _data_.formConfigRecipients.elements(); e1.hasMoreElements(); )
			{
				validRecipient = false;
				tempFormRecipient = ((InternetAddress)e1.nextElement()).toString();

				// Make sure that there is only once occurance of the '@' sign.
				// No solid validation of email is done is as there is a possibility of the existence of an email
				// address in the format: sunil@ultrahertz (intranet environment)
				if (!Pattern.compile("(^@)|(@$)|(@.*@)").matcher(tempFormRecipient).find() && Pattern.compile("@").matcher(tempFormRecipient).find())
				{				
					emailDomain = tempFormRecipient.split("@")[1];
				}
				else
					throw new Exception(returnError(_data_,"no_recipient",null).toString());
				
				for (Enumeration e2 = _CONFIG_RECIPIENTS_.elements(); e2.hasMoreElements();)
				{
					tempConfigRecipient = (String)e2.nextElement();
					if (emailDomain.equalsIgnoreCase(tempConfigRecipient) || tempFormRecipient.equalsIgnoreCase(tempConfigRecipient))
					{
						validRecipient = true;
						break;
					}
				}

				if (!validRecipient) throw new Exception(returnError(_data_,"no_recipient",null).toString());
			}		
		}

		// For each required field definited in the form:
		for (Enumeration requiredFields = _data_.formConfigRequired.elements(); requiredFields.hasMoreElements(); )
		{
			tempRequiredField = (String)requiredFields.nextElement();

			// If the required field is the email field, the syntax of the email
			// address if checked to make sure it passes a valid syntax.  
			if (tempRequiredField.equals("email") && !verifyEmailAddress((String)_data_.formConfig.get(tempRequiredField)))
			{
				errors.add("Email address unspecified/invalid");
			}

			// Otherwise, if the required field is a configuration field and it
			// has no value or has been filled in with a space, send an error.				
			else if (_data_.formConfig.get(tempRequiredField) != null && _data_.formConfig.get(tempRequiredField).equals(""))
			{
				errors.add("Field \"" + tempRequiredField + "\" not filled in.");
			}

			// If it is a regular form field which has not been filled in or
			// filled in with a space, flag it as an error field.
			else if (_data_.form.get(tempRequiredField) != null && _data_.form.get(tempRequiredField).equals(""))
			{
				errors.add("Field \"" + tempRequiredField + "\" not filled in.");
			}
		}

		if (errors.size() > 0)
		{
			String tempArray[] = new String[errors.size()];
			errors.toArray(tempArray);
			throw new Exception(returnError(_data_,"missing_fields",tempArray).toString());
		}
		
		// Removing the next 2 lines wouldn't do any harm.
		errors = null; emailDomain = null; tempConfigRecipient = null; 
		tempFormRecipient = null; tempRequiredField = null;
	}
	
	private void sendEmail(Data _data_) 
		throws Exception
	{
		String tempElement, env;
		String subject, emailAdd, realName;
		StringBuffer emailMsg = new StringBuffer();
		String[] sortedFields;
		InternetAddress tempFormConfigRecipients[] = new InternetAddress[_data_.formConfigRecipients.size()];
		
		// Determine the email "From" field
		emailAdd = (_data_.formConfig.get("email").equals("") ? "Nobody" : (String)_data_.formConfig.get("email"));
		
		// Determine the realname to be placed alongside the email address
		realName = (_data_.formConfig.get("realname").equals("") ? "" : "("+_data_.formConfig.get("realname")+")");

		// Determine the email "subject" field
		subject = (_data_.formConfig.get("subject").equals("") ? "WWW Form Submission" : (String)_data_.formConfig.get("subject"));
		if (subject.length() > 256) subject.substring(0,256);
		
		emailMsg.append("Below is the result of your feedback form.  It was submitted by:\n");
		emailMsg.append(_data_.formConfig.get("realname") + " " + _data_.formConfig.get("email") + " on " + _data_.timeStamp + "\n");
		emailMsg.append("-----------------------------------------------------------------------------------\n\n");
		
		// Print Configuration if requested
		if (!_data_.formConfig.get("print_config").equals(""))
		{
			for (Enumeration e = _data_.formConfigPrintConfig.elements(); e.hasMoreElements(); )
			{
				tempElement = (String)e.nextElement();
				emailMsg.append(tempElement + ": " +_data_.formConfig.get(tempElement)+"\n\n");
			}
		}
			
		// Print all fields
		for (Enumeration e = _data_.fieldOrder.elements(); e.hasMoreElements(); )
		{
			tempElement = (String)e.nextElement();				
			if (!_data_.formConfig.get("print_blank_fields").equals("") || (_data_.form.get(tempElement) != null && !_data_.form.get(tempElement).equals("")))
			{
				emailMsg.append(tempElement + ": "+ (_data_.form.get(tempElement) == null ? "" : _data_.form.get(tempElement))+"\n\n");
			}				
		}

		emailMsg.append("-----------------------------------------------------------------------------------\n\n");		

		// Send any specified Environment Variables to recipient.
		for (Enumeration e = _data_.formConfigEnvReport.elements(); e.hasMoreElements(); )
		{
			tempElement = (String)e.nextElement();
			if (_data_.env.get(tempElement) != null && !_data_.env.get(tempElement).equals("null"))
			{
				emailMsg.append(tempElement + ": " + _data_.env.get(tempElement) + "; ");
			}
		}

		// Ok, let's seal the envelope and send the email
		// Ver 1.1: Integrated mail component into JFormMail for now.
		try
		{
			Properties p = System.getProperties();
			p.put("mail.smtp.host", _CONFIG_SMTP_HOST_);
			Session session=Session.getDefaultInstance(p,null);

			MimeMessage message = new MimeMessage(session);
			message.setFrom(new InternetAddress(emailAdd+realName));
			_data_.formConfigRecipients.toArray(tempFormConfigRecipients);

			// Next version of JFormMail would allow users to specify "TO, CC and BCC"
			message.addRecipients(Message.RecipientType.TO, tempFormConfigRecipients);

			message.setSubject(subject);
			message.setContent(emailMsg.toString(), "text/plain");
			message.setHeader("X-Generated-By","JFormMail v1.1 by Sunil Amber (sunilamber@hotmail.com), www.sunilamber.com");
			Transport.send(message);			
		}
		catch (Exception e)
		{
			String tempArray[] = {e.getMessage()};
			throw new Exception(returnError(_data_,"email_transport_error",tempArray).toString());
		}
	}
	
	private boolean verifyEmailAddress(String emailAdd)
	{
		//Search for illegal syntax/illegal characters
		Pattern p1 = Pattern.compile("(@.*@)|(\\.\\.)|(@\\.)|(\\.@)|(^\\.)|([^\\x20\\x2D\\x2E\\x30-\\x39\\x40-\\x5B\\x5D\\x5F\\x61-\\x7A])");
		Matcher m1 = p1.matcher(emailAdd);
		
		//Match syntax of traditional email format
		Pattern p2 = Pattern.compile("^.+@(\\[?)[a-zA-Z0-9\\-\\.]+\\.([a-zA-Z0-9]+)(\\]?)$");
		Matcher m2 = p2.matcher(emailAdd);

		if (m1.find() || !m2.matches())
		{
			return false;
		}

		return true;
	}

	private StringBuffer returnError(Data _data_, String errorMsg, String[] errorInfo)
	{
		StringBuffer buffer = new StringBuffer(), tempBuffer = new StringBuffer();
		
		//Handler For Bad Referer
		if (errorMsg.equals("bad_referer"))
		{
			if (errorInfo[0] != null && !errorInfo[0].equals(""))
			{
				buffer.append("<html>\n<head>\n<title>JFormMail v1.1</title>\n</head>\n<body bgcolor=#FFFFFF text=#000000>\n<center>\n<table border=0 width=600 bgcolor=#FFFFFF cellpadding=\"1\" cellspacing=\"1\">\n<tr> \n<td bgcolor=\"#000000\"> \n<table border=0 width=\"100%\" bgcolor=#FFFFFF cellpadding=\"0\" cellspacing=\"0\">\n<tr> \n<td bgcolor=\"#000000\"> \n<div align=\"center\"><font size=\"2\" color=\"#FFFFFF\" face=\"Verdana, Arial, Helvetica, sans-serif\"><b>Bad \nReferrer - Access Denied</b></font></div>\n</td>\n</tr>\n<tr> \n<td bgcolor=\"#FFFFFF\"> \n<div align=\"left\"> \n<table width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"4\">\n<tr>\n<td><font face=\"Courier New, Courier, mono\" size=\"2\"><br>\nThe form attempting to use <a href=\"http://www.sunilamber.com/ssm/jformmail/\">JFormMail</a> \nresides at "+errorInfo[0]+", \nwhich is not allowed to access this cgi script.<br>\n<br>\nIf you are attempting to configure JFormMail to run with \nthis form, you need to add the following to &quot;valid.referers&quot; \nin your JFormMail.ini file, explained in detail in the README \nfile. <br>\n<br>\nAdd '"+errorInfo[1]+"' to your &quot;valid.referers&quot; variable.<br>\n</font></td>\n</tr>\n</table>\n<font face=\"Courier New, Courier, mono\" size=\"2\"> </font> \n<hr width=\"100%\" noshade align=\"center\" size=\"1\">\n<div align=\"center\"><font face=\"Courier New, Courier, mono\" size=\"2\"><a href=\"http://www.sunilamber.com/ssm/jformmail/\">JFormMail</a> \nV1.1&copy; 2002-2003 Sunil Amber<br>\nA Free Product From <a href=\"http://www.sunilamber.com/ssm/\">Sunil's \nSoftware Mission</a></font></div>\n</div>\n</td>\n</tr>\n</table>\n</td>\n</tr>\n</table>\n</center>\n</body>\n</html>");
			}
			else
			{
				buffer.append("<html>\n<head>\n<title>JFormMail v1.1</title>\n</head>\n<body bgcolor=#FFFFFF text=#000000>\n<center>\n<table border=0 width=600 bgcolor=#FFFFFF cellpadding=\"1\" cellspacing=\"1\">\n<tr> \n<td bgcolor=\"#000000\"> \n<table border=0 width=\"100%\" bgcolor=#FFFFFF cellpadding=\"0\" cellspacing=\"0\">\n<tr> \n<td bgcolor=\"#000000\"> \n<div align=\"center\"><font size=\"2\" color=\"#FFFFFF\" face=\"Verdana, Arial, Helvetica, sans-serif\"><b>JFormMail</b></font></div>\n</td>\n</tr>\n<tr> \n<td bgcolor=\"#FFFFFF\"> \n<div align=\"center\"><b><font size=\"2\" face=\"Courier New, Courier, mono\">Copyright \n2002-2003 Sunil Amber<br>\nVersion 1.1 - Released June 28, 2003<br>\nA Free Contribution From <a href=\"http://www.sunilamber.com/ssm/\">Sunil's \nSoftware Mission</a></font></b></div>\n</td>\n</tr>\n</table>\n</td>\n</tr>\n</table>\n</center>\n</body>\n</html>");
			}
		}

		//Handler For No Recipient
		else if (errorMsg.equals("no_recipient"))
		{
			buffer.append("<html>\n<head>\n<title>JFormMail v1.1</title>\n</head>\n<body bgcolor=#FFFFFF text=#000000>\n<center>\n<table border=0 width=600 bgcolor=#FFFFFF cellpadding=\"1\" cellspacing=\"1\">\n<tr> \n<td bgcolor=\"#000000\"> \n<table border=0 width=\"100%\" bgcolor=#FFFFFF cellpadding=\"0\" cellspacing=\"0\">\n<tr> \n<td bgcolor=\"#000000\"> \n<div align=\"center\"><font size=\"2\" color=\"#FFFFFF\" face=\"Verdana, Arial, Helvetica, sans-serif\"><b>Error: \nBad/No Recipient</b></font></div>\n</td>\n</tr>\n<tr> \n<td bgcolor=\"#FFFFFF\"> \n<div align=\"left\"><font face=\"Courier New, Courier, mono\" size=\"2\"><br>\n</font> \n<table width=\"100%\" border=\"0\" cellspacing=\"4\" cellpadding=\"0\">\n<tr> \n<td><font face=\"Courier New, Courier, mono\" size=\"2\">There \nwas no recipient or an invalid recipient specified in the \ndata sent to FormMail. Please make sure:<br>\n<br>\n1)The recipient email specified in the form data is valid. \nA recipient email in this context is considered valid if \nthere is an '@' sign, and the email does not start or end \nwith an '@'.<br>\n<br>\n2)You have filled in the recipient form field with an e-mail \naddress that has been configured in the &quot;valid.recipients&quot; \nvariable in your JFormMail.ini file. More information on \nfilling in recipient form fields and variables can be found \nin the README file.</font></td>\n</tr>\n</table>\n<font face=\"Courier New, Courier, mono\" size=\"2\"> <br>\n</font> \n<hr width=\"100%\" noshade align=\"center\" size=\"1\">\n<div align=\"center\"><font face=\"Courier New, Courier, mono\" size=\"2\"><a href=\"http://www.sunilamber.com/ssm/jformmail/\">JFormMail</a> \nV1.1&copy; 2002-2003 Sunil Amber<br>\nA Free Product From <a href=\"http://www.sunilamber.com/ssm/\">Sunil's \nSoftware Mission</a></font></div>\n</div>\n</td>\n</tr>\n</table>\n</td>\n</tr>\n</table>\n</center>\n</body>\n</html>");
		}

		//Handler For Missing Fields
		else if (errorMsg.equals("missing_fields"))
		{

			//Redirect to a custom page
			if (!_data_.formConfig.get("missing_fields_redirect").equals(""))
			{
				System.out.println(_data_.formConfig.get("missing_fields_redirect"));
				try
				{
					_data_.response.sendRedirect(cleanHtml((String)_data_.formConfig.get("missing_fields_redirect")));					
				}
				catch (IOException ioex)
				{
					String tempArray[] = {cleanHtml((String)_data_.formConfig.get("missing_fields_redirect"))};
					buffer.append(returnError(_data_,"redirection_error",tempArray));
				}
			}

			//Else, Display the errors
			else
			{
				for (int i=0 ;i<errorInfo.length ; i++)
				{
					tempBuffer.append("<li><font face=\"Courier New, Courier, mono\" size=\"2\">"+errorInfo[i]+"</font><br>");
				}
				buffer.append("<html>\n<head>\n<title>JFormMail v1.1</title>\n</head>\n<body bgcolor=#FFFFFF text=#000000>\n<center>\n<table border=0 width=600 bgcolor=#FFFFFF cellpadding=\"1\" cellspacing=\"1\">\n<tr> \n<td bgcolor=\"#000000\"> \n<table border=0 width=\"100%\" bgcolor=#FFFFFF cellpadding=\"0\" cellspacing=\"0\">\n<tr> \n<td bgcolor=\"#000000\"> \n<div align=\"center\"><font size=\"2\" color=\"#FFFFFF\" face=\"Verdana, Arial, Helvetica, sans-serif\"><b>Error: \nBlank/Errornous Fields</b></font></div>\n</td>\n</tr>\n<tr> \n<td bgcolor=\"#FFFFFF\"> <br>\n<table width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"4\">\n<tr>\n<td><font face=\"Courier New, Courier, mono\" size=\"2\">The following \nerror(s) occured during the form submission:</font><br>\n<ul>\n"+tempBuffer+"<br>\n</ul>\n<font face=\"Courier New, Courier, mono\" size=\"2\"> These fields \nmust be filled in before you can successfully submit the form.<br>\n<br>\nClick <a href=\"javascript:history.back();\">here</a> to go \nback or use your browser's back button to return to the form \nand try again. </font></td>\n</tr>\n</table>\n<font face=\"Courier New, Courier, mono\" size=\"2\"> </font> <br>\n<hr width=\"100%\" noshade align=\"center\" size=\"1\">\n<div align=\"center\"><font face=\"Courier New, Courier, mono\" size=\"2\"><a href=\"http://www.sunilamber.com/ssm/jformmail/\">JFormMail</a> \nV1.1 &copy; 2002-2003 Sunil Amber<br>\nA Free Product From <a href=\"http://www.sunilamber.com/ssm/\">Sunil's \nSoftware Mission</a></font> </div>\n</td>\n</tr>\n</table>\n</td>\n</tr>\n</table>\n</center>\n</body>\n</html>");
			}
		}

		//Handle For Invalid Headers
		else if (errorMsg.equals("invalid_headers"))
		{
			buffer.append("<html>\n<head>\n<title>JFormMail v1.1</title>\n</head>\n<body bgcolor=#FFFFFF text=#000000>\n<center>\n<table border=0 width=600 bgcolor=#FFFFFF cellpadding=\"1\" cellspacing=\"1\">\n<tr> \n<td bgcolor=\"#000000\"> \n<table border=0 width=\"100%\" bgcolor=#FFFFFF cellpadding=\"0\" cellspacing=\"0\">\n<tr> \n<td bgcolor=\"#000000\"> \n<div align=\"center\"><font size=\"2\" color=\"#FFFFFF\" face=\"Verdana, Arial, Helvetica, sans-serif\"><b>Error: \nBad Header Fields</b></font></div>\n</td>\n</tr>\n<tr> \n<td bgcolor=\"#FFFFFF\"> \n<table width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"4\">\n<tr>\n<td><font face=\"Courier New, Courier, mono\" size=\"2\"><br>\nThe header fields, which include recipient, email, realname \nand subject were filled in with invalid values. You may not \ninclude any newline characters in these parameters. More information \non filling in these form fields and variables can be found \nin the &quot;README&quot; file. <br>\n</font></td>\n</tr>\n</table>\n<hr width=\"100%\" noshade align=\"center\" size=\"1\">\n<div align=\"center\"><font face=\"Courier New, Courier, mono\" size=\"2\"><a href=\"http://www.sunilamber.com/ssm/jformmail/\">JFormMail</a> \nV1.1&copy; 2002-2003 Sunil Amber<br>\nA Free Product From <a href=\"http://www.sunilamber.com/ssm/\">Sunil's \nSoftware Mission</a></font> </div>\n</td>\n</tr>\n</table>\n</td>\n</tr>\n</table>\n</center>\n</body>\n</html>");
		}

		//Handle For Email Transport Error
		else if (errorMsg.equals("email_transport_error"))
		{
			buffer.append("<html>\n<head>\n<title>JFormMail v1.1</title>\n</head>\n<body bgcolor=#FFFFFF text=#000000>\n<center>\n<table border=0 width=600 bgcolor=#FFFFFF cellpadding=\"1\" cellspacing=\"1\">\n<tr> \n<td bgcolor=\"#000000\"> \n<table border=0 width=\"100%\" bgcolor=#FFFFFF cellpadding=\"0\" cellspacing=\"0\">\n<tr> \n<td bgcolor=\"#000000\"> \n<div align=\"center\"><font size=\"2\" color=\"#FFFFFF\" face=\"Verdana, Arial, Helvetica, sans-serif\"><b>Error: \nMail Transport Error</b></font></div>\n</td>\n</tr>\n<tr> \n<td bgcolor=\"#FFFFFF\"> \n<div align=\"left\">\n<table width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"4\">\n<tr>\n<td><font face=\"Courier New, Courier, mono\" size=\"2\"><br>\nYour form could not be submitted due to the following mail \ntransport error: <br>\n<ul>\n<font color=\"#FF0000\">"+errorInfo[0]+"</font> \n</ul>\nPlease report this error to the the administrator of this \nsite</font>. <br>\n<font face=\"Courier New, Courier, mono\" size=\"2\">Click <a href=\"javascript:history.back();\">here</a> \nto go back or use your browser's back button to return to \nthe form and try again.</font> <br>\n</td>\n</tr>\n</table>\n</div>\n<hr width=\"100%\" noshade align=\"center\" size=\"1\">\n<div align=\"center\"><font face=\"Courier New, Courier, mono\" size=\"2\"><a href=\"http://www.sunilamber.com/ssm/jformmail/\">JFormMail</a> \nV1.1&copy; 2002-2003 Sunil Amber<br>\nA Free Product From <a href=\"http://www.sunilamber.com/ssm/\">Sunil's \nSoftware Mission</a></font> </div>\n</td>\n</tr>\n</table>\n</td>\n</tr>\n</table>\n</center>\n</body>\n</html>");
		}
		
		//Handle for Redirection Error
		else if (errorMsg.equals("redirection_error"))
		{
			buffer.append("<html>\n<head>\n<title>JFormMail v1.1</title>\n</head>\n<body bgcolor=#FFFFFF text=#000000>\n<center>\n<table border=0 width=600 bgcolor=#FFFFFF cellpadding=\"1\" cellspacing=\"1\">\n<tr> \n<td bgcolor=\"#000000\"> \n<table border=0 width=\"100%\" bgcolor=#FFFFFF cellpadding=\"0\" cellspacing=\"0\">\n<tr> \n<td bgcolor=\"#000000\"> \n<div align=\"center\"><font size=\"2\" color=\"#FFFFFF\" face=\"Verdana, Arial, Helvetica, sans-serif\"><b>Error: \nRedirection Error</b></font></div>\n</td>\n</tr>\n<tr> \n<td bgcolor=\"#FFFFFF\"> \n<div align=\"left\"><font face=\"Courier New, Courier, mono\" size=\"2\"><br>\n</font>\n<table width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"4\">\n<tr>\n<td><font face=\"Courier New, Courier, mono\" size=\"2\">An unexpected \nredirection error pointing to the following page has occured.<br>\n<ul>\n<li><a href=\"##\">"+errorInfo[0]+"</a> \n</ul>\nClick <a href=\"javascript:history.back();\">here</a> to go \nback or use your browser's back button to return to the \nform and try again.</font><font face=\"Courier New, Courier, mono\" size=\"2\"><br>\n<br>\nPlease report this error to the the administrator of this \nsite if the problem persists.<br>\n</font></td>\n</tr>\n</table>\n</div>\n<hr width=\"100%\" noshade align=\"center\" size=\"1\">\n<div align=\"center\"><font face=\"Courier New, Courier, mono\" size=\"2\"><a href=\"http://www.sunilamber.com/ssm/jformmail/\">JFormMail</a> \nV1.1&copy; 2002-2003 Sunil Amber<br>\nA Free Product From <a href=\"http://www.sunilamber.com/ssm/\">Sunil's \nSoftware Mission</a></font> </div>\n</td>\n</tr>\n</table>\n</td>\n</tr>\n</table>\n</center>\n</body>\n</html>");
		}

		return buffer;
	}

	private void returnHtml(Data _data_)
		throws Exception
	{
		StringBuffer bufferOut = new StringBuffer(), formData = new StringBuffer();
		PrintWriter out = _data_.response.getWriter();
		String pageTitle = "", returnLinkUrlTitle = "",tempElement;
		_data_.safeFormConfig = new Hashtable();
				
		// Now that we have finished using form values for any e-mail related
		// reasons, we will convert all of the form fields and config values
		// to remove any cross-site scripting security holes.
		for (Enumeration e = _data_.formConfig.keys(); e.hasMoreElements(); )
		{
			tempElement = (String)e.nextElement();
			_data_.safeFormConfig.put(tempElement,cleanHtml((String)_data_.formConfig.get(tempElement)));
		}

		for (Enumeration e = _data_.form.keys(); e.hasMoreElements(); )
		{
			tempElement = (String)e.nextElement();
			_data_.form.put(tempElement,cleanHtml((String)_data_.form.get(tempElement)));
		}

		if (!_data_.formConfig.get("redirect").equals(""))
		{
			try
			{
				_data_.response.sendRedirect((String)_data_.safeFormConfig.get("redirect"));
			}
			catch (Exception e)
			{
				String tempArray[] = {""+_data_.safeFormConfig.get("redirect")};
				throw new Exception(returnError(_data_,"redirection_error",tempArray).toString());
			}
		}
		else
		{
			_data_.response.setContentType("text/html");
			
			// Determine the title of the page
			pageTitle = (_data_.formConfig.get("title").equals("") ? "Thank You" : (String)_data_.safeFormConfig.get("title"));

			// Generate all fields key/value pair HTML
			for (Enumeration e = _data_.fieldOrder.elements(); e.hasMoreElements(); )
			{
				tempElement = (String)e.nextElement();
				if (!_data_.formConfig.get("print_blank_fields").equals("") || (_data_.form.get(tempElement) != null && !_data_.form.get(tempElement).equals("")))
				{
					formData.append("<li><b>" + cleanHtml((String)tempElement) + ":</b> "+ cleanHtml(_data_.form.get(tempElement) == null ? "" : (String)_data_.form.get(tempElement))+"<p>\n\n");
				}
			}

			// Check for a Return Link and print one if found.
			if (!_data_.formConfig.get("return_link_url").equals("") && !_data_.formConfig.get("return_link_title").equals(""))
			returnLinkUrlTitle = "<ul><li><a href=\""+_data_.formConfig.get("return_link_url")+"\">"+_data_.formConfig.get("return_link_title")+"</a></ul>";
			
			// Let's put all dynamic variables into HTML
			bufferOut.append("<html>\n<head>\n<title>\n"+pageTitle+"\n</title>\n</head>");
			bufferOut.append("<body"+printBodyAttributes(_data_)+">");
			bufferOut.append("<center> <table width=\"700\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">");
			bufferOut.append("<tr><td><div align=\"center\">");

			// Page header goes in here
			bufferOut.append("<h1>"+pageTitle+"</h1>");
			
			// Recipient and time stamp goes in here
			bufferOut.append("</div></td></tr><tr><td>");
			bufferOut.append("<div align=\"center\">Below is what you submitted to "+_data_.safeFormConfig.get("recipient")+" on "+_data_.timeStamp+"</div>");
			bufferOut.append("</td></tr> <tr> <td><hr size=1 width=100%> </td> </tr> <tr> <td><br>");
			
			// Form data goes in here.
			bufferOut.append(formData);

			bufferOut.append("<br></td></tr><tr><td><hr size=1 width=100%></td></tr><tr><td>");			
			
			// Return link goes in here
			bufferOut.append(returnLinkUrlTitle);
			
			// Page footer goes in here
			bufferOut.append("</td> </tr> <tr> <td> <hr size=1 width=100%> </td> </tr> <tr> <td>");
			bufferOut.append("<div align=\"center\"><font face=\"Courier New, Courier, mono\" size=\"2\"><a href=\"http://www.sunilamber.com/ssm/jformmail/\">JFormMail</a>");
			bufferOut.append("V1.1 &copy; 2002-2003 Sunil Amber<br> A Free Product From <a href=\"http://www.sunilamber.com/ssm/\">Sunil's Software Mission</a></font></div>");
			bufferOut.append("</td> </tr></table></center><p>&nbsp; </body></html>");

			// Ok, we are done for the moment, let's print out the final buffer.
			out.println(bufferOut);
		}
	}

	private static String cleanHtml(String str)
	{
		str = str.replaceAll("&","&amp;");
		str = str.replaceAll("<","&lt;");
		str = str.replaceAll(">","&gt;");
		str = str.replaceAll("\"","&quot;");
		str = str.replaceAll("'","&#39;");
	
		return str;
	}

	private StringBuffer printBodyAttributes(Data _data_)
		throws Exception
	{	
		String tempElement;
		StringBuffer buffer = new StringBuffer();
		Hashtable mappings = new Hashtable();
		mappings.put("bgcolor","bgcolor");
		mappings.put("background","background");
		mappings.put("link_color","link");
		mappings.put("vlink_color","vlink");
		mappings.put("alink_color","alink");
		mappings.put("text_color","text");

		for (Enumeration e = mappings.keys(); e.hasMoreElements(); )
		{
			tempElement = (String)e.nextElement();
			if (!_data_.formConfig.get(tempElement).equals(""))
			{
				buffer.append(" "+mappings.get(tempElement)+"=\""+_data_.safeFormConfig.get(tempElement)+"\""); 
			}
		}

		return buffer;
	}

	private Hashtable getEnvVariables(HttpServletRequest request)
	{
		String tempElement;
		Hashtable env = new Hashtable();

		// Add all environmental variables to a hash class 
		// Some variables might have been missed out.
		env.put("AUTH_TYPE",""+request.getAuthType());
		env.put("CONTENT_LENGTH",""+request.getContentLength());
		env.put("CONTENT_TYPE", ""+request.getContentType());
		env.put("DOCUMENT_ROOT",""+getServletContext().getRealPath("/"));
		env.put("HTTP_ACCEPT",""+request.getHeader("Accept"));
		env.put("HTTP_REFERER",""+request.getHeader("Referer"));
		env.put("HTTP_ACCEPT_LANGUAGE",""+request.getHeader("Accept-Language"));
		env.put("HTTP_ACCEPT_ENCODING",""+request.getHeader("Accept-Encoding"));
		env.put("HTTP_CONNECTION",""+request.getHeader("Connection"));
		env.put("HTTP_HOST",""+request.getHeader("Host"));
		env.put("HTTP_USER_AGENT",""+request.getHeader("User-Agent"));
		env.put("PATH_INFO", ""+request.getPathInfo());
		env.put("PATH_TRANSLATED", ""+request.getPathTranslated());
		env.put("QUERY_STRING", ""+request.getQueryString());
		env.put("REMOTE_ADDR", ""+request.getRemoteAddr());
		env.put("REMOTE_HOST", ""+request.getRemoteHost());
		env.put("REMOTE_USER", ""+request.getRemoteUser());
		env.put("REQUEST_METHOD", ""+request.getMethod());
		env.put("REQUEST_URI", ""+request.getRequestURI());
		env.put("SCRIPT_NAME", ""+request.getServletPath());
		env.put("SERVER_NAME", ""+request.getServerName());
		env.put("SERVER_PORT",""+request.getServerPort());
		env.put("SERVER_PROTOCOL", ""+request.getProtocol());
		env.put("SERVER_SOFTWARE",""+getServletContext().getServerInfo());
		
		// Let's also store all other env variables not listed above.
		for (Enumeration e = request.getHeaderNames(); e.hasMoreElements(); )
		{
			tempElement = (String)e.nextElement();
			if (!env.containsKey(tempElement))
			{
				env.put(tempElement.toUpperCase(),""+request.getHeader(tempElement));
			}
		}

		return env;
	}
}	
