/*
 * JDBCLogRejection.java
 *
 * Created on November 14, 2003, 1:52 AM
 */

package org.apache.james.transport.mailets;

import org.apache.avalon.cornerstone.services.datasource.DataSourceSelector;
import org.apache.avalon.excalibur.datasource.DataSourceComponent;
import org.apache.avalon.framework.component.ComponentManager;
import org.apache.mailet.GenericMailet;
import org.apache.james.Constants;
import org.apache.james.util.JDBCUtil;
import org.apache.mailet.Mail;
import org.apache.mailet.MailAddress;
import org.apache.mailet.MailetException;
import org.apache.james.util.RFC2822Headers;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.InternetAddress;
import javax.mail.Message;
import javax.mail.Address;

import java.sql.*;

/**
 *
 * @author  Corey Johnson
 */
public class JDBCLogRejection extends GenericMailet {
    
    protected DataSourceComponent datasource;
    protected String query = null;
    protected String rejectType = null;
    
    // The JDBCUtil helper class
    private final JDBCUtil theJDBCUtil =
            new JDBCUtil() {
                protected void delegatedLog(String logString) {
                    log("JDBCLogRejection: " + logString);
                }
            };
    
    
    /**
     * Initialize the mailet, loading all configuration parameters.
     *
     * @throws MessagingException
     */
    public void init() throws MessagingException {  
        String logdbURL = getInitParameter("logdburl");
        rejectType = getInitParameter("reject-type");         
        String datasourceName = logdbURL.substring(5);
        int pos = datasourceName.indexOf("/");
        String tableName = datasourceName.substring(pos + 1);
        datasourceName = datasourceName.substring(0, pos);        
                
        Connection conn = null;
        
        try {
            ComponentManager componentManager = (ComponentManager)getMailetContext().getAttribute(Constants.AVALON_COMPONENT_MANAGER);
            // Get the DataSourceSelector service
            DataSourceSelector datasources = (DataSourceSelector)componentManager.lookup(DataSourceSelector.ROLE);
            // Get the data-source required.
            datasource = (DataSourceComponent)datasources.select(datasourceName);

            conn = datasource.getConnection();          

            // Check if the required table exists. If not, complain.
            DatabaseMetaData dbMetaData = conn.getMetaData();
            // Need to ask in the case that identifiers are stored, ask the DatabaseMetaInfo.
            // Try UPPER, lower, and MixedCase, to see if the table is there.
            if (!(theJDBCUtil.tableExists(dbMetaData, tableName)))  {
                StringBuffer exceptionBuffer =
                    new StringBuffer(128)
                            .append("Could not find table '")
                            .append(tableName)
                            .append("' in datasource '")
                            .append(datasourceName)
                            .append("'");
                throw new MailetException(exceptionBuffer.toString());
            }

            //Build the query
            StringBuffer queryBuffer =
                new StringBuffer(128)
                        .append("INSERT INTO ")
                        .append(tableName)
                        .append(" (fromAddr, toAddr, subject, notice, msgSize, lineCount, timestamp, type) ")
                        .append("VALUES")
                        .append(" (?, ?, ?, ?, ?, ?, now(), ?) ");
            query = queryBuffer.toString();            
        } catch (MailetException me) {
            throw me;
        } catch (Exception e) {
            throw new MessagingException("Error initializing JDBCLogRejection", e);
        } finally {
            theJDBCUtil.closeJDBCConnection(conn);
        }        
    }
    
    public void service(Mail mail) throws MessagingException {
        Connection conn = null;
        PreparedStatement logdbStmt = null;        
        MimeMessage message = mail.getMessage();
                               
        try {
            conn = datasource.getConnection();
            logdbStmt = conn.prepareStatement(query);
            
            // need to handle multiple receiptents.. and also only log traffic to
            // real addresses.  Have to check CC and BCC..  as well as TO!!!!! 
            
            // first grab the From address..  grab only one... i guess it could have
            // multiple?  Since "getSender returns a Collection?
            InternetAddress[] senderAddr = new InternetAddress[1];
            senderAddr[0] = mail.getSender().toInternetAddress();
            logdbStmt.setString(1, senderAddr[0].toString());
                        
            // next grab all recipients..  (To, CC and BCC)
            // and append them            
            // testing with To now.. grabbing only one.
            String[] rcpts = null;
            rcpts = message.getHeader(RFC2822Headers.TO);
            //if (rcpts != null) {
            //    for (int i = 0; i < rcpts.length; i++) {
            //                     
            //    }
            //}                               
            logdbStmt.setString(2, rcpts[0].toString());
            
            // log subject
            logdbStmt.setString(3, message.getSubject());            
            
            // log error message
            if (mail.getErrorMessage() != null) {
                logdbStmt.setString(4, mail.getErrorMessage());
            } else {
                logdbStmt.setString(4, ""); 
            }
            
            // log message size
            logdbStmt.setInt(5, message.getSize());
            
            // log line count
            if (message.getLineCount() >= 0) {
                logdbStmt.setInt(6, message.getLineCount());
            } else {
                logdbStmt.setInt(6, 0);
            }
            
            // set rejection type (spam, virus, rule)
            logdbStmt.setString(7, rejectType.trim());
            
            logdbStmt.executeUpdate();
        } catch (SQLException sqle) {
            throw new MessagingException("Error accessing database", sqle);
        } catch (Exception ex) {
            throw new MessagingException("Unspecified exception thrown in JDBCLogRejection", ex);
        } finally {
            theJDBCUtil.closeJDBCStatement(logdbStmt);
            theJDBCUtil.closeJDBCConnection(conn);
        }
    }
    
     /**
     * Return a string describing this mailet.
     *
     * @return a string describing this mailet
     */
    public String getMailetInfo() {
        return "JDBCLogRejection Mailet";
    }
    
}

