001    package org.rakeshv.mail;
002    
003    import java.io.PrintWriter;
004    import java.io.FileWriter;
005    import java.io.IOException;
006    import java.util.Date;
007    import java.util.Iterator;
008    import java.util.List;
009    
010    import javax.mail.BodyPart;
011    import javax.mail.Folder;
012    import javax.mail.Message;
013    import javax.mail.MessagingException;
014    import javax.mail.Multipart;
015    import javax.mail.Session;
016    import javax.mail.internet.InternetAddress;
017    import javax.mail.internet.MimeBodyPart;
018    import javax.mail.internet.MimeMessage;
019    import javax.mail.internet.MimeMultipart;
020    import javax.servlet.http.HttpServletRequest;
021    
022    import org.rakeshv.xml.addressbook.AddressBook;
023    import org.rakeshv.xml.addressbook.Person;
024    import org.rakeshv.xml.addressbook.Group;
025    import org.rakeshv.xml.addressbook.Member;
026    
027    /**
028     * This class handles <code>multipart/form-data encoded form
029     * posts</code> from the <code>write.jsp</code> page that is used
030     * to compose email messages.  This class parses out the message
031     * attributes, as well as all the attachments added to the message
032     * from the <code>HttpServletRequest</code>.
033     *
034     * <p>Copyright 2003, Rakesh Vidyadharan</p>
035     *
036     * @author Rakesh Vidyadharan 5<sup><small>th</small></sup> January
037     *   2003.
038     *
039     * $Id: SendHandler.java,v 1.5 2004/05/26 11:42:38 rakesh Exp $
040     */
041    public class SendHandler extends Object
042    {
043      /**
044       * The web session for the user using the webmail service.
045       */
046      private Session session = null;
047    
048      /**
049       * The <code>Folder</code> which the user is viewing at present.
050       * This is used to determine if the new message being created is
051       * a reply to an existing message or not.
052       */
053      private Folder folder = null;
054    
055      /**
056       * The {@link org.rakeshv.xml.addressbook.AddressBook} object for
057       * the current user.
058       */
059      private AddressBook addressBook = null;
060    
061      /**
062       * The {@link WriteFormParser} class that is used to parse out the
063       * form parts and elements from the <code>HttpRequest</code>.
064       */
065      private WriteFormParser formParser = null;
066    
067      /**
068       * The <code>Message</code> object that is to be created with all
069       * the attributes and parts specified in the form post.
070       */
071      private Message message = null;
072    
073      /**
074       * Default constructor.  Does nothing.
075       */
076      protected SendHandler() {}
077    
078      /**
079       * Creates an instance of the handler, and sets the instance fields
080       * to the passed in values.
081       *
082       * @param folder - The mail folder that the user is currently
083       *   viewing.  See {@link #folder}.
084       * @param addressBook - The user's address book.  See
085       *   {@link #addressBook}.
086       * @param formParser - The parsed contents of the
087       *   form.  The {@link WriteFormParser#parseFormData()} method
088       *   must have been invoked prior to initialising this class.
089       * @param session - The web session.  See {@link #session}.
090       */
091      public SendHandler( Folder folder, AddressBook addressBook, 
092          WriteFormParser formParser, Session session )
093      {
094        this.folder = folder;
095        this.addressBook = addressBook;
096        this.formParser = formParser;
097        this.session = session;
098      }
099    
100      /**
101       * Creates the appropriate type of message.  Fetches all the
102       * attachments and properties for the new message from the
103       * {@link WriteFormParser} and creates the new <code>Message</code>.
104       * If no attachments were specified in the <code>form post</code>,
105       * a "text/plain" message is created, otherwise a "multipart/mixed" 
106       * message is created.
107       *
108       * @see #createMessage( Message )
109       *
110       * @return Message - The new message with all the message attributes
111       *   including attachments set.
112       * @throws MessagingException - If any exceptions are encountered
113       *   while creating the new message.
114       * @throws IOException - If errors are encountered while setting
115       *   the body of the message.
116       */
117      public Message createMessage() throws MessagingException, IOException
118      {
119        int replyNumber = 0;
120        if ( formParser.getReply() != null && ! formParser.getReply().equals( "" ) )
121        {
122          try
123          {
124            replyNumber = Integer.parseInt( formParser.getReply() );
125          }
126          catch ( NumberFormatException nfe )
127          {
128            // Nothing to be done
129          }
130        }
131    
132        if ( replyNumber > 0 )
133        {
134          message = folder.getMessage( replyNumber ).reply( false );
135        }
136        else
137        {
138          message = new MimeMessage( session );
139        }
140    
141        setMessageAttributes();
142        setMessageBody();
143        return message;
144      }
145    
146      /**
147       * Creates the appropriate type of message for forwarded mail.  
148       * Fetches all the attachments and properties for the new message 
149       * from the {@link WriteFormParser} and creates the new 
150       * <code>Message</code>.  This method also attaches any attachments 
151       * that were originally part of the specified message to the new 
152       * message being composed.
153       *
154       * @param currentMessage - The {@link 
155       *   WebMailBean#currentMessage} that is being forwarded.
156       * @return Message - The new message with all the message attributes
157       *   including attachments set.
158       * @throws MessagingException - If any exceptions are encountered
159       *   while creating the new message.
160       * @throws IOException - If errors are encountered while setting
161       *   the body of the message.
162       */
163      public Message createMessage( Message currentMessage ) 
164        throws MessagingException, IOException
165      {
166        message = currentMessage.reply( false );
167        setMessageAttributes();
168        setForwardBody( currentMessage );
169        return message;
170      }
171    
172      /**
173       * Set the common attributes for the {@link #message}.  The common 
174       * attributes set are <code>from, to, cc, bcc, subject</code>.
175       * The attributes are fetched from the <code>HttpServetRequest</code>
176       * and added to the new message.  Simply calls the appropriate 
177       * <code>methods</code> for setting the attributes.
178       *
179       * @see #setFrom()
180       * @see #setTo()
181       * @see #setCc()
182       * @see #setBcc()
183       * @see #setSubject()
184       *
185       * @throws MessagingException - If any exceptions are encountered
186       *   while creating the new message.
187       */
188      private void setMessageAttributes()
189        throws MessagingException
190      {
191        setFrom();
192        setTo();
193        setCc();
194        setBcc();
195        setSubject();
196        setDate();
197      }
198    
199      /**
200       * Set the <code>from</code> attribute of the new message.
201       *
202       * @throws MessagingException - If any exceptions are encountered
203       *   while creating the new message.
204       */
205      private void setFrom()
206        throws MessagingException
207      {
208        message.setFrom( new InternetAddress( formParser.getFrom() ) );
209      }
210    
211      /**
212       * Set the <code>to</code> attribute of the new message.
213       *
214       * @throws MessagingException - If any exceptions are encountered
215       *   while creating the new message.
216       */
217      private void setTo()
218        throws MessagingException
219      {
220        String to = formParser.getTo();
221    
222        StringBuffer toBuffer = new StringBuffer();
223        if ( formParser.getPersons() != null )
224        {
225          for ( Iterator iterator = formParser.getPersons().iterator(); iterator.hasNext(); )
226          {
227            String entry = (String) iterator.next();
228    
229            if ( ! entry.equals( "" ) )
230            {
231              Person person = (Person) addressBook.getPersons().get( entry );
232              toBuffer.append( person.getMail() ).append( "," );
233            }
234          }
235        }
236        if ( formParser.getGroups() != null )
237        {
238          for ( Iterator iterator = formParser.getGroups().iterator(); iterator.hasNext(); )
239          {
240            String entry = (String) iterator.next();
241    
242            if ( ! entry.equals( "" ) )
243            {
244              Group group = (Group) addressBook.getGroups().get( entry );
245              List list = group.getMembers();
246              for ( Iterator iter = list.iterator(); iter.hasNext(); )
247              {
248                Member member = (Member) iter.next();
249                toBuffer.append( member.getMail() ).append( "," );
250              }
251            }
252          }
253        }
254        if ( to != null )
255        {
256          message.setRecipients( Message.RecipientType.TO,
257            InternetAddress.parse( to ) );
258    
259          if ( toBuffer.length() > 1 )
260          {
261            message.addRecipients( Message.RecipientType.TO,
262              InternetAddress.parse( toBuffer.substring( 0, toBuffer.length() - 1 ) ) );
263          }
264        }
265        else if ( toBuffer.length() > 1 )
266        {
267          message.addRecipients( 
268              Message.RecipientType.TO, 
269              InternetAddress.parse( 
270                toBuffer.substring( 0, toBuffer.length() - 1 ) 
271              ) 
272          );
273        }
274      }
275    
276      /**
277       * Set the <code>cc</code> attribute for the message.
278       *
279       * @throws MessagingException - If any exceptions are encountered
280       *   while creating the new message.
281       */
282      private void setCc()
283        throws MessagingException
284      {
285        String cc = formParser.getCc();
286    
287        if ( cc != null )
288        {
289          message.setRecipients( 
290              Message.RecipientType.CC, 
291              InternetAddress.parse( cc ) 
292          );
293        }
294      }
295    
296      /**
297       * Set the <code>bcc</code> attribute for the message.
298       *
299       * @throws MessagingException - If any exceptions are encountered
300       *   while creating the new message.
301       */
302      private void setBcc()
303        throws MessagingException
304      {
305        String bcc = formParser.getBcc();
306        if ( bcc != null )
307        {
308          message.setRecipients( 
309              Message.RecipientType.BCC, 
310              InternetAddress.parse( bcc ) 
311          );
312        }
313      }
314    
315      /**
316       * Set the <code>subject</code> attribute for the message.
317       *
318       * @throws MessagingException - If any exceptions are encountered
319       *   while creating the new message.
320       */
321      private void setSubject()
322        throws MessagingException
323      {
324        message.setSubject( formParser.getSubject() );
325      }
326    
327      /**
328       * Set the <code>date</code> attribute for the message.
329       *
330       * @throws MessagingException - If any exceptions are encountered
331       *   while creating the new message.
332       */
333      private void setDate()
334        throws MessagingException
335      {
336        message.setSentDate( new Date() );
337      }
338    
339      /**
340       * Sets the various body parts for the {@link #message}.  If no 
341       * attachments were included in the form post, or if no attachments 
342       * were associated with the message to which this new message is a 
343       * reply to, then a plain-text message will be created.  Otherwise,
344       * a message with multiple body parts will be created.
345       *
346       * @see #setBodyWithAttachments
347       *
348       * @throws MessagingException - If errors are encountered while 
349       *   setting the message body.
350       * @throws IOException - If errors are encountered while fetching
351       *   the content from the existing message.
352       */
353      private void setMessageBody() throws MessagingException, IOException
354      {
355        if ( formParser.getAttachments() != null && ! formParser.getAttachments().isEmpty() )
356        {
357          setBodyWithAttachments();
358        }
359        else
360        {
361          message.setText( formParser.getBody() );
362        }
363      }
364    
365      /**
366       * Set the body parts for the forwarded message.  If the original 
367       * message was a multipart message, then add all the original parts 
368       * of the message to the new message.  Also add any additional
369       * attachments added to the current new message.
370       *
371       * @param originalMessage - The message which is being
372       *   forwarded.
373       * @throws MessagingException - If errors are encountered while
374       *   adding the body to the reply message.
375       * @throws IOException - If errors are encountered while fetching
376       *   the content from the existing message.
377       */
378      private void setForwardBody( Message originalMessage ) 
379        throws MessagingException, IOException
380      {
381        Multipart multipart = new MimeMultipart();
382    
383        if ( message.isMimeType( "multipart/*" ) || ! formParser.getAttachments().isEmpty() )
384        {
385          // Add the new message body as the first part
386          BodyPart bodyPart = new MimeBodyPart();
387          bodyPart.setText( formParser.getBody() );
388          multipart.addBodyPart( bodyPart );
389    
390          // Add any new attachments added to this message
391          if ( ! formParser.getAttachments().isEmpty() )
392          {
393            for ( Iterator iterator = formParser.getAttachments().iterator(); iterator.hasNext(); )
394            {
395              multipart.addBodyPart( (BodyPart) iterator.next() );
396            }
397          }
398          
399          Multipart oldPart = (Multipart) originalMessage.getContent();
400          int count = oldPart.getCount();
401          // Add any old attachments to the new message
402          for ( int i = 1; i < count; ++i )
403          {
404            multipart.addBodyPart( oldPart.getBodyPart( i ) );
405          }
406    
407          message.setContent( multipart );
408        }
409        else
410        {
411          message.setText( formParser.getBody() );
412        }
413      }
414    
415      /**
416       * Set the body parts for the reply.  If the original message was
417       * a multipart message, then add all the original parts of the
418       * message to the new message.
419       *
420       * @throws MessagingException - If errors are encountered while
421       *   setting the body of the new message.
422       */
423      private void setBodyWithAttachments() throws MessagingException, IOException
424      {
425        Multipart multipart = new MimeMultipart();
426    
427        // Add the new message body as the first part
428        BodyPart bodyPart = new MimeBodyPart();
429        bodyPart.setText( formParser.getBody() );
430        multipart.addBodyPart( bodyPart );
431    
432        // Add the other attachments extracted from the form
433        for ( Iterator iterator = formParser.getAttachments().iterator(); iterator.hasNext(); )
434        {
435          multipart.addBodyPart( (BodyPart) iterator.next() );
436        }
437        
438        message.setContent( multipart );
439      }
440    }