function validate(form)
{
  // custom attributes for form controls.
  // 1. required={boolean} - a control is required only either if required is set or required=true. it is not required if it is not set or required=false.
  // 2. errormsg={string} - optional. used to show customize error message. the control will be used if this is not defined.
  // 3. subtype={set("integer","numeric","alphabetic","alphanumeric","date","email","confirm")} - optional. used to determine further control handling. confirm is used for password confirmation.
  // 4. minlength={integer} - used to control the minimum length of a text box.

  var element=new Object();
  var genericmessage="Please ";
  var specificmessage="";
  var error=false;

  for (var i=0; i<form.length; i++)
  {
    element=form.elements[i];
    errmsg=(element.getAttribute("errormsg")?element.getAttribute("errormsg"):element.name);
    if (element.getAttribute("subtype"))
      element.setAttribute("subtype",element.getAttribute("subtype").toLowerCase());

    // test for required elements.
    if (typeof element.getAttribute("required")=="string"&&(!element.getAttribute("required").length||element.getAttribute("required").toLowerCase()=="true"))
    {
      switch (element.type)
      {
        // password, text or textarea fields.
        case "password":
          if (element.getAttribute("subtype")&&element.getAttribute("subtype")=="confirm")
          {
            if (element.value!="")
              for (var j=i-1; j>=0; j--)	// find the password field.
                if (form.elements[j].type=="password")
                {
                  if (element.value!=form.elements[j].value)
                  {
                    specificmessage="The passwords do not match. Please try again.";
                    element.value="";
                    element=form.elements[j];
                    element.value="";
                  }
                  break;
                }
          }
        case "text":
        case "textarea":
        case "hidden":
          genericmessage="enter ";
          error=(element.value=="");
          break;

        // select boxes.
        case "select-one":
        case "select-multiple":
          genericmessage="select ";
          error=(element.selectedIndex<0 || element.options[element.selectedIndex].value=="");
          break;

        // radio buttons or check boxes.
        case "radio":
        case "checkbox":
          genericmessage="select ";

          var grp=document.getElementsByName(element.name);
          for (var g=0; g<grp.length; g++)
          {
            error=!grp[g].checked;
            if (!error)
              break;
          }
          break;

        // catch all.
        default:
          alert("type: "+element.type+"\n"+"name: "+element.name);
      }
    }

    // tests for subtypes and minlength.
    if (element.type=="text"||element.type=="password"||element.type=="textarea")
    {
      // test subtype.
      if (!error&&element.value.length!=0)
      {
        switch (element.getAttribute("subtype"))
        {
          case "email":
            if (error=(!/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,4})+$/.test(element.value)))
              specificmessage="Please enter a valid e-mail address.";
            break;
          case "integer":
            if (error=!(/(^-?\d\d*$)/.test(element.value)))
              specificmessage="Only integers are allowed in "+errmsg+".";
            break;
          case "numeric":
            if (error=!(/(^-?\d\d*\.\d*$)|(^-?\d\d*$)|(^-?\.\d\d*$)/.test(element.value)))
              specificmessage="Only numbers or decimals are allowed in "+errmsg+".";
            break;
          case "alphabetic":
            if (error=(/[^a-z]/i.test(element.value)))
              specificmessage="Only alphabets are allowed in "+errmsg+".";
            break;
          case "alphanumeric":
            if (error=(/[^a-z\d]/i.test(element.value)))
              specificmessage="Only alphabets and numbers are allowed in "+errmsg+".";
            break;
/*
          case "date":
            break;
*/
          default:
            //alert(element.name+" has no subtype defined.");
        }
      }

      // test for minimum length.
      if (!error&&element.getAttribute("minlength")&&element.value.length!=0)
      {
        error=element.value.length<element.getAttribute("minlength");
        specificmessage=errmsg.charAt(0).toUpperCase()+errmsg.substr(1)+" must have a minimum length of "+element.getAttribute("minlength")+".";
      }
    }

    // alert the user if there is an error message.
    if (error)
    {
      genericmessage="Please "+genericmessage+errmsg+".";
      alert (specificmessage!=""?specificmessage:genericmessage);
      element.focus();
      return false;
    }
    specificmessage="";
  }
  return true;
}