001    package com.saelist.command;
002    
003    import org.apache.log4j.*;
004    import java.io.*;
005    import java.net.*;
006    import java.util.*;
007    import com.saelist.stx.*;
008    import com.saelist.stx.parser.*;
009    import com.saelist.util.*;
010    
011    import javax.mail.*;
012    import javax.mail.internet.*;
013    import javax.activation.*;
014    
015    /**
016      Sends messages in a structured text file to email recipients.
017      * See the schema file for exact format of the message file.
018     */
019    public class SmtpCommand extends AbstractCommand {
020    
021      protected static Logger logger = Logger.getLogger("com.saelist.command.SmtpCommand");
022    
023      /**
024       *
025       */
026      public void execute() throws CommandException {
027    
028        Writer sentbox = null;
029        Writer problembox = null;
030    
031        try {
032    
033          Properties props = System.getProperties();
034          props.put("file.encoding", "UTF-8");
035          props.put("mail.smtp.host", config.eval("smpt/host"));
036          Session session = Session.getDefaultInstance(props, null);
037          session.setDebug("true".equals(config.eval("smtp/debug")));
038    
039          // Add any messages in outbox to config.
040    
041          if(config.select1("storage/out-box") != null) {
042            Pair outbox = LstxParser.parse(Strings.loadFile(config.eval1("storage/out-box")));
043            // System.out.println("outbox=" + outbox);
044            for(Iterator messages = outbox.select("message"); messages.hasNext(); )
045              config.add(((Pair) messages.next()).copy());
046          }
047    
048          // Open the sentbox and the problem box if specified.
049    
050          if(config.select1("storage/sent-box") != null)
051            sentbox = new BufferedWriter(new FileWriter(config.eval1("storage/sent-box")));
052          if(config.select1("storage/problem-box") != null)
053            problembox = new BufferedWriter(new FileWriter(config.eval1("storage/problem-box")));
054    
055          // Send each message.
056    
057          for(Iterator messages = config.select("message"); messages.hasNext(); ) {
058            Exception exception = null;
059            Pair message = (Pair) messages.next();
060            try {
061              MimeMessage mimeMessage = new MimeMessage(session);
062              mimeMessage.setFrom(new InternetAddress(message.eval("from")));
063              addAddresses(mimeMessage, Message.RecipientType.TO, message.select("to/*"));
064              addAddresses(mimeMessage, Message.RecipientType.CC, message.select("cc/*"));
065              addAddresses(mimeMessage, Message.RecipientType.BCC, message.select("bcc/*"));
066              mimeMessage.setSubject(message.eval("subject"), "UTF-8");
067              mimeMessage.setContent(createContent(message));
068              mimeMessage.setSentDate(new Date());
069              mimeMessage.setHeader("X-Mailer", getClass().getName());
070    
071              Transport.send(mimeMessage);
072    
073    
074              if(sentbox != null)
075                store(sentbox, message);
076    
077            } catch(AddressException e) {
078              exception = e;
079            } catch(MessagingException e) {
080              exception = e;
081            } catch(UnsupportedEncodingException e) {
082              exception = e;
083            }
084    
085            //Log any message level problem and store a failed message in the problem box.
086    
087            if(exception != null) {
088              logger.error(exception);
089              if(problembox != null) {
090                Pair msg = message.copy();
091                Pair status = new Pair(message, "status");
092                Pair value = new Pair(status, exception.toString());
093                status.add(value);
094                msg.add(status);
095                store(problembox, msg);
096              }
097            }
098          }
099    
100        } catch(IOException e) {
101    
102          // Let the caller handle session level problems.
103          throw new CommandException(e);
104    
105        } finally {
106          try {
107            if(sentbox != null) {
108              sentbox.flush();
109              sentbox.close();
110            }
111            if(problembox != null) {
112              problembox.flush();
113              problembox.close();
114            }
115          } catch(IOException e) {
116            throw new CommandException(e);
117          }
118        }
119      }
120    
121      private void store(Writer box, Pair message) throws IOException {
122        Pair root = new Pair(null, "root");
123        root.add(message.copy());
124        LstxParser.unParse(box, root);
125      }
126    
127      private void addAddresses(MimeMessage mimeMessage, Message.RecipientType type,  Iterator recipients) throws AddressException, MessagingException {
128        while(recipients.hasNext())
129          mimeMessage.addRecipients(type, InternetAddress.parse(((Pair) recipients.next()).getText()));
130      }
131    
132      private Multipart createContent(Pair message) throws UnsupportedEncodingException, MessagingException {
133    
134        Multipart multipart = new MimeMultipart();
135    
136        // Add the body text
137    
138        MimeBodyPart part = new MimeBodyPart();
139    
140        if("true".equals(message.eval("is-html"))) {
141          part.setContent(concat(message.select("text/*")), "text/html;charset=UTF-8");
142          part.setHeader("Content-Type", "text/html;charset=UTF-8");
143          part.setHeader("Content-Transfer-Encoding", "8bit");
144        } else
145          part.setText(concat(message.select("text/*")), "UTF-8");
146    
147        multipart.addBodyPart(part);
148    
149        // Add the attachements
150    
151        for(Iterator attatchments = message.select("attachment/*"); attatchments.hasNext(); ) {
152          String attachment = ((Pair) attatchments.next()).getText();
153          File file = new File(attachment);
154          part = new MimeBodyPart();
155          DataSource source = new FileDataSource(attachment);
156          part.setDataHandler(new DataHandler(source));
157          // part.setHeader("Content-Type", "applications/msword");
158          part.setFileName(file.getName());
159          multipart.addBodyPart(part);
160        }
161    
162        return multipart;
163    
164      }
165    
166      /** Concatenate the texts of the incoming pairs separating with linefeeds. */
167      private String concat(Iterator lines) {
168        String text = "";
169        while(lines.hasNext())
170          text += ((Pair) lines.next()).getText() + "\n";
171        return text;
172      }
173    
174    }