/*
* Copyright (C) 1996 - 2008 Alan Williamson
*
* This file is part of Mail25 Mailet Container.
*
* Mail25 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Free Software Foundation,version 3.
*
* Mail25 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mail25. If not, see http://www.gnu.org/licenses/
*
* http://alan.blog-city.com/
*/
package org.alanwilliamson.mail25.server;
/*
* Stores the current session data for a given client transaction.
*
* If the current mail being received is shaping up to be more than
* MEMORY_SIZE (64KB) then the in-memory buffering will be stopped
* and instead all data will be paged straight out to disk. This allows
* us to handle very large emails.
*
*/
import java.io.BufferedInputStream;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.mail.internet.InternetAddress;
import org.apache.mailet.MailAddress;
import org.quickserver.net.server.ClientData;
public class MailData implements ClientData, Serializable {
private static final long serialVersionUID = 1L;
private static int lastId = 0;
private int thisId;
private int sizeRxd = 0;
private long startTime = 0, rxdTime = 0;
private int totalRxd = 0, totalMails = 0;
private int MEMORY_SIZE = 64000;
private boolean mailRxd = false;
private int lastOutStatus = 0;
private String lastOutMsg = "";
private boolean dataMode = false;
private ByteArrayOutputStream byteArray;
private FileInputStream fileInputStream = null;
private FileWriter fileWriter = null;
private PrintWriter printWriter = null;
private File fileSpool = null;
private String clientAddress = null;
private List mailFromList = null;
private Collection mailToList = null;
private Mail25 mail25;
private cfMailSession cfmailsession;
public MailData(){
thisId = lastId++;
cfmailsession = new cfMailSession();
}
public void setMail25( Mail25 mail25 ){
this.mail25 = mail25;
}
public Mail25 getMail25(){
return this.mail25;
}
public int getId(){
return thisId;
}
public int getLastOutStatus(){return lastOutStatus;}
public String getLastStatusMsg(){return lastOutMsg;}
public boolean isDataMode(){ return dataMode; }
public boolean isMailRxd(){ return mailRxd; }
public int getSize(){ return sizeRxd; }
public long getMailRxdTime(){ return rxdTime; }
public int getTotalSize(){ return totalRxd; }
public int getTotalMails(){ return totalMails; }
public void setRecipients(Collection recipients) {
mailToList = recipients;
}
public InputStream getInputStream() throws FileNotFoundException {
if ( fileSpool == null )
return new BufferedInputStream( new ByteArrayInputStream( byteArray.toByteArray() ) );
else{
fileInputStream = new FileInputStream( fileSpool );
return new BufferedInputStream( fileInputStream );
}
}
public void setMailProcessed(){
mailRxd = false;
}
private void reset(){
mailFromList = new ArrayList();
mailToList = new ArrayList();
lastOutStatus = 0;
lastOutMsg = "";
mailRxd = false;
dataMode = false;
sizeRxd = 0;
closeAndDeleteFile();
}
public List getFromList(){
return mailFromList;
}
public void setClientAddress( String ip ){
clientAddress = ip;
}
public String getClientAddress(){
return clientAddress;
}
public Collection getToList(){
return mailToList;
}
public void cmdHelo(String lineIn) {
lastOutStatus = 250;
lastOutMsg = "Welcome";
sizeRxd += lineIn.length();
}
public void cmdQuit(String lineIn) {
lastOutStatus = 221;
lastOutMsg = "Bye";
//- If this message was spooled out to disk, the nuke it
closeAndDeleteFile();
}
public void cmdMailFrom(String lineIn) {
startTime = System.currentTimeMillis();
totalMails++;
sizeRxd = lineIn.length();
totalRxd += lineIn.length();
reset();
try{
InternetAddress[] address = InternetAddress.parse( lineIn.substring( lineIn.indexOf(":")+1 ) );
boolean bAccept = false;
for (int x=0; x<address.length;x++){
bAccept = mail25.acceptMailFrom( cfmailsession, address[x], getClientAddress() );
if ( bAccept ){
mailFromList.add( new MailAddress( address[x] ) );
}
}
if ( bAccept ){
lastOutStatus = 250;
lastOutMsg = "Ok";
}else{
lastOutStatus = 501;
lastOutMsg = "Bad address";
}
}catch (Exception e){
lastOutStatus = 500;
lastOutMsg = "Bad Syntax (" + e.getMessage() + ")";
}
}
public void cmdRcptTo(String lineIn) {
sizeRxd += lineIn.length();
totalRxd += lineIn.length();
try{
InternetAddress[] address = InternetAddress.parse( lineIn.substring( lineIn.indexOf(":")+1 ) );
boolean bAccept = false;
for (int x=0; x<address.length;x++){
bAccept = mail25.acceptMailTo( cfmailsession, address[x], getClientAddress() );
if ( bAccept ){
mailToList.add( new MailAddress( address[x] ) );
}
}
if ( bAccept ){
lastOutStatus = 250;
lastOutMsg = "Ok";
}else{
lastOutStatus = 550;
lastOutMsg = "No one here";
}
}catch (Exception e){
lastOutStatus = 500;
lastOutMsg = "Bad Syntax (" + e.getMessage() + ")";
}
}
public void cmdData(String lineIn) {
/*
* Got to make sure they have put this in the right order
*/
if ( mailToList.size() == 0 || mailFromList.size() == 0 ){
lastOutStatus = 503;
lastOutMsg = "not valid here";
return;
}
sizeRxd += lineIn.length();
totalRxd += lineIn.length();
lastOutStatus = 354;
lastOutMsg = "End data with <CR><LF>.<CR><LF>";
dataMode = true;
byteArray = new ByteArrayOutputStream( MEMORY_SIZE );
printWriter = new PrintWriter( new BufferedWriter( new OutputStreamWriter(byteArray) ) );
}
public void close(){
//-- This makes sure all the buffers are closed
if ( printWriter != null )
printWriter.close();
closeAndDeleteFile();
}
public void dataRxd(String lineIn) throws IOException {
sizeRxd += lineIn.length();
totalRxd += lineIn.length();
if ( lineIn.length() == 1 && lineIn.charAt(0) == '.' ){
lastOutStatus = 250;
lastOutMsg = "Ok: mail accepted";
dataMode = false;
mailRxd = true;
rxdTime = System.currentTimeMillis() - startTime;
printWriter.flush();
printWriter.close();
if ( fileWriter != null )
fileWriter.close();
fileWriter = null;
printWriter = null;
}else{
//- check for the escape for the .
if ( lineIn.length() >= 2 && lineIn.charAt(0) == '.' && lineIn.charAt(1) == '.' ){
lineIn = lineIn.substring( 1 );
}
printWriter.println( lineIn );
printWriter.flush();
//- check to see we aren't handling too big a message. if we are
//- then swing over the output buffers and page to disk instead.
if ( byteArray != null && byteArray.size() > MEMORY_SIZE ){
spoolToDisk();
}
lastOutStatus = 0;
}
}
private void closeAndDeleteFile(){
try{
if ( fileWriter != null )
fileWriter.close();
if ( fileInputStream != null )
fileInputStream.close();
if ( fileSpool != null )
fileSpool.delete();
}catch(Exception ignoreTheClose){}
fileWriter = null;
fileSpool = null;
fileInputStream = null;
}
private void spoolToDisk() throws IOException{
fileSpool = mail25.getSpoolFile();
//- Create the output
fileWriter = new FileWriter(fileSpool);
printWriter = new PrintWriter( new BufferedWriter( fileWriter ) );
//- Page out to disk what we already have collected
String out = new String( byteArray.toByteArray() );
printWriter.print( out );
printWriter.flush();
//-- Reset the internal buffer, and set it to null to let it be garbage collected
byteArray.reset();
byteArray = null;
}
public boolean hasRpct() {
return (mailToList.size() > 0);
}
public boolean hasFrom() {
return (mailFromList.size() > 0);
}
public Object getMailSession() {
return cfmailsession;
}
}