var	ip ='<!--#echo var="REMOTE_ADDR"-->';	// client ip placed here by apache
var	server = location.hostname;			// set server to current server name

function resetForm (guidance) {

	switch (guidance) {
		case 'start':  // check form parameters and reset form for subscribe
			var exception = false;
			try {
				var stateObj = document.getElementById ('state'); 
				stateObj.value = 'start'}
				catch(e) {alert ('SubQuickly: missing hidden parameter, name=state'); exception=true};
			
			try {
				var saveObj = document.getElementById ('save');
				saveObj.value = ''}
				catch (e) {alert ('SubQuickly: missing hidden parameter, name=save'); exception=true};
			
			try {
				var listsObj = document.getElementById ('lists');
				listsObj.value = ''}
				catch (e) {alert ('SubQuickly: missing hidden parameter, name=lists'); exception=true};
					
			// detect newsletters; count them and save the number
			try {
				var noLists = 0;
				var nlObject  = document.getElementById ('nl');
				var nlType = nlObject.type;
				if (nlType == 'hidden') noLists = 1;
				if (nlType == 'checkbox')  noLists = document.newsForm.nl.length;
				if (nlType == 'select-one' || nlType == 'select-multiple') noLists = nlObject.length}
				catch (e) {alert ('SubQuickly: missing newsletter ID parameter name=nl'); exception=true};
				
			// save count of newsletters
			try {
				var nolObj = document.getElementById ('nol');
				nolObj.value = noLists}
				catch (e) {alert ('SubQuickly: missing hidden parameter, name=nol'); exception=true};
			
			if (exception) { alert ('SubQuickly: initialization failed.'); break };
			
			// set form for subscribe option
			setRows ('subscribe');
			advise ('See subscribe feedback here...');
			
			// ensure actions are visible
			var actionRowObj = document.getElementById('subAction');
			actionRowObj.style.visibility = 'visible';
			break;

		case 'state': // reset process state to start and clear user message area
			var stateObj = document.getElementById ('state');
			stateObj.value = 'start';
			break;

		case 'clear':  // clear user message area
			clearMsg();
			break;
			
		case 'visible': // entire form -> visible
			var formObj = document.getElementById ('subscribe');
			formObj.style.display = 'block';
			clearMsg();
			break;
			
		case 'hidden': // entire form -> hidden
			var formObj = document.getElementById ('subscribe');
			formObj.style.display = 'none';
			clearMsg();
			break;
	}
	return
}


function setRows (action) {

		var l1 = document.getElementById('label1'); 
		var l2 = document.getElementById('label2'); 

		var row1Obj = document.getElementById('row1');
		var row2Obj = document.getElementById('row2');
		
		var field1Obj = document.getElementById('field1');
		var field2Obj = document.getElementById('field2');
		var field3Obj = document.getElementById('field3');

	switch (action) {
		case 'subscribe':
			l1.innerHTML = 'Your Email:'
			l2.innerHTML = 'Your Name:'
			row1Obj.style.visibility = 'visible';
			row2Obj.style.visibility = 'visible';
			field1Obj.value = '';
			field2Obj.value = 'First';
			field3Obj.value = 'Last';
			document.newsForm.action[0].checked = true; // subscribe
			advise ('See subscribe feedback here...');
			break;
			
		case 'subContinue': // step 2 of subscribe
			l1.innerHTML = 'Your Email:'
			l2.innerHTML = 'Your Name:'
			row1Obj.style.visibility = 'visible';
			row2Obj.style.visibility = 'visible';
			field1Obj.value = '';
			document.newsForm.action[0].checked = true; // subscribe
			break;

		case 'cancel':
			l1.innerHTML = 'Email Address:'
			l2.innerHTML = ''
			row1Obj.style.visibility = 'visible';
			row2Obj.style.visibility = 'hidden';
			field1Obj.value = '';
			field2Obj.value = '';
			document.newsForm.action[1].checked = true; // cancel
			advise ('See cancel feedback here...');
			break;
			
		case 'update':
			l1.innerHTML = 'Former Email:'
			l2.innerHTML = 'Your Name:'	
			row1Obj.style.visibility = 'visible';
			row2Obj.style.visibility = 'hidden';
			field1Obj.value = '';
			field2Obj.value = '';
			field3Obj.value = '';
			document.newsForm.action[2].checked = true; // update
			advise ('See update feedback here...');
			break;

		case 'upContinue': // step 2 of update
			l1.innerHTML = 'New Email:'
			l2.innerHTML = 'Your Name:'
			row1Obj.style.visibility = 'visible';
			row2Obj.style.visibility = 'visible';
			field1Obj.value = '';
			field2Obj.value = 'First';
			field3Obj.value = 'Last';
			document.newsForm.action[2].checked = true; // subscribe
			break;
	}
return
}

function newMsg (text) {		// create a new empty msg object
	var msg = new Object();
	msg.size = 0;
	if (text != '') msg.size = 1;
	msg.text = text;
	msg.state = '';
	return (msg);
}

function clearMsg () {			// clear the message area
	var msg = newMsg('');
	putMsg (msg, '');
}

function advise (text) { 		// place advisory text in the message area
	var msg = newMsg (text);
	putMsg (msg, 'note');
	return;
}

function alarm (text) { 		// put alert text in the mesage area
	var msg = newMsg (text);
	putMsg (msg, 'alarm');
	return;
}

function putMsg(msg, category) { // show advisory or alert message to the user
	var i;
	var myText = '';
	switch (category) {
		case 'alarm': myText = '<span class=\"alert\">' + msg.text + '</span>'; break;
		case 'note': myText = '<span class=\"note\">' + msg.text + '</span>'; break;
	}
	var nolObj = document.getElementById('nol'); 		// reserve 2 lines for each newsletters
	if (msg.size < nolObj.value) {
		var begin = msg.size;
		if (begin == 0) begin = 1;
		for (i=begin; i <= nolObj.value; i++) { myText += '&nbsp;<br>&nbsp;<br>' }
	}
	var rObj = document.getElementById('responseText'); 
	rObj.innerHTML = myText;
	return;
}


function getAction () {
	var i;
	var action = '';
	for (i = 0; i < document.newsForm.action.length; i++) {
		if (document.newsForm.action[i].checked) { action = document.newsForm.action[i].value }
	}
	return (action);
}

/* pre validate the form submittal; if OK, send it to the server */
function preValidate () { 
	var i;
	var stateObj = document.getElementById('state');
	var listsObj = document.getElementById('lists');
	var saveObj = document.getElementById('save');
	var field1Obj = document.getElementById('field1');
	var field2Obj = document.getElementById('field2');
	var field3Obj = document.getElementById('field3');	
	var action = getAction ();
	var lists = '';
	var noLists = document.newsForm.nl.length;
	if (noLists == undefined) {
		lists += ',' + document.newsForm.nl.value
	} else {
		if (document.newsForm.nl[0].type == 'hidden') {
			for (i=0; i < document.newsForm.nl.length; i++) {
				lists += ',' + document.newsForm.nl[i].value
			}
		} else {
			for (i=0; i < document.newsForm.nl.length; i++) {
				if (document.newsForm.nl[i].checked) lists += ',' + document.newsForm.nl[i].value;
			}
		}
	}
	lists = lists.substr(1);
	listsObj.value = lists;

	switch (action) {

	case 'subscribe':

		var email = field1Obj.value;
		var first = field2Obj.value;
		if (first == 'First') first = '';
		var last = field3Obj.value;
		if (last == 'Last') last = '';

		if (stateObj.value == 'start') {

			if (email == '' && first == '') {
				alarm ('Enter your Email address and name');
				field1Obj.focus();
				return (false);
			}
				
			if (email == '') {
				alarm ('Enter your Email address');
				field1Obj.focus();
				return (false);
			}
			
			if (emailCheck (email) == false) { 
				alarm ('Your Email address looks incorrect');
				field1Obj.focus();
				return (false);
			}
			
			if (first == '') {
				alarm ('Enter your name');
				field2Obj.focus();
				return (false);
			}
			
			if (first.indexOf ('@') >= 0) {
				alarm ('Please re-enter your first name');
				field2Obj.focus();
				return (false);
			}
			
			// trim leading and trailing spaces from first and last names
			first = first.replace (/^\s*/, '');
			last = last.replace (/^\s*/, '');
			first = first.replace (/$\s*/, '');
			last = last.replace (/$\s*/, '');
			
			// both names in first field, a common error
			if (first == last || last == '') {
				last = '';
				if (first.indexOf(' ') > 0) {
					var  names = first.split(' ');
					var lastOne = names.length - 1;
					if (lastOne > 0) {
						first = '';
						for (i=0; i < lastOne; ++i) first += names[i] + ' ';
						last = names[lastOne];
						first = first.replace (/$\s*/, '');	
					}
				}
			}

			field2Obj.value = first;		// update first and last with results of analysis
			field3Obj.value = last;
			var fn = first + ' ' + last;
			var params = 'request=' + stateObj.value + '&action=' + action  + '&lists=' + escape(lists) + '&fromAddress=' + escape (field1Obj.value) + '&firstName=' + escape (first) + '&lastName=' + escape (last) + '&fromName=' + escape(fn);
			break;
			
		} else { // continuation of a subscribe

			if (email != saveObj.value) { // check re-entered address
				resetForm ('start');
				alarm ('This Email address is not a match for the previous entry. Please try again from the beginning.');
				var addressObj = document.getElementById('field1');
				addressObj.value = saveObj.value;
				saveObj.value = '';
				stateObj.value = 'start';
				addressObj.focus();
				return (false);
			}

			var fn = first + ' ' + last;
			var params = 'request=' + stateObj.value + '&action=' + action  + '&lists=' + escape(lists) + '&fromAddress=' + escape(field1Obj.value) + '&fromName' + escape(fn) + '&firstName=' + escape(first) + '&lastName=' + escape(last)  + '&ip=' + ip;
			break;
		}
		
	case 'cancel':
		if (field1Obj.value == '') {
			alarm ('Enter your Email address');
			return (false);
		}
		var params = 'request=' + stateObj.value + '&action=' + action  + '&lists=' + escape(lists) + '&fromAddress=' + escape (field1Obj.value)  + '&ip=' + ip;
		break;
		
	case 'update':
	
		if (stateObj.value == 'start') {
			
			if (field1Obj.value == '') {
				alarm ('Enter your former Email address');
				return (false);
			}
			var params = 'request=' + stateObj.value + '&action=' + action  + '&lists=' + escape(lists) + '&fromAddress=' + escape (field1Obj.value);
			
		} else {	// continuation of update
		
			var email = field1Obj.value;
			var first = field2Obj.value;
			if (first == 'First') first = '';
			var last = field3Obj.value;
			if (last == 'Last') last = '';
			var full = first + ' ' + last;

			if (email == '') {
				alarm ('Enter your new Email address');
				return (false);
			}
			
			if (emailCheck (email) == false) { 
				alarm ('Your new Email address is not a regular Email address');
				return (false);
			}

			var params = 'request=' + stateObj.value + '&action=' + action  + '&lists=' + escape(lists) + '&fromAddress=' + escape (saveObj.value) + '&newAddress=' + escape (email) + '&firstName=' + escape(first) + '&lastName=' + escape(last) + '&fromName=' + escape(full)  + '&ip=' + ip;
		}
		break;
	}
	
	var url = 'http://' + server + '/subQuickly.fcgi';
	if (window.XMLHttpRequest) {
		/* mozilla/firefox requires the user to authorize xml requests */
		try {netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead")}
		catch (e) {};
		req = new XMLHttpRequest();
	} else if (window.ActiveXObject) {
		/* explorer only understands activex */
		req = new ActiveXObject('Microsoft.XMLHTTP');
	}
	req.open('POST', url, true);
	req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
	req.onreadystatechange = handleResponse;	
	
	try {
		req.send(params);
		advise ('Submitting ...')}
		catch (e) {alert ('SubQuckly: unable to submit subscribe request ' + e)};
	return (false)
}

function parseResponse (response) {
	var xmlText = response;
	var begin = xmlText.indexOf('<message') + 9;
	var end = xmlText.indexOf ('</message');
	xmlText = xmlText.slice (begin, end);
	// debug: var respObj = document.getElementById('response');
	// debug: respObj.value = xmlText;
	var msg = newMsg ('');
	var xmlRgx = /<([^>]*)>([^<]*)<\/([^>]*)>/;
	var result = xmlText.match (xmlRgx);
	while (result != null) {
		var label = result[1];
		var value = unescape (result[2]);
		if (label == 'state') msg.state = value;
		if (label == 'text') {
			var respArray = value.split (':');	// re-format text response for readability
			if (respArray.length > 1) {
				value = '<b>' + respArray[0] + ':</b><br>' + respArray[1]
			}
			if (msg.text == '') msg.text = value;
			else msg.text += '<br>' + value;
			++msg.size;
		}
		begin = result.index + result[1].length + result[2].length + result[3].length + 5;
		xmlText = xmlText.slice(begin);
		result = xmlText.match (xmlRgx);
	}
	return (msg);
}

/* handle response from the server */
function handleResponse () { 
	if (req.readyState == 4) {
		if (req.status == 200) {
			var stateObj = document.getElementById('state');
			var listsObj = document.getElementById('lists');
			var field1Obj = document.getElementById('field1');
			var field2Obj = document.getElementById('field2');
			var field1RowObj = document.getElementById('row1');
			var field2RowObj = document.getElementById('row2');
			var actionRowObj = document.getElementById('subAction');
			var saveObj = document.getElementById('save');
			

			var msg = parseResponse (req.responseText);
			stateObj.value = msg.state;
			switch (msg.state) {
			
				case 'start': // returning to step 1
					actionRowObj.style.visibility = 'visible';
					field1RowObj.style.visibility = 'visible';
					field2RowObj.style.visibility = 'visible';
					putMsg (msg, 'alarm');
					break;
				
				case 'continue': // proceding to step 2
					actionRowObj.style.visibility = 'hidden';
					var action = getAction ();
					if (action == 'subscribe') {
						saveObj.value = field1Obj.value;
						setRows ('subContinue');
					}
					if (action == 'update') {
						saveObj.value = field1Obj.value;
						setRows ('upContinue')
					}
					putMsg (msg, 'note');					
					break;
					
				case 'end': // returning for completion
					actionRowObj.style.visibility = 'visible';
					putMsg (msg, 'note');
					break;
				
				default:
					alert ('Error in handleResponse: msg.state=' + msg.state + ' from ' + req.responseText);
					break;
			}
		}
	}	
}

/*

Email address script from Sandeep
 
 V1.1.3: Sandeep V. Tamhankar (stamhankar@hotmail.com) 
 Original:  Sandeep V. Tamhankar (stamhankar@hotmail.com)
 
 Changes:
1.1.4: Fixed a bug where upper ASCII characters (i.e. accented letters
international characters) were allowed.

1.1.3: Added the restriction to only accept addresses ending in two
letters (interpreted to be a country code) or one of the known
TLDs (com, net, org, edu, int, mil, gov, arpa), including the
new ones (biz, aero, name, coop, info, pro, museum).  One can
easily update the list (if ICANN adds even more TLDs in the
future) by updating the knownDomsPat variable near the
top of the function.  Also, I added a variable at the top
of the function that determines whether or not TLDs should be
checked at all.  This is good if you are using this function
internally (i.e. intranet site) where hostnames don't have to 
conform to W3C standards and thus internal organization e-mail
addresses don't have to either.
Changed some of the logic so that the function will work properly
with Netscape 6.

1.1.2: Fixed a bug where trailing . in e-mail address was passing
(the bug is actually in the weak regexp engine of the browser; I
simplified the regexps to make it work).

1.1.1: Removed restriction that countries must be preceded by a domain,
so abc@host.uk is now legal.  However, there's still the 
restriction that an address must end in a two or three letter
word.

1.1: Rewrote most of the function to conform more closely to RFC 822.

1.0: Original  */

function emailCheck (emailStr) {

/* The following variable tells the rest of the function whether or not
to verify that the address ends in a two-letter country or well-known
TLD.  1 means check it, 0 means don't. */

var checkTLD=1;

/* The following is the list of known TLDs that an e-mail address must end with. */

var knownDomsPat=/^(com|net|org|edu|int|mil|gov|arpa|biz|aero|name|coop|info|pro|museum)$/;

/* The following pattern is used to check if the entered e-mail address
fits the user@domain format.  It also is used to separate the username
from the domain. */

var emailPat=/^(.+)@(.+)$/;

/* The following string represents the pattern for matching all special
characters.  We don't want to allow special characters in the address. 
These characters include ( ) < > @ , ; : \ " . [ ] */

var specialChars="\\(\\)><@,;:\\\\\\\"\\.\\[\\]";

/* The following string represents the range of characters allowed in a 
username or domainname.  It really states which chars aren't allowed.*/

var validChars="\[^\\s" + specialChars + "\]";

/* The following pattern applies if the "user" is a quoted string (in
which case, there are no rules about which characters are allowed
and which aren't; anything goes).  E.g. "jiminy cricket"@disney.com
is a legal e-mail address. */

var quotedUser="(\"[^\"]*\")";

/* The following pattern applies for domains that are IP addresses,
rather than symbolic names.  E.g. joe@[123.124.233.4] is a legal
e-mail address. NOTE: The square brackets are required. */

var ipDomainPat=/^\[(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\]$/;

/* The following string represents an atom (basically a series of non-special characters.) */

var atom=validChars + '+';

/* The following string represents one word in the typical username.
For example, in john.doe@somewhere.com, john and doe are words.
Basically, a word is either an atom or quoted string. */

var word="(" + atom + "|" + quotedUser + ")";

// The following pattern describes the structure of the user

var userPat=new RegExp("^" + word + "(\\." + word + ")*$");

/* The following pattern describes the structure of a normal symbolic
domain, as opposed to ipDomainPat, shown above. */

var domainPat=new RegExp("^" + atom + "(\\." + atom +")*$");

/* Finally, let's start trying to figure out if the supplied address is valid. */

/* Begin with the coarse pattern to simply break up user@domain into
different pieces that are easy to analyze. */

var matchArray=emailStr.match(emailPat);

if (matchArray==null) {

/* Too many/few @'s or something; basically, this address doesn't
even fit the general mould of a valid e-mail address. */

return false;
}
var user=matchArray[1];
var domain=matchArray[2];

// Start by checking that only basic ASCII characters are in the strings (0-127).
var i;
for (i=0; i<user.length; i++) {
if (user.charCodeAt(i)>127) {
return false;
}
}
for (i=0; i<domain.length; i++) {
if (domain.charCodeAt(i)>127) {
return false;
}
}

// See if "user" is valid 

if (user.match(userPat)==null) {

// user is not valid

return false;
}

/* if the e-mail address is at an IP address (as opposed to a symbolic
host name) make sure the IP address is valid. */

var IPArray=domain.match(ipDomainPat);
if (IPArray!=null) {

// this is an IP address

for (var i=1;i<=4;i++) {
if (IPArray[i]>255) {
return false;
}
}
return true;
}

// Domain is symbolic name.  Check if it's valid.

var atomPat=new RegExp("^" + atom + "$");
var domArr=domain.split(".");
var len=domArr.length;
for (i=0; i<len; i++) {
if (domArr[i].search(atomPat)==-1) {
return false;
}
}

/* domain name seems valid, but now make sure that it ends in a
known top-level domain (like com, edu, gov) or a two-letter word,
representing country (uk, nl), and that there's a hostname preceding 
the domain or country. */

if (checkTLD && domArr[domArr.length-1].length!=2 && 
domArr[domArr.length-1].search(knownDomsPat)==-1) {
return false;
}

// Make sure there's a host name preceding the domain.

if (len<2) {
return false;
}

// If we've gotten this far, everything's valid!
return true;
}

