Mega Code Archive

 
Categories / Java / Email
 

Class that implements a Multipart that handles multipartform-data content type

/***  * jwma Java WebMail  * Copyright (c) 2000-2003 jwma team  *  * jwma is free software; you can distribute and use this source  * under the terms of the BSD-style license received along with  * the distribution.  ***/ package dtw.webmail.util; import java.io.*; import java.util.Hashtable; import javax.mail.*; import javax.mail.internet.*; import javax.activation.*; import org.apache.log4j.Logger; //import dtw.webmail.JwmaKernel; /**  * Class that implements a Multipart that handles  * the <tt>multipart/form-data</tt> content type.  *  * @author Dieter Wimberger  * @version 0.9.7 07/02/2003  */ public class FormdataMultipart extends MimeMultipart {   //logging   private static Logger log = Logger.getLogger(FormdataMultipart.class);   //instance attributes   private Hashtable m_Params = new Hashtable();   private boolean m_Removed = false;   /**    * Constructs a <tt>FormdataMultipart</tt> instance.<br>    * This implementation just calls the superclass constructor.    *    * @return the newly created <tt>FormdataMultipart</tt> instance.    */   public FormdataMultipart() {     super();   }//constructor   /**    * Constructs a <tt>FormdataMultipart</tt> instance.<br>    * Automatically processes the body parts to extract parameters,    * and attachments.    *    * @param DataSource to construct the Multipart from, will be a    *        <tt>MultipartInputStream</tt>.    *    * @return the newly created <tt>FormdataMultipart</tt> instance.    */   public FormdataMultipart(DataSource ds)       throws MessagingException, IOException {     super(ds);     processBodyParts();     updateHeaders();   }//constructor   /**    * Returns the extracted parameters (with the extrcted values)    * as <tt>Hashtable</tt>.    *    * @return the extracted parameter data as <tt>Hashtable</tt>    */   public Hashtable getParameters() {     return m_Params;   }//getParameters   /**    * Processes the body parts of the form-data.    * Extracts parameters and set values, and    * leaves over the attachments.    *    * @throws IOException if i/o operations fail.    * @throws MessagingException if parsing or part handling with    *         Mail API classes fails.    */   private void processBodyParts()       throws IOException, MessagingException {     //if write out to log for debug reasons!     //ByteArrayOutputStream bout=new ByteArrayOutputStream();     //writeTo(bout);     //JwmaKernel.getReference().debugLog().write(bout.toString());     for (int i = 0; i < getCount(); i++) {       MimeBodyPart mbp = (MimeBodyPart) getBodyPart(i);       processBodyPart(mbp);       if (m_Removed) {         m_Removed = false;         //decrease index i approbiately         i--;       }     }     setSubType("mixed");     //JwmaKernel.getReference().debugLog().write(     //  "Processed multipart/form-data. Attachment parts:"+getCount()     //);   }//processParts   /**    * Processes a body part of the form-data.    * Extracts parameters and set values, and    * leaves over the attachments.    *    * @param mbp the <tt>MimeBodyPart</tt> to be processed.    *    * @throws IOException if i/o operations fail.    * @throws MessagingException if parsing or part handling with    *         Mail API classes fails.    */   private void processBodyPart(MimeBodyPart mbp)       throws MessagingException, IOException {     //String contenttype=new String(mbp.getContentType());     //JwmaKernel.getReference().debugLog().write("Processing "+contenttype);     //check if a content-type is given     String[] cts = mbp.getHeader("Content-Type");     if (cts == null || cts.length == 0) {       //this is a parameter, get it out and       //remove the part.       String controlname = extractName(           (mbp.getHeader("Content-Disposition"))[0]);       //JwmaKernel.getReference().debugLog().write("Processing control:"+controlname);       //retrieve value observing encoding       InputStream in = mbp.getInputStream();       String[] encoding = mbp.getHeader("Content-Transfer-Encoding");       if (encoding != null && encoding.length > 0) {         in = MimeUtility.decode(in, encoding[0]);       }       String value = extractValue(in);       if (value != null || !value.trim().equals("")) {         addParameter(controlname, value);       }       //flag removal       m_Removed = true;       removeBodyPart(mbp);     } else {       String filename = extractFileName(           (mbp.getHeader("Content-Disposition"))[0]);       //normally without file the control should be not successful.       //but neither netscape nor mircosoft iexploder care much.       //the only feature is an empty filename.       if (filename.equals("")) {         //kick it out too         m_Removed = true;         removeBodyPart(mbp);       } else {         //JwmaKernel.getReference().debugLog().write("Incoming filename="+filename);         //IExploder sends files with complete path.         //jwma doesnt want this.         int lastindex = filename.lastIndexOf("\\");         if (lastindex != -1) {           filename = filename.substring(lastindex + 1, filename.length());         }         //JwmaKernel.getReference().debugLog().write("Outgoing filename="+filename);         //Observe a possible encoding         InputStream in = mbp.getInputStream();         String[] encoding = mbp.getHeader("Content-Transfer-Encoding");         if (encoding != null && encoding.length > 0) {           in = MimeUtility.decode(in, encoding[0]);         }         ByteArrayOutputStream bout = new ByteArrayOutputStream();         OutputStream out = (OutputStream) bout;         int i = 0;         while ((i = in.read()) != -1) {           //maybe more efficient in buffers, but well           out.write(i);         }         out.flush();         out.close();         //create the datasource         MimeBodyPartDataSource mbpds =             new MimeBodyPartDataSource(                 //    contenttype,filename,bout.toByteArray()                 cts[0], filename, bout.toByteArray()             );         //Re-set the Content-Disposition header, in case         //the file name was changed         mbp.removeHeader("Content-Disposition");         mbp.addHeader(             "Content-Disposition", "attachment; filename=\"" +             filename +             "\""         );         //set a base64 transferencoding und the data handler         mbp.addHeader("Content-Transfer-Encoding", "base64");         mbp.setDataHandler(new DataHandler(mbpds));       }     }   }//processBodyPart   /**    * Returns the name of a parameter by extracting it    * from the content-disposition header line.    *    * @param disposition the content-disposition header line as    *        <tt>String</tt>.    *    * @return the name of the parameter as <tt>String</tt>.    *    * @throws IOException if the header line is malformed.    */   private String extractName(String disposition)       throws IOException {     int end = 0;     int start = -1;     start = disposition.indexOf("name=\"");     end = disposition.indexOf("\"", start + 7);   //offset is to skip name=\"     if (start == -1 || end == -1) {       throw new IOException("Mime header malformed.");     }     return disposition.substring(start + 6, end);   }//extractName   /**    * Returns the filename of an attachment by extracting it    * from the content-disposition header line.    *    * @param disposition the content-disposition header line as    *        <tt>String</tt>.    *    * @return the filename of the attachment as <tt>String</tt>.    *    * @throws IOException if the header line is malformed.    */   private String extractFileName(String disposition)       throws IOException {     int end = 0;     int start = -1;     start = disposition.indexOf("filename=\"");     end = disposition.indexOf("\"", start + 10);   //offset is to skip filename=\"     if (start == -1 || end == -1) {       throw new IOException("Mime header malformed.");     }     return disposition.substring(start + 10, end);   }//extractFileName   /**    * Returns the value of a parameter by extracting it    * from the <tt>InputStream</tt> that represents the content    * of the (parameter) part.    *    * @param in <tt>InputStream</tt> that reads from the content    *        of the (parameter) part.    *    * @return the value of the parameter as <tt>String</tt>.    *    * @throws IOException if reading from the stream fails.    */   private String extractValue(InputStream in)       throws IOException {     ByteArrayOutputStream out = new ByteArrayOutputStream();     int i = 0;     while ((i = in.read()) != -1) {       out.write(i);     }     out.flush();     out.close();     in.close();     //JwmaKernel.getReference().debugLog().write("Retrieved value="+out.toString());     //apply a little bit of magic when returning     return out.toString("iso-8859-1");   }//extractValue   /**    * Adds a parameter and mapped value to the parameters collection.    * If the parameter already exists, it adds another value to    * an already existing parameter by extending the array of strings.    *    * @param name the name of the parameter as <tt>String</tt>.    * @param value the value of the parameter as <tt>String</tt>.    */   private void addParameter(String name, String value) {     String values[];     //JwmaKernel.getReference().debugLog().write("Adding "+name+"="+value);     if (m_Params.containsKey(name)) {       String oldValues[] = (String[]) m_Params.get(name);       values = new String[oldValues.length + 1];       for (int i = 0; i < oldValues.length; i++) {         values[i] = oldValues[i];       }       values[oldValues.length] = value;     } else {       values = new String[1];       values[0] = value;     }     m_Params.put(name, values);   }//addParameter }//FormdataMultipart