/*
*
*/
package org.subethamail.smtp.io;
import java.io.ByteArrayInputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import org.subethamail.smtp.util.TextUtils;
/**
* Prepends a Received: header at the beginning of the input stream.
*/
public class ReceivedHeaderStream extends FilterInputStream
{
ByteArrayInputStream header;
/**
* @param softwareName
* A software name and version, or null if this information
* should not be printed
* @param singleRecipient
* The single recipient of the message. If there are more than
* one recipients then this must be null.
*/
public ReceivedHeaderStream(InputStream in, String heloHost, InetAddress host, String whoami, String softwareName,
String singleRecipient)
{
super(in);
/* Looks like:
Received: from iamhelo (wasabi.infohazard.org [209.237.247.14])
by mx.google.com with SMTP id 32si2669129wfa.13.2009.05.27.18.27.31;
Wed, 27 May 2009 18:27:48 -0700 (PDT)
*/
DateFormat fmt = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z (z)", Locale.US);
String timestamp = fmt.format(new Date());
StringBuilder header = new StringBuilder();
header.append("Received: from " + heloHost + " (" + constructTcpInfo(host) + ")\r\n");
header.append(" by " + whoami + " with SMTP");
if (softwareName != null)
header.append(" (" + softwareName + ")");
if (singleRecipient != null)
header.append("\r\n for " + singleRecipient);
header.append(";\r\n");
header.append(" " + timestamp + "\r\n");
this.header = new ByteArrayInputStream(TextUtils.getAsciiBytes(header.toString()));
}
/**
* Returns a formatted TCP-info element, depending on the success of the IP
* address name resolution either with domain name or only the address
* literal.
*
* @param host
* the address of the remote SMTP client.
* @return the formatted TCP-info element as defined by RFC 5321
*/
private String constructTcpInfo(InetAddress host)
{
// if it is not successful it just returns the address
String domain = host.getCanonicalHostName();
String address = host.getHostAddress();
// check whether the host name resolution was successful
if (domain.equals(address))
return "[" + address + "]";
else
return domain + " [" + address + "]";
}
/* */
@Override
public int available() throws IOException
{
return this.header.available() + super.available();
}
/* */
@Override
public void close() throws IOException
{
super.close();
}
/* */
@Override
public synchronized void mark(int readlimit)
{
throw new UnsupportedOperationException();
}
/* */
@Override
public boolean markSupported()
{
return false;
}
/* */
@Override
public int read() throws IOException
{
if (this.header.available() > 0)
return this.header.read();
else
return super.read();
}
/* */
@Override
public int read(byte[] b, int off, int len) throws IOException
{
if (this.header.available() > 0)
{
int countRead = this.header.read(b, off, len);
if (countRead < len)
{
// We need to add a little extra from the normal stream
int remainder = len - countRead;
int additionalRead = super.read(b, off + countRead, remainder);
return countRead + additionalRead;
}
else
return countRead;
}
else
return super.read(b, off, len);
}
/* */
@Override
public int read(byte[] b) throws IOException
{
return this.read(b, 0, b.length);
}
/* */
@Override
public synchronized void reset() throws IOException
{
throw new UnsupportedOperationException();
}
/* */
@Override
public long skip(long n) throws IOException
{
throw new UnsupportedOperationException();
}
}