//Include file to allow email addresses to be encoded and decoded
//V1.0 by Bruceee, 4 Oct 2005

var codeChar=23      //change as you wish -- range 1-31; change PagNum on decode side to match
var Data1=new(Array) //storage for email names
var Data2=new(Array) //storage for email domains
var nl='\n'          //when written to a string, forces a new line
var SubjectLine=''   //saves subject if subject box unchecked

function setSubject() {
//remember old subject name and reinstate depending on state of check box
var box = eval("document.getElementById('SubjectRequired')")
var subject = eval("document.getElementById('SubjLine')")
if (box.checked) {
  if (subject.value=="") {subject.value=SubjectLine}
  }
else {SubjectLine=subject.value; subject.value=""}
}

function AddToList() {
//collect name and domain from entry boxes and add them to the main list
var recipient=eval("document.getElementById('Recipient')")
var combined=eval("document.getElementById('Combined')")
var domain=eval("document.getElementById('Domain')")
recipient.value=trim(recipient.value)
domain.value=trim(domain.value)
var Addr=recipient.value + '@'+ domain.value
if (recipient.value==0||domain.value==0) return
if (!validAddr(Addr)) return
if (combined.value.length>0) {combined.value+=nl}
combined.value += Addr
recipient.value=''
recipient.focus()
}

function trim(aString) {
aString = aString.replace(/^\d+(?=\s)/g,"") // strip any index no
aString = aString.replace(/^\s+/g,"")// strip leading
return aString.replace(/\s+$/g,"")   // strip trailing
}

/*
This code is partly duplicated in the decode section
encode or decode provided input string
Certain characters: double quotes, comma and backslash (" , \) will cause problems if left "unescaped"
in strings intended for copying. Therefore translate those into the much safer ascii 17, 18 and 19.
*/
function TestPage(aTest) {
var Output = new String
if (aTest==undefined) return
for (var i=0;i<aTest.length;i++) {
  ch = aTest.charCodeAt(i)
  if (ch==17) {ch=34} //decoding
  if (ch==18) {ch=44}
  if (ch==19) {ch=92}
  if (ch<32) {continue}
  ch = ch^codeChar
  if (ch==34) {ch=17} //encoding
  if (ch==44) {ch=18}
  if (ch==92) {ch=19}
  Output+= String.fromCharCode(ch)
  }
return Output
}

function cleanInput(aInput) {
var output=''
for (var i=0;i<aInput.length;i++) {
  var ch=aInput.charCodeAt(i)&127
  if (ch!=10 && ch!=13 && ch<32)  {continue} //strip control chars
  if (ch==34 || ch==44 || ch==92) {continue} //strip illegal chars
  output+=String.fromCharCode(ch)
  }
return output
}

/*
Encode the email Data1 and addresses. As far as possible clean up the text,
check each name/address for validity, warn if invalid.
take static code from TEXTAREA objects on the main form and add
the encoded Data1/Data2 to fill out code pane
Compare the encoded subject line against the original
Fill out a numbered list and check the result against the original list
*/
function Encode() {
//get pointers to each of the form objects to be used
var subReqd   =eval("document.getElementById('SubjectRequired')")
var codePane  =eval("document.getElementById('CodePane')")
var combined  =eval("document.getElementById('Combined')")
var subject   =eval("document.getElementById('SubjLine')")
var staticCode=eval("document.getElementById('StaticCode')")
var lookupCode=eval("document.getElementById('LookupCode')")

/*
Get the mail list as one big string
mask off 8th bit, remove control characters (except new lines)
remove illegal characters: double quotes, comma and backslash (" , \)
which are illegal in email addresses, and will screw up the encoded list
*/
var cleanAddrs=cleanInput(combined.value)
/*Check each email name/address for validity
split up the lines into Data1 and Data2, then form encoded arrays
*/
var lineCount=0
codePane.value=''
var lines=cleanAddrs.split("\n")
for (var i=0;i<lines.length;i++) {
  lines[i]=trim(lines[i])
  if (lines[i].length==0) continue  //skip blank line
  if (!validAddr(lines[i])) return
  var addrParts=lines[i].split("@")
  lineCount++
  Data1[lineCount]=TestPage(addrParts[0]) //encode Data1
  Data2[lineCount]=TestPage(addrParts[1]) //encode Data2
//Action if no data
  }
if (lineCount==0) {
  alert('No email addresses to encode')
  return
  }
codePane.value =  '<script type="text/javascript">'+nl
codePane.value += '//Test and update pages'+nl
codePane.value += "var PagNum="+codeChar+nl
codePane.value += staticCode.value //predefined code
var SingleDomain=(lineCount==1)
//First block of code for multiple Data2; encoded data, and preparatory decode code
//If only one domain, no arrays necessary
if (!SingleDomain) {
  codePane.value += lookupCode.value//more predefined code
  codePane.value += 'D1="'+Data1.toString()+'"'+nl
  codePane.value += 'D2="'+Data2.toString()+'"'+nl
  codePane.value += 'D3="'+TestPage("email address")+'"'+nl
  codePane.value += 'D4="'+TestPage("email domain")+'"'+nl
  codePane.value += 'D5="'+TestPage("UNKNOWN!!!")+'"'+nl
  codePane.value += 'var Data1=D1.split(",")'+nl
  codePane.value += 'var Data2=D2.split(",")'+nl
  codePane.value += 'for (i=0;i<Data1.length;i++) {Data1[i]=TestPage(Data1[i])}'+nl
  }
codePane.value += "function TestAllPages(aName,aIndex) {" + nl
codePane.value += 'Page1=TestPage("'+TestPage("mai"+"lto:")+'")' + nl
codePane.value += 'Page3=TestPage("'+TestPage("@")+'")' + nl
if (SingleDomain) {codePane.value+='Page4=TestPage("'+Data2[1]+'")'+ nl}
else
 {codePane.value += 'Page4=TestPage(Lookup(aName,aIndex))' + nl}
//encode subject line if any
if (subReqd.checked) {
//  alert(subject.value)
  var cleanSub=cleanInput(subject.value)
  cleanSub=trim(cleanSub)
  subject.value=cleanSub
  encodedSub=TestPage(cleanSub)
  var decodedSub=TestPage(encodedSub)
  if (decodedSub!=cleanSub) {
    alert('Subject line failed to encode\nOriginal   :'+cleanSub+
    '\nEncoded :'+decodedSub+'\n\nTry reducing any punctuation')
    }
  codePane.value += 'Page5=TestPage("'+TestPage("?subject=")+'")' + nl
  codePane.value += 'Page6=TestPage("'+encodedSub+'")' + nl
  codePane.value += 'return Page1+aName+Page3+Page4+Page5+Page6' + nl
  }
else {
  codePane.value += 'return Page1+aName+Page3+Page4' + nl
  }
codePane.value += "}" + nl
codePane.value += "</script>" + nl
validateAddrs()
}

/*
take the encoded Data1 and Data2 as written to the code box
decode them
compare against the originals, reporting any errors
write the decoded versions to a new numbered list
*/
function validateAddrs() {
var D1=Data1.toString()
var D2=Data2.toString()
var Names1=D1.split(",")
var Domains1=D2.split(",")
for (var i=1;i<Names1.length;i++) {
  Names1[i]=TestPage(Names1[i])
  Domains1[i]=TestPage(Domains1[i])
  }
var combined = eval("document.getElementById('Combined')")
var numberedList = eval("document.getElementById('NumberedList')")
var OrigList=combined.value.split("\n")
var failCount=0
var newLine
var LineCount=0
numberedList.value=''
for (var i=0;i<OrigList.length;i++) {
  OrigList[i]=trim(OrigList[i])
  if (OrigList[i].length==0) {
    numberedList.value+=nl
    continue
    }
  LineCount++
  newLine=Names1[LineCount]
  newLine += '@'+(Domains1[LineCount])
  if (numberedList.value.length>0) {numberedList.value+=nl}
  numberedList.value+=LineCount+'    '+newLine
  if (OrigList[i]!=newLine) {
    alert('This address failed to encode.\nOriginal Line:   '+OrigList[i]+
     '\nAfter encode: '+newLine+'\nIt will not be usable on your web pages')
    failCount++
    }
  }
  if (failCount==0) {
    alert(LineCount+' address(es) successfully encoded')
  }
  else {alert(LineCount+' address(es) encoded; '+failCount+' failure(s)')}
}

/* True explanation:
Get domain name that matches given name or index
if index defined, look up the domain name from the index
if no Data1 predefined, return the string for the first domain
if no index defined, do a search for the name and return associated name from the index
This code is exactly duplicated for decoding
False explanation for decode section:
*/
//Given a page name and index, return its status
function Lookup(aName,aIndex) {
var result=0
var aNameLow=trim(aName).toLowerCase()
try {
if (aIndex==undefined) {
//sequential search for given name
  for (i=1;i<Data1.length;i++) {
    if (Data1[i].toLowerCase()==aNameLow) {
      result=i
      break
    }
  }
}
else {
  if (aIndex<1 || aIndex>=Data1.length) {result=-1}
  else {result=aIndex}
  }
}
finally {
  switch (result) {
  case -1: errorMsg ='No '+TestPage(D3)+' defined for index '+ aIndex; break
  case  0: errorMsg ='No '+TestPage(D4)+' defined for '+ aName; break
  default: return Data2[result]
  }
  errorMsg +='.\nWebmaster has screwed up'
  alert(errorMsg)
  return D5
  }
}

function validAddr(aAddr){
//special chars allowed in name part are ._+'&
var mask = /^[\w\-\+'&](\.?[\w\-\+'&])*@\w(\.?[-\w])*\.([a-z]{3,4}(\.[a-z]{2})?|[a-z]{2}(\.[a-z]{2})?)$/i
if (!mask.test(aAddr)){
  alert(aAddr+"\nAddress seems to be invalid.\nBut will try to encode it anyway....")
  return true
  }
return true
}
