View Javadoc

1   /****************************************************************
2    * Licensed to the Apache Software Foundation (ASF) under one   *
3    * or more contributor license agreements.  See the NOTICE file *
4    * distributed with this work for additional information        *
5    * regarding copyright ownership.  The ASF licenses this file   *
6    * to you under the Apache License, Version 2.0 (the            *
7    * "License"); you may not use this file except in compliance   *
8    * with the License.  You may obtain a copy of the License at   *
9    *                                                              *
10   *   http://www.apache.org/licenses/LICENSE-2.0                 *
11   *                                                              *
12   * Unless required by applicable law or agreed to in writing,   *
13   * software distributed under the License is distributed on an  *
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15   * KIND, either express or implied.  See the License for the    *
16   * specific language governing permissions and limitations      *
17   * under the License.                                           *
18   ****************************************************************/
19  
20  
21  
22  package org.apache.james.transport.mailets;
23  
24  import org.apache.avalon.cornerstone.services.datasources.DataSourceSelector;
25  import org.apache.avalon.excalibur.datasource.DataSourceComponent;
26  import org.apache.avalon.framework.service.ServiceManager;
27  import org.apache.james.Constants;
28  import org.apache.james.api.user.JamesUser;
29  import org.apache.james.api.user.UsersRepository;
30  import org.apache.james.util.sql.JDBCUtil;
31  import org.apache.james.util.sql.SqlResources;
32  import org.apache.mailet.base.GenericMailet;
33  import org.apache.mailet.Mail;
34  import org.apache.mailet.MailAddress;
35  import org.apache.mailet.base.RFC2822Headers;
36  import org.apache.mailet.base.RFC822DateFormat;
37  
38  import javax.mail.Message;
39  import javax.mail.MessagingException;
40  import javax.mail.Session;
41  import javax.mail.internet.InternetAddress;
42  import javax.mail.internet.MimeBodyPart;
43  import javax.mail.internet.MimeMessage;
44  import javax.mail.internet.MimeMultipart;
45  
46  import java.io.File;
47  import java.io.IOException;
48  import java.io.PrintWriter;
49  import java.io.StringWriter;
50  import java.sql.Connection;
51  import java.sql.DatabaseMetaData;
52  import java.sql.PreparedStatement;
53  import java.sql.ResultSet;
54  import java.sql.SQLException;
55  import java.util.Collection;
56  import java.util.HashMap;
57  import java.util.HashSet;
58  import java.util.Iterator;
59  import java.util.Locale;
60  import java.util.Map;
61  import java.util.Set;
62  import java.util.StringTokenizer;
63  
64  /** <P>Manages for each local user a "white list" of remote addresses whose messages
65   * should never be blocked as spam.</P>
66   * <P>The normal behaviour is to check, for a local sender, if a remote recipient
67   * is already in the list: if not, it will be automatically inserted.
68   * This is under the interpretation that if a local sender <I>X</I> sends a message to a
69   * remote recipient <I>Y</I>, then later on if a message is sent by <I>Y</I> to <I>X</I> it should be
70   * considered always valid and never blocked; hence <I>Y</I> should be in the white list
71   * of <I>X</I>.</P>
72   * <P>Another mode of operations is when a local sender sends a message to <I>whitelistManagerAddress</I>
73   * with one of three specific values in the subject, to
74   * (i) send back a message displaying a list of the addresses in his own list;
75   * (ii) insert some new addresses in his own list;
76   * (iii) remove some addresses from his own list.
77   * In all this cases the message will be ghosted and the postmaster will reply
78   * to the sender.</P>
79   * <P> The sender name is always converted to its primary name (handling aliases).</P>
80   * <P>Sample configuration:</P>
81   * <PRE><CODE>
82   * &lt;mailet match="SMTPAuthSuccessful" class="WhiteListManager"&gt;
83   *   &lt;repositoryPath&gt; db://maildb &lt;/repositoryPath&gt;
84   *   &lt;!--
85   *     If true automatically inserts the local sender to remote recipients entries in the whitelist (default is false).
86   *   --&gt;
87   *   &lt;automaticInsert&gt;true&lt;/automaticInsert&gt;
88   *   &lt;!--
89   *     Set this to an email address of the "whitelist manager" to send commands to (default is null).
90   *   --&gt;
91   *   &lt;whitelistManagerAddress&gt;whitelist.manager@xxx.yyy&lt;/whitelistManagerAddress&gt;
92   *   &lt;!--
93   *     Set this to a unique text that you can use (by sending a message to the "whitelist manager" above)
94   *     to tell the mailet to send back the contents of the white list (default is null).
95   *   --&gt;
96   *   &lt;displayFlag&gt;display whitelist&lt;/displayFlag&gt;
97   *   &lt;!--
98   *     Set this to a unique text that you can use (by sending a message to the "whitelist manager" above)
99   *     to tell the mailet to insert some new remote recipients to the white list (default is null).
100  *   --&gt;
101  *   &lt;insertFlag&gt;insert whitelist&lt;/insertFlag&gt;
102  *   &lt;!--
103  *     Set this to a unique text that you can use (by sending a message to the "whitelist manager" above)
104  *     to tell the mailet to remove some remote recipients from the white list (default is null).
105  *   --&gt;
106  *   &lt;removeFlag&gt;remove whitelist&lt;/removeFlag&gt;
107  * &lt;/mailet&gt;
108  * </CODE></PRE>
109  *
110  * @see org.apache.james.transport.matchers.IsInWhiteList
111  * @version SVN $Revision: $ $Date: $
112  * @since 2.3.0
113  */
114 public class WhiteListManager extends GenericMailet {
115     
116     private boolean automaticInsert;
117     private String displayFlag;
118     private String insertFlag;
119     private String removeFlag;
120     private MailAddress whitelistManagerAddress;
121     
122     private String selectByPK;
123     private String selectBySender;
124     private String insert;
125     private String deleteByPK;
126     
127     /** The date format object used to generate RFC 822 compliant date headers. */
128     private RFC822DateFormat rfc822DateFormat = new RFC822DateFormat();
129 
130     private DataSourceComponent datasource;
131 
132     /** The user repository for this mail server.  Contains all the users with inboxes
133      * on this server.
134      */
135     private UsersRepository localusers;
136 
137     /**
138      * The JDBCUtil helper class
139      */
140     private final JDBCUtil theJDBCUtil = new JDBCUtil() {
141         protected void delegatedLog(String logString) {
142             log("WhiteListManager: " + logString);
143         }
144     };
145     
146     /**
147      * Contains all of the sql strings for this component.
148      */
149     private SqlResources sqlQueries = new SqlResources();
150 
151     /**
152      * Holds value of property sqlFile.
153      */
154     private File sqlFile;
155 
156      /**
157      * Holds value of property sqlParameters.
158      */
159     private Map sqlParameters = new HashMap();
160 
161     /**
162      * Getter for property sqlParameters.
163      * @return Value of property sqlParameters.
164      */
165     private Map getSqlParameters() {
166 
167         return this.sqlParameters;
168     }
169 
170     /** Initializes the mailet.
171      */
172     public void init() throws MessagingException {
173         automaticInsert = new Boolean(getInitParameter("automaticInsert")).booleanValue();
174         log("automaticInsert: " + automaticInsert);
175 
176         displayFlag = getInitParameter("displayFlag");
177         insertFlag = getInitParameter("insertFlag");
178         removeFlag = getInitParameter("removeFlag");
179         
180         String whitelistManagerAddressString = getInitParameter("whitelistManagerAddress");
181         if (whitelistManagerAddressString != null) {
182             whitelistManagerAddressString = whitelistManagerAddressString.trim();
183             log("whitelistManagerAddress: " + whitelistManagerAddressString);
184             try {
185                 whitelistManagerAddress = new MailAddress(whitelistManagerAddressString);
186             }
187             catch (javax.mail.internet.ParseException pe) {
188                 throw new MessagingException("Bad whitelistManagerAddress", pe);
189             }
190             
191             if (displayFlag != null) {
192                 displayFlag = displayFlag.trim();
193                 log("displayFlag: " + displayFlag);
194             }
195             else {
196                 log("displayFlag is null");
197             }
198             if (insertFlag != null) {
199                 insertFlag = insertFlag.trim();
200                 log("insertFlag: " + insertFlag);
201             }
202             else {
203                 log("insertFlag is null");
204             }
205             if (removeFlag != null) {
206                 removeFlag = removeFlag.trim();
207                 log("removeFlag: " + removeFlag);
208             }
209             else {
210                 log("removeFlag is null");
211             }
212         }
213         else {
214             log("whitelistManagerAddress is null; will ignore commands");
215         }
216         
217         String repositoryPath = getInitParameter("repositoryPath");
218         if (repositoryPath != null) {
219             log("repositoryPath: " + repositoryPath);
220         }
221         else {
222             throw new MessagingException("repositoryPath is null");
223         }
224 
225         ServiceManager serviceManager = (ServiceManager) getMailetContext().getAttribute(Constants.AVALON_COMPONENT_MANAGER);
226 
227         try {
228             // Get the DataSourceSelector block
229             DataSourceSelector datasources = (DataSourceSelector) serviceManager.lookup(DataSourceSelector.ROLE);
230             // Get the data-source required.
231             int stindex =   repositoryPath.indexOf("://") + 3;
232             String datasourceName = repositoryPath.substring(stindex);
233             datasource = (DataSourceComponent) datasources.select(datasourceName);
234         } catch (Exception e) {
235             throw new MessagingException("Can't get datasource", e);
236         }
237 
238          try {
239             // Get the UsersRepository
240             localusers = (UsersRepository)serviceManager.lookup(UsersRepository.ROLE);
241         } catch (Exception e) {
242             throw new MessagingException("Can't get the local users repository", e);
243         }
244 
245         try {
246             initSqlQueries(datasource.getConnection(), getMailetContext());
247         } catch (Exception e) {
248             throw new MessagingException("Exception initializing queries", e);
249         }        
250         
251         selectByPK = sqlQueries.getSqlString("selectByPK", true);
252         selectBySender = sqlQueries.getSqlString("selectBySender", true);
253         insert = sqlQueries.getSqlString("insert", true);
254         deleteByPK = sqlQueries.getSqlString("deleteByPK", true);
255     }
256     
257     /** Services the mailet.
258      */    
259     public void service(Mail mail) throws MessagingException {
260         
261         // check if it's a local sender
262         MailAddress senderMailAddress = mail.getSender();
263         if (senderMailAddress == null) {
264             return;
265         }
266         if (!getMailetContext().isLocalEmail(senderMailAddress)) {
267             // not a local sender, so return
268             return;
269         }
270         
271         Collection recipients = mail.getRecipients();
272         
273         if (recipients.size() == 1
274         && whitelistManagerAddress != null
275         && whitelistManagerAddress.equals(recipients.toArray()[0])) {
276             
277             mail.setState(Mail.GHOST);
278         
279             String subject = mail.getMessage().getSubject();
280             if (displayFlag != null && displayFlag.equals(subject)) {
281                 manageDisplayRequest(mail);
282             }
283             else if (insertFlag != null && insertFlag.equals(subject)) {
284                 manageInsertRequest(mail);
285             }
286             else if (removeFlag != null && removeFlag.equals(subject)) {
287                 manageRemoveRequest(mail);
288             }
289             else {
290                 StringWriter sout = new StringWriter();
291                 PrintWriter out = new PrintWriter(sout, true);
292                 out.println("Answering on behalf of: " + whitelistManagerAddress);
293                 out.println("ERROR: Unknown command in the subject line: " + subject);
294                 sendReplyFromPostmaster(mail, sout.toString());
295             }
296             return;
297         }
298         
299         if (automaticInsert) {
300             checkAndInsert(senderMailAddress, recipients);
301         }
302         
303     }
304     
305     /** Returns a string describing this mailet.
306      *
307      * @return a string describing this mailet
308      */
309     public String getMailetInfo() {
310         return "White List Manager mailet";
311     }
312     
313     /** Loops through each address in the recipient list, checks if in the senders
314      * list and inserts in it otherwise.
315      */    
316     private void checkAndInsert(MailAddress senderMailAddress, Collection recipients) throws MessagingException {
317         String senderUser = senderMailAddress.getUser().toLowerCase(Locale.US);
318         String senderHost = senderMailAddress.getHost().toLowerCase(Locale.US);
319         
320         senderUser = getPrimaryName(senderUser);
321         
322         Connection conn = null;
323         PreparedStatement selectStmt = null;
324         PreparedStatement insertStmt = null;
325         boolean dbUpdated = false;
326         
327         try {
328             
329             for (Iterator i = recipients.iterator(); i.hasNext(); ) {
330                 ResultSet selectRS = null;
331                 try {
332                     MailAddress recipientMailAddress = (MailAddress)i.next();
333                     String recipientUser = recipientMailAddress.getUser().toLowerCase(Locale.US);
334                     String recipientHost = recipientMailAddress.getHost().toLowerCase(Locale.US);
335                     
336                     if (getMailetContext().isLocalServer(recipientHost)) {
337                         // not a remote recipient, so skip
338                         continue;
339                     }
340                     
341                     if (conn == null) {
342                         conn = datasource.getConnection();
343                     }
344                     
345                     if (selectStmt == null) {
346                         selectStmt = conn.prepareStatement(selectByPK);
347                     }
348                     selectStmt.setString(1, senderUser);
349                     selectStmt.setString(2, senderHost);
350                     selectStmt.setString(3, recipientUser);
351                     selectStmt.setString(4, recipientHost);
352                     selectRS = selectStmt.executeQuery();
353                     if (selectRS.next()) {
354                         //This address was already in the list
355                         continue;
356                     }
357                     
358                     if (insertStmt == null) {
359                         insertStmt = conn.prepareStatement(insert);
360                     }
361                     insertStmt.setString(1, senderUser);
362                     insertStmt.setString(2, senderHost);
363                     insertStmt.setString(3, recipientUser);
364                     insertStmt.setString(4, recipientHost);
365                     insertStmt.executeUpdate();
366                     dbUpdated = true;
367                     
368                 } finally {
369                     theJDBCUtil.closeJDBCResultSet(selectRS);
370                 }
371                 
372                 //Commit our changes if necessary.
373                 if (conn != null && dbUpdated && !conn.getAutoCommit()) {
374                     conn.commit();
375                     dbUpdated = false;
376                 }
377             }
378         } catch (SQLException sqle) {
379             log("Error accessing database", sqle);
380             throw new MessagingException("Exception thrown", sqle);
381         } finally {
382             theJDBCUtil.closeJDBCStatement(selectStmt);
383             theJDBCUtil.closeJDBCStatement(insertStmt);
384             //Rollback our changes if necessary.
385             try {
386                 if (conn != null && dbUpdated && !conn.getAutoCommit()) {
387                     conn.rollback();
388                     dbUpdated = false;
389                 }
390             }
391             catch (Exception e) {}
392             theJDBCUtil.closeJDBCConnection(conn);
393         }
394     }
395     
396     /** Manages a display request.
397      */    
398     private void manageDisplayRequest(Mail mail)
399     throws MessagingException {
400         MailAddress senderMailAddress = mail.getSender();
401         String senderUser = senderMailAddress.getUser().toLowerCase(Locale.US);
402         String senderHost = senderMailAddress.getHost().toLowerCase(Locale.US);
403         
404         senderUser = getPrimaryName(senderUser);
405         
406         Connection conn = null;
407         PreparedStatement selectStmt = null;
408         ResultSet selectRS = null;
409         
410         StringWriter sout = new StringWriter();
411         PrintWriter out = new PrintWriter(sout, true);
412         
413         try {
414             out.println("Answering on behalf of: " + whitelistManagerAddress);
415             out.println("Displaying white list of " + (new MailAddress(senderUser, senderHost)) + ":");
416             out.println();
417             
418             conn = datasource.getConnection();
419             selectStmt = conn.prepareStatement(selectBySender);
420             selectStmt.setString(1, senderUser);
421             selectStmt.setString(2, senderHost);
422             selectRS = selectStmt.executeQuery();
423             while (selectRS.next()) {
424                 MailAddress mailAddress =
425                     new MailAddress(selectRS.getString(1), selectRS.getString(2));
426                 out.println(mailAddress.toInternetAddress().toString());
427             }
428             
429             out.println();
430             out.println("Finished");
431             
432             sendReplyFromPostmaster(mail, sout.toString());
433                         
434         } catch (SQLException sqle) {
435             out.println("Error accessing the database");
436             sendReplyFromPostmaster(mail, sout.toString());
437             throw new MessagingException("Error accessing database", sqle);
438         } finally {
439             theJDBCUtil.closeJDBCResultSet(selectRS);
440             theJDBCUtil.closeJDBCStatement(selectStmt);
441             theJDBCUtil.closeJDBCConnection(conn);
442         }
443     }
444     
445     /** Manages an insert request.
446      */    
447     private void manageInsertRequest(Mail mail)
448     throws MessagingException {
449         MailAddress senderMailAddress = mail.getSender();
450         String senderUser = senderMailAddress.getUser().toLowerCase(Locale.US);
451         String senderHost = senderMailAddress.getHost().toLowerCase(Locale.US);
452         
453         senderUser = getPrimaryName(senderUser);
454         
455         Connection conn = null;
456         PreparedStatement selectStmt = null;
457         PreparedStatement insertStmt = null;
458         boolean dbUpdated = false;
459         
460         StringWriter sout = new StringWriter();
461         PrintWriter out = new PrintWriter(sout, true);
462         
463         try {
464             out.println("Answering on behalf of: " + whitelistManagerAddress);
465             out.println("Inserting in the white list of " + (new MailAddress(senderUser, senderHost)) + " ...");
466             out.println();
467             
468             MimeMessage message = mail.getMessage() ;
469             
470             Object content= message.getContent();
471             
472             if (message.getContentType().startsWith("text/plain")
473             && content instanceof String) {
474                 StringTokenizer st = new StringTokenizer((String) content, " \t\n\r\f,;:<>");
475                 while (st.hasMoreTokens()) {
476                     ResultSet selectRS = null;
477                     try {
478                         MailAddress recipientMailAddress;
479                         try {
480                             recipientMailAddress = new MailAddress(st.nextToken());
481                         }
482                         catch (javax.mail.internet.ParseException pe) {
483                             continue;
484                         }
485                         String recipientUser = recipientMailAddress.getUser().toLowerCase(Locale.US);
486                         String recipientHost = recipientMailAddress.getHost().toLowerCase(Locale.US);
487                         
488                         if (getMailetContext().isLocalServer(recipientHost)) {
489                             // not a remote recipient, so skip
490                             continue;
491                         }
492                         
493                         if (conn == null) {
494                             conn = datasource.getConnection();
495                         }
496                         
497                         if (selectStmt == null) {
498                             selectStmt = conn.prepareStatement(selectByPK);
499                         }
500                         selectStmt.setString(1, senderUser);
501                         selectStmt.setString(2, senderHost);
502                         selectStmt.setString(3, recipientUser);
503                         selectStmt.setString(4, recipientHost);
504                         selectRS = selectStmt.executeQuery();
505                         if (selectRS.next()) {
506                             //This address was already in the list
507                             out.println("Skipped:  " + recipientMailAddress);
508                             continue;
509                         }
510                         
511                         if (insertStmt == null) {
512                             insertStmt = conn.prepareStatement(insert);
513                         }
514                         insertStmt.setString(1, senderUser);
515                         insertStmt.setString(2, senderHost);
516                         insertStmt.setString(3, recipientUser);
517                         insertStmt.setString(4, recipientHost);
518                         insertStmt.executeUpdate();
519                         dbUpdated = true;
520                         out.println("Inserted: " + recipientMailAddress);
521                         
522                     } finally {
523                         theJDBCUtil.closeJDBCResultSet(selectRS);
524                     }
525                 }
526                 
527                 if (dbUpdated) {
528                     log("Insertion request issued by " + senderMailAddress);
529                 }
530                 //Commit our changes if necessary.
531                 if (conn != null && dbUpdated && !conn.getAutoCommit()) {
532                     conn.commit() ;
533                     dbUpdated = false;
534                 }
535             }
536             else {
537                 out.println("The message must be plain - no action");
538             }
539             
540             out.println();
541             out.println("Finished");
542             
543             sendReplyFromPostmaster(mail, sout.toString());
544             
545         } catch (SQLException sqle) {
546             out.println("Error accessing the database");
547             sendReplyFromPostmaster(mail, sout.toString());
548             throw new MessagingException("Error accessing the database", sqle);
549         } catch (IOException ioe) {
550             out.println("Error getting message content");
551             sendReplyFromPostmaster(mail, sout.toString());
552             throw new MessagingException("Error getting message content", ioe);
553         } finally {
554             theJDBCUtil.closeJDBCStatement(selectStmt);
555             theJDBCUtil.closeJDBCStatement(insertStmt);
556             //Rollback our changes if necessary.
557             try {
558                 if (conn != null && dbUpdated && !conn.getAutoCommit()) {
559                     conn.rollback() ;
560                     dbUpdated = false;
561                 }
562             }
563             catch (Exception e) {}
564             theJDBCUtil.closeJDBCConnection(conn);
565         }
566     }
567     
568     /** Manages a remove request.
569      */    
570     private void manageRemoveRequest(Mail mail)
571     throws MessagingException {
572         MailAddress senderMailAddress = mail.getSender();
573         String senderUser = senderMailAddress.getUser().toLowerCase(Locale.US);
574         String senderHost = senderMailAddress.getHost().toLowerCase(Locale.US);
575         
576         senderUser = getPrimaryName(senderUser);
577         
578         Connection conn = null;
579         PreparedStatement selectStmt = null;
580         PreparedStatement deleteStmt = null;
581         boolean dbUpdated = false;
582         
583         StringWriter sout = new StringWriter();
584         PrintWriter out = new PrintWriter(sout, true);
585         
586         try {
587             out.println("Answering on behalf of: " + whitelistManagerAddress);
588             out.println("Removing from the white list of " + (new MailAddress(senderUser, senderHost)) + " ...");
589             out.println();
590             
591             MimeMessage message = mail.getMessage() ;
592             
593             Object content= message.getContent();
594             
595             if (message.getContentType().startsWith("text/plain")
596             && content instanceof String) {
597                 StringTokenizer st = new StringTokenizer((String) content, " \t\n\r\f,;:<>");
598                 while (st.hasMoreTokens()) {
599                     ResultSet selectRS = null;
600                     try {
601                         MailAddress recipientMailAddress;
602                         try {
603                             recipientMailAddress = new MailAddress(st.nextToken());
604                         }
605                         catch (javax.mail.internet.ParseException pe) {
606                             continue;
607                         }
608                         String recipientUser = recipientMailAddress.getUser().toLowerCase(Locale.US);
609                         String recipientHost = recipientMailAddress.getHost().toLowerCase(Locale.US);
610                         
611                         if (getMailetContext().isLocalServer(recipientHost)) {
612                             // not a remote recipient, so skip
613                             continue;
614                         }
615                         
616                         if (conn == null) {
617                             conn = datasource.getConnection();
618                         }
619                         
620                         if (selectStmt == null) {
621                             selectStmt = conn.prepareStatement(selectByPK);
622                         }
623                         selectStmt.setString(1, senderUser);
624                         selectStmt.setString(2, senderHost);
625                         selectStmt.setString(3, recipientUser);
626                         selectStmt.setString(4, recipientHost);
627                         selectRS = selectStmt.executeQuery();
628                         if (!selectRS.next()) {
629                             //This address was not in the list
630                             out.println("Skipped: " + recipientMailAddress);
631                             continue;
632                         }
633                         
634                         if (deleteStmt == null) {
635                             deleteStmt = conn.prepareStatement(deleteByPK);
636                         }
637                         deleteStmt.setString(1, senderUser);
638                         deleteStmt.setString(2, senderHost);
639                         deleteStmt.setString(3, recipientUser);
640                         deleteStmt.setString(4, recipientHost);
641                         deleteStmt.executeUpdate();
642                         dbUpdated = true;
643                         out.println("Removed: " + recipientMailAddress);
644                         
645                     } finally {
646                         theJDBCUtil.closeJDBCResultSet(selectRS);
647                     }
648                 }
649 
650                 if (dbUpdated) {
651                     log("Removal request issued by " + senderMailAddress);
652                 }
653                 //Commit our changes if necessary.
654                 if (conn != null && dbUpdated && !conn.getAutoCommit()) {
655                     conn.commit() ;
656                     dbUpdated = false;
657                 }
658             }
659             else {
660                 out.println("The message must be plain - no action");
661             }
662             
663             out.println();
664             out.println("Finished");
665             
666             sendReplyFromPostmaster(mail, sout.toString());
667             
668         } catch (SQLException sqle) {
669             out.println("Error accessing the database");
670             sendReplyFromPostmaster(mail, sout.toString());
671             throw new MessagingException("Error accessing the database", sqle);
672         } catch (IOException ioe) {
673             out.println("Error getting message content");
674             sendReplyFromPostmaster(mail, sout.toString());
675             throw new MessagingException("Error getting message content", ioe);
676         } finally {
677             theJDBCUtil.closeJDBCStatement(selectStmt);
678             theJDBCUtil.closeJDBCStatement(deleteStmt);
679             //Rollback our changes if necessary.
680             try {
681                 if (conn != null && dbUpdated && !conn.getAutoCommit()) {
682                     conn.rollback() ;
683                     dbUpdated = false;
684                 }
685             }
686             catch (Exception e) {}
687             theJDBCUtil.closeJDBCConnection(conn);
688         }
689     }
690     
691     private void sendReplyFromPostmaster(Mail mail, String stringContent) throws MessagingException {
692         try {
693             MailAddress notifier = getMailetContext().getPostmaster();
694             
695             MailAddress senderMailAddress = mail.getSender();
696             
697             MimeMessage message = mail.getMessage();
698             //Create the reply message
699             MimeMessage reply = new MimeMessage(Session.getDefaultInstance(System.getProperties(), null));
700             
701             //Create the list of recipients in the Address[] format
702             InternetAddress[] rcptAddr = new InternetAddress[1];
703             rcptAddr[0] = senderMailAddress.toInternetAddress();
704             reply.setRecipients(Message.RecipientType.TO, rcptAddr);
705             
706             //Set the sender...
707             reply.setFrom(notifier.toInternetAddress());
708             
709             //Create the message body
710             MimeMultipart multipart = new MimeMultipart();
711             //Add message as the first mime body part
712             MimeBodyPart part = new MimeBodyPart();
713             part.setContent(stringContent, "text/plain");
714             part.setHeader(RFC2822Headers.CONTENT_TYPE, "text/plain");
715             multipart.addBodyPart(part);
716             
717             reply.setContent(multipart);
718             reply.setHeader(RFC2822Headers.CONTENT_TYPE, multipart.getContentType());
719             
720             //Create the list of recipients in our MailAddress format
721             Set recipients = new HashSet();
722             recipients.add(senderMailAddress);
723             
724             //Set additional headers
725             if (reply.getHeader(RFC2822Headers.DATE)==null){
726                 reply.setHeader(RFC2822Headers.DATE, rfc822DateFormat.format(new java.util.Date()));
727             }
728             String subject = message.getSubject();
729             if (subject == null) {
730                 subject = "";
731             }
732             if (subject.indexOf("Re:") == 0){
733                 reply.setSubject(subject);
734             } else {
735                 reply.setSubject("Re:" + subject);
736             }
737             reply.setHeader(RFC2822Headers.IN_REPLY_TO, message.getMessageID());
738             
739             //Send it off...
740             getMailetContext().sendMail(notifier, recipients, reply);
741         }
742         catch (Exception e) {
743             log("Exception found sending reply", e);
744         }
745     }
746     
747     /** Gets the main name of a local customer, handling alias */
748     private String getPrimaryName(String originalUsername) {
749         String username;
750         try {
751             username = localusers.getRealName(originalUsername);
752             JamesUser user = (JamesUser) localusers.getUserByName(username);
753             if (user.getAliasing()) {
754                 username = user.getAlias();
755             }
756         }
757         catch (Exception e) {
758             username = originalUsername;
759         }
760         return username;
761     }
762     
763     /**
764      * Initializes the sql query environment from the SqlResources file.
765      * Will look for conf/sqlResources.xml.
766      * @param conn The connection for accessing the database
767      * @param mailetContext The current mailet context,
768      * for finding the conf/sqlResources.xml file
769      * @throws Exception If any error occurs
770      */
771     private void initSqlQueries(Connection conn, org.apache.mailet.MailetContext mailetContext) throws Exception {
772         try {
773             if (conn.getAutoCommit()) {
774                 conn.setAutoCommit(false);
775             }
776             
777             this.sqlFile = new File((String) mailetContext.getAttribute("confDir"), "sqlResources.xml").getCanonicalFile();
778             sqlQueries.init(this.sqlFile, "WhiteList" , conn, getSqlParameters());
779             
780             checkTables(conn);
781         } finally {
782             theJDBCUtil.closeJDBCConnection(conn);
783         }
784     }
785     
786     private void checkTables(Connection conn) throws SQLException {
787 
788         // Need to ask in the case that identifiers are stored, ask the DatabaseMetaInfo.
789         // Try UPPER, lower, and MixedCase, to see if the table is there.
790         
791         boolean dbUpdated = false;
792         
793         dbUpdated = createTable(conn, "whiteListTableName", "createWhiteListTable");
794         
795         //Commit our changes if necessary.
796         if (conn != null && dbUpdated && !conn.getAutoCommit()) {
797             conn.commit();
798             dbUpdated = false;
799         }
800             
801     }
802     
803     private boolean createTable(Connection conn, String tableNameSqlStringName, String createSqlStringName) throws SQLException {
804         String tableName = sqlQueries.getSqlString(tableNameSqlStringName, true);
805         
806         DatabaseMetaData dbMetaData = conn.getMetaData();
807 
808         // Try UPPER, lower, and MixedCase, to see if the table is there.
809         if (theJDBCUtil.tableExists(dbMetaData, tableName)) {
810             return false;
811         }
812         
813         PreparedStatement createStatement = null;
814         
815         try {
816             createStatement =
817                     conn.prepareStatement(sqlQueries.getSqlString(createSqlStringName, true));
818             createStatement.execute();
819             
820             StringBuffer logBuffer = null;
821             logBuffer =
822                     new StringBuffer(64)
823                     .append("Created table '")
824                     .append(tableName)
825                     .append("' using sqlResources string '")
826                     .append(createSqlStringName)
827                     .append("'.");
828             log(logBuffer.toString());
829             
830         } finally {
831             theJDBCUtil.closeJDBCStatement(createStatement);
832         }
833         
834         return true;
835     }
836     
837 }
838