//////////////////////////////////////////////////////////////////////////// 
// 
// Copyright (C) DSTC Pty Ltd (ACN 052 372 577) 1993, 1994, 1995.
// Unpublished work.  All Rights Reserved.
// 
// The software contained on this media is the property of the
// DSTC Pty Ltd.  Use of this software is strictly in accordance
// with the license agreement in the accompanying LICENSE.DOC 
// file. If your distribution of this software does not contain 
// a LICENSE.DOC file then you have no rights to use this 
// software in any manner and should contact DSTC at the address 
// below to determine an appropriate licensing arrangement.
// 
//      DSTC Pty Ltd
//      Level 7, GP South
//      University of Queensland
//      St Lucia, 4072
//      Australia
//      Tel: +61 7 3365 4310
//      Fax: +61 7 3365 4311
//      Email: jcsi@dstc.qut.edu.au
// 
// This software is being provided "AS IS" without warranty of
// any kind.  In no event shall DSTC Pty Ltd be liable for
// damage of any kind arising out of or in connection with
// the use or performance of this software.
// 
//////////////////////////////////////////////////////////////////////////// 

package jcsi.servlet;

import java.util.Set;
import java.util.HashSet;
import java.util.Properties;
import java.util.Date;
import java.io.*;
import java.security.*;
import java.security.cert.*;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.activation.*;
import javax.mail.*;
import javax.mail.internet.*;

import com.dstc.security.smime.*;
import com.dstc.security.pkcs8.*;
import com.dstc.security.util.Config;

public class SMIMEServlet extends HttpServlet
  implements SingleThreadModel
{
  private static final String SMIME_CONF = "jcsi.smime.conf";
  private static final String SMIME_PROPERTIES = "smime.properties";
  private static final String SUBJECT = "A test S/MIME message";

  private Properties props;
  private Session session;
  private String from;
  private String sigAlgName;
  private PrivateKey privKey;
  private X509Certificate myCert;
  private Set myCerts;

  public SMIMEServlet() throws ServletException
  {
    super();

    try
    {
      props = Config.getProperties(SMIME_CONF, SMIME_PROPERTIES);
      String keyDir = (String)props.getProperty("jcsi.smime.key.dir");

      from = (String)props.getProperty("jcsi.smime.sender");
      sigAlgName = (String)props.getProperty("jcsi.smime.signatureAlg");

      if (sigAlgName == null)
        throw new ServletException("Signature algorithm not yet set");

      String fileName 
        = keyDir + File.separator 
	    + (String)props.getProperty("jcsi.smime.privKey");

      if (fileName == null)
        throw new ServletException("Location of private key file unspecified");

      FileInputStream is = new FileInputStream(fileName);

      byte encoded[] = new byte[is.available()];
      is.read(encoded);

      PKCS8EncryptedPrivateKey encKey
        = new PKCS8EncryptedPrivateKey(encoded);

      encKey.decrypt((String)props.getProperty("jcsi.smime.privKey.password"));

      this.privKey = encKey.getPrivateKey();

      fileName 
        = keyDir + File.separator 
	  + (String)props.getProperty("jcsi.smime.myCert");

      if (fileName == null)
        throw new ServletException("Location of user certificate unspecified");

      is = new FileInputStream(fileName);

      CertificateFactory certFact = CertificateFactory.getInstance("X509");

      this.myCert = (X509Certificate)certFact.generateCertificate(is);

      this.myCerts = new HashSet();
      myCerts.add(myCert);

      fileName 
        = keyDir + File.separator 
	    + (String)props.getProperty("jcsi.smime.caCert");

      if (fileName != null)
      {
        is = new FileInputStream(fileName);

        myCerts.add((X509Certificate)certFact.generateCertificate(is));
        is.close();
      }
    }
    catch (Exception e)
    {
      e.printStackTrace();
      throw new ServletException(e.getMessage());
    }
  }

  public void doGet(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException
  {
    doPost(req, resp);
  }

  public void doPost(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException
  {
    try
    {
      session = Session.getDefaultInstance(props, null);
      session.setDebug(true);

      setupMailcap();

      StringBuffer sb = new StringBuffer();
      sb.append("Hello!\n");

      String to = req.getParameter("email");

      MimeMessage msg = compose(to, sb.toString());
      sign(msg);

      Transport.send(msg);

      resp.setContentType("text/html");
      resp.getWriter().println("<HTML>");
      resp.getWriter().println("Done! Please check your mail");
      resp.getWriter().println("</HTML>");
    }
    catch (Exception e)
    {
      e.printStackTrace();
      throw new ServletException(e.getMessage());
    }
  }

  private MimeMessage compose(String to, String contents)
    throws ServletException, IOException
  {
    try
    {
      MimeMessage msg 
        = new MimeMessage(Session.getDefaultInstance(null, null));
  
      InternetHeaders hdrs = new InternetHeaders();
      hdrs.addHeader("Content-Type", "text/plain; charset=us-ascii");
      hdrs.addHeader("Content-Transfer-Encoding", "7bit");
  
      MimeBodyPart part = new MimeBodyPart(hdrs, contents.getBytes());
      msg.setContent(part.getContent(), "text/plain");
      msg.setHeader("Content-Type", "text/plain; charset=us-ascii");
      msg.setHeader("Content-Transfer-Encoding", "7bit");

      msg.setSubject(SUBJECT);
      msg.setSentDate(new Date());
      msg.setFrom(new InternetAddress(from));
  
      InternetAddress[] address = {new InternetAddress(to)};
      msg.setRecipients(Message.RecipientType.TO, address);

      return msg;
    }
    catch (MessagingException e)
    {
      throw new ServletException(e.getMessage());
    }
  }

  private void sign(MimeMessage msg) 
    throws ServletException
  {
    try
    {
      MimeBodyPart bodyPart = new MimeBodyPart();
      bodyPart.setContent(msg.getContent(), msg.getContentType());
      bodyPart.setHeader("Content-Type", msg.getContentType());
      bodyPart.setHeader("Content-Transfer-Encoding", msg.getEncoding());
      bodyPart.setDisposition(msg.getDisposition());
      bodyPart.setDescription(msg.getDescription());

      MimeMultipartSigned mp = new MimeMultipartSigned(bodyPart);
      mp.setSignatureAlgorithm(sigAlgName);
      mp.setDigestAlgorithm("SHA-1");
      mp.setKeys(privKey, myCert);
      mp.setCertificates(myCerts);

      mp.sign();
      msg.setContent(mp);
    } 
    catch (Exception e)
    {
      e.printStackTrace();
      throw new ServletException(e.getMessage());
    }
  }

  private void setupMailcap()
  {
    MailcapCommandMap map = new MailcapCommandMap();
    map.addMailcap("application/x-pkcs7-signature;; " +
      " x-java-content-handler=" +
      "com.dstc.security.smime.handlers.x_pkcs7_signature");
    map.addMailcap("multipart/signed;; " +
    " x-java-content-handler=" +
      "com.dstc.security.smime.handlers.multipart_signed");
    map.addMailcap("application/x-pkcs7-mime;; " +
      " x-java-content-handler=" +
      "com.dstc.security.smime.handlers.x_pkcs7_mime");

    CommandMap.setDefaultCommandMap(map);
  }
}
