Methods Summary |
---|
private final java.lang.String | arrayToString(java.lang.Object[] array)Utility method for obtaining a string representation of an array of Objects.
if (array == null) {
return "null";
}
StringBuffer sb = new StringBuffer(1024);
sb.append("[");
for (int i = 0; i < array.length; i++) {
if (i > 0) {
sb.append(",");
}
sb.append(array[i]);
}
sb.append("]");
return sb.toString();
|
protected final void | checkInitParameters(java.lang.String[] allowedArray)Checks if there are unallowed init parameters specified in the configuration file
against the String[] allowedInitParameters.
// if null then no check is requested
if (allowedArray == null) {
return;
}
Collection allowed = new HashSet();
Collection bad = new ArrayList();
for (int i = 0; i < allowedArray.length; i++) {
allowed.add(allowedArray[i]);
}
Iterator iterator = getInitParameterNames();
while (iterator.hasNext()) {
String parameter = (String) iterator.next();
if (!allowed.contains(parameter)) {
bad.add(parameter);
}
}
if (bad.size() > 0) {
throw new MessagingException("Unexpected init parameters found: "
+ arrayToString(bad.toArray()));
}
|
protected java.net.InetAddress | getAddresses(int index)Indexed getter for property addresses.
return this.addresses[index];
|
protected java.net.InetAddress[] | getAddresses()Getter for property addresses.
return this.addresses;
|
public int | getAddressesCount()Getter for property addressesCount.
return getAddresses().length;
|
protected java.lang.String[] | getAllowedInitParameters()Gets the expected init parameters.
String[] allowedArray = {
// "static",
"debug",
"host",
"port",
"maxPings",
"pingIntervalMilli",
"streamBufferSize"
};
return allowedArray;
|
protected java.net.Socket | getClamdSocket()Gets a Socket connected to CLAMD.
Will loop though the round-robin address list until the first one accepts
the connection.
InetAddress address = null;
Set usedAddresses = new HashSet(getAddressesCount());
for (;;) {
// this do-while loop is needed because other threads could in the meantime
// calling getNextAddress(), and because of that the current thread may skip
// some working address
do {
if (usedAddresses.size() >= getAddressesCount()) {
String logText = "Unable to connect to CLAMD. All addresses failed.";
log(logText + " Giving up.");
throw new MessagingException(logText);
}
address = getNextAddress();
} while (!usedAddresses.add(address));
try {
// get the socket
return new Socket(address, getPort());
} catch (IOException ioe) {
log("Exception caught acquiring main socket to CLAMD on "
+ address + " on port " + getPort() + ": " + ioe.getMessage());
address = getNextAddress();
// retry
continue;
}
}
|
public java.lang.String | getHost()Getter for property host.
return this.host;
|
public java.lang.String | getMailetInfo()Return a string describing this mailet.
return "Antivirus Check using ClamAV (CLAMD)";
|
public int | getMaxPings()Getter for property maxPings.
return this.maxPings;
|
protected synchronized java.net.InetAddress | getNextAddress()Getter for property nextAddress.
Gets the address of the next CLAMD server to connect to in this round, using round-robin.
Increments the nextAddressIndex for the next round.
InetAddress address = getAddresses(nextAddressIndex);
nextAddressIndex++;
if (nextAddressIndex >= getAddressesCount()) {
nextAddressIndex = 0;
}
return address;
|
public int | getPingIntervalMilli()Getter for property pingIntervalMilli.
return this.pingIntervalMilli;
|
public int | getPort()Getter for property port.
return this.port;
|
public int | getStreamBufferSize()Getter for property streamBufferSize.
return this.streamBufferSize;
|
protected final int | getStreamPortFromAnswer(java.lang.String answer)Parses the answer from a STREAM request and gets the port number.
int port = -1;
if (answer != null && answer.startsWith(STREAM_PORT_STRING)) {
try {
port = Integer.parseInt(answer.substring(STREAM_PORT_STRING.length()));
} catch (NumberFormatException nfe) {
}
}
if (port <= 0) {
throw new ConnectException("\"PORT nn\" expected - unable to parse: " + "\"" + answer + "\"");
}
return port;
|
public void | init()Mailet initialization routine.
// check that all init parameters have been declared in allowedInitParameters
checkInitParameters(getAllowedInitParameters());
try {
initDebug();
if (isDebug()) {
log("Initializing");
}
initHost();
initPort();
initMaxPings();
initPingIntervalMilli();
initStreamBufferSize();
// If "maxPings is > ping the CLAMD server to check if it is up
if (getMaxPings() > 0) {
ping();
}
} catch (Exception e) {
log("Exception thrown", e);
throw new MessagingException("Exception thrown", e);
}
|
protected void | initDebug()Initializer for property debug.
String debugParam = getInitParameter("debug");
setDebug((debugParam == null) ? false : new Boolean(debugParam).booleanValue());
|
protected void | initHost()Initializer for property host.
setHost(getInitParameter("host"));
if (isDebug()) {
log("host: " + getHost());
}
|
protected void | initMaxPings()Initializer for property maxPings.
String maxPingsParam = getInitParameter("maxPings");
setMaxPings((maxPingsParam == null) ? DEFAULT_MAX_PINGS : Integer.parseInt(maxPingsParam));
if (isDebug()) {
log("maxPings: " + getMaxPings());
}
|
protected void | initPingIntervalMilli()Initializer for property pingIntervalMilli.
String pingIntervalMilliParam = getInitParameter("pingIntervalMilli");
setPingIntervalMilli((pingIntervalMilliParam == null) ? DEFAULT_PING_INTERVAL_MILLI : Integer.parseInt(pingIntervalMilliParam));
if (isDebug()) {
log("pingIntervalMilli: " + getPingIntervalMilli());
}
|
protected void | initPort()Initializer for property port.
String portParam = getInitParameter("port");
setPort((portParam == null) ? DEFAULT_PORT : Integer.parseInt(portParam));
if (isDebug()) {
log("port: " + getPort());
}
|
protected void | initStreamBufferSize()Initializer for property streamBufferSize.
String streamBufferSizeParam = getInitParameter("streamBufferSize");
setStreamBufferSize((streamBufferSizeParam == null) ? DEFAULT_STREAM_BUFFER_SIZE : Integer.parseInt(streamBufferSizeParam));
if (isDebug()) {
log("streamBufferSize: " + getStreamBufferSize());
}
|
public boolean | isDebug()Getter for property debug.
return this.debug;
|
private void | logMailInfo(org.apache.mailet.Mail mail)
// writes the error message to the log
StringWriter sout = new StringWriter();
PrintWriter out = new PrintWriter(sout, true);
out.print("Mail details:");
out.print(" MAIL FROM: " + mail.getSender());
Iterator rcptTo = mail.getRecipients().iterator();
out.print(", RCPT TO: " + rcptTo.next());
while (rcptTo.hasNext()) {
out.print(", " + rcptTo.next());
}
log(sout.toString());
|
private void | logMessageInfo(javax.mail.internet.MimeMessage mimeMessage)
// writes the error message to the log
StringWriter sout = new StringWriter();
PrintWriter out = new PrintWriter(sout, true);
out.println("MimeMessage details:");
try {
if (mimeMessage.getSubject() != null) {
out.println(" Subject: " + mimeMessage.getSubject());
}
if (mimeMessage.getSentDate() != null) {
out.println(" Sent date: " + mimeMessage.getSentDate());
}
String[] sender = null;
sender = mimeMessage.getHeader(RFC2822Headers.FROM);
if (sender != null) {
out.print(" From: ");
for (int i = 0; i < sender.length; i++) {
out.print(sender[i] + " ");
}
out.println();
}
String[] rcpts = null;
rcpts = mimeMessage.getHeader(RFC2822Headers.TO);
if (rcpts != null) {
out.print(" To: ");
for (int i = 0; i < rcpts.length; i++) {
out.print(rcpts[i] + " ");
}
out.println();
}
rcpts = mimeMessage.getHeader(RFC2822Headers.CC);
if (rcpts != null) {
out.print(" CC: ");
for (int i = 0; i < rcpts.length; i++) {
out.print(rcpts[i] + " ");
}
out.println();
}
out.print(" Size (in bytes): " + mimeMessage.getSize());
if (mimeMessage.getLineCount() >= 0) {
out.print(", Number of lines: " + mimeMessage.getLineCount());
}
} catch (MessagingException me) {
log("Exception caught reporting message details", me);
}
log(sout.toString());
|
protected void | ping()Tries to "ping" all the CLAMD daemons to
check if they are up and accepting requests.
for (int i = 0; i < getAddressesCount(); i++) {
ping(getAddresses(i));
}
|
protected void | ping(java.net.InetAddress address)Tries (and retries as specified up to 'getMaxPings()') to "ping" the specified CLAMD daemon to
check if it is up and accepting requests.
Socket socket = null;
int ping = 1;
for (; ; ) {
if (isDebug()) {
log("Trial #" + ping + "/" + getMaxPings() + " - creating socket connected to " + address + " on port " + getPort());
}
try {
socket = new Socket(address, getPort());
break;
} catch (ConnectException ce) {
log("Trial #" + ping + "/" + getMaxPings() + " - exception caught: " + ce.toString() + " while creating socket connected to " + address + " on port " + getPort());
ping++;
if (ping <= getMaxPings()) {
log("Waiting " + getPingIntervalMilli() + " milliseconds before retrying ...");
Thread.sleep(getPingIntervalMilli());
} else {
break;
}
}
}
// if 'socket' is still null then 'maxPings' has been exceeded
if (socket == null) {
throw new ConnectException("maxPings exceeded: " + getMaxPings() + ". Giving up. The clamd daemon seems not to be running");
}
try {
// get the reader and writer to ping and receive pong
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "ASCII"));
PrintWriter writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
log("Sending: \"PING\" to " + address + " ...");
writer.println("PING");
writer.flush();
boolean pongReceived = false;
for (;;) {
String answer = reader.readLine();
if (answer != null) {
answer = answer.trim();
log("Received: \"" + answer + "\"");
answer = answer.trim();
if (answer.equals("PONG")) {
pongReceived = true;
}
} else {
break;
}
}
reader.close();
writer.close();
if (!pongReceived) {
throw new ConnectException("Bad answer from \"PING\" probe: expecting \"PONG\"");
}
} finally {
socket.close();
}
|
protected final void | saveChanges(javax.mail.internet.MimeMessage message)Saves changes resetting the original message id.
String messageId = message.getMessageID();
message.saveChanges();
if (messageId != null) {
message.setHeader(RFC2822Headers.MESSAGE_ID, messageId);
}
|
public void | service(org.apache.mailet.Mail mail)Scans the mail.
// if already checked no action
if (mail.getAttribute(MAIL_ATTRIBUTE_NAME) != null) {
return;
}
MimeMessage mimeMessage = mail.getMessage();
if (mimeMessage == null) {
log("Null MimeMessage. Will send to ghost");
// write mail info to log
logMailInfo(mail);
mail.setState(Mail.GHOST);
return;
}
// get the socket
Socket socket = getClamdSocket();
BufferedReader reader = null;
PrintWriter writer = null;
Socket streamSocket = null;
BufferedOutputStream bos = null;
try {
// prepare the reader and writer for the commands
reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "ASCII"));
writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
// write a request for a port to use for streaming out the data to scan
writer.println("STREAM");
writer.flush();
// parse and get the "stream" port#
int streamPort = getStreamPortFromAnswer(reader.readLine());
// get the "stream" socket and the related (buffered) output stream
streamSocket = new Socket(socket.getInetAddress(), streamPort);
bos = new BufferedOutputStream(streamSocket.getOutputStream(), getStreamBufferSize());
// stream out the message to the scanner
mimeMessage.writeTo(bos);
bos.flush();
bos.close();
streamSocket.close();
String answer = null;
boolean virusFound = false;
String logMessage = "";
for (;;) {
answer = reader.readLine();
if (answer != null) {
answer = answer.trim();
// if a virus is found the answer will be '... FOUND'
if (answer.substring(answer.length() - FOUND_STRING.length()).equals(FOUND_STRING)) {
virusFound = true;
logMessage = answer + " (by CLAMD on " + socket.getInetAddress() + ")";
log(logMessage);
}
} else {
break;
}
}
reader.close();
writer.close();
if (virusFound) {
String errorMessage = mail.getErrorMessage();
if (errorMessage == null) {
errorMessage = "";
} else {
errorMessage += "\r\n";
}
StringBuffer sb = new StringBuffer(errorMessage);
sb.append(logMessage + "\r\n");
// write mail and message info to log
logMailInfo(mail);
logMessageInfo(mimeMessage);
// mark the mail with a mail attribute to check later on by other matchers/mailets
mail.setAttribute(MAIL_ATTRIBUTE_NAME, "true");
// sets the error message to be shown in any "notifyXxx" message
mail.setErrorMessage(sb.toString());
// mark the message with a header string
mimeMessage.setHeader(HEADER_NAME, "true");
} else {
if (isDebug()) {
log("OK (by CLAMD on " + socket.getInetAddress() + ")");
}
mail.setAttribute(MAIL_ATTRIBUTE_NAME, "false");
// mark the message with a header string
mimeMessage.setHeader(HEADER_NAME, "false");
}
try {
saveChanges(mimeMessage);
} catch (Exception ex) {
log("Exception caught while saving changes (header) to the MimeMessage. Ignoring ...", ex);
}
} catch (Exception ex) {
log("Exception caught calling CLAMD on " + socket.getInetAddress() + ": " + ex.getMessage(), ex);
throw new MessagingException("Exception caught", ex);
} finally {
try {
if (reader != null) {
reader.close();
}
} catch (Throwable t) {}
try {
if (writer != null) {
writer.close();
}
} catch (Throwable t) {}
try {
if (bos != null) {
bos.close();
}
} catch (Throwable t) {}
try {
if (streamSocket != null) {
streamSocket.close();
}
} catch (Throwable t) {}
try {
if (socket != null) {
socket.close();
}
} catch (Throwable t) {}
}
|
protected void | setAddresses(java.net.InetAddress[] addresses)Setter for property addresses.
this.addresses = addresses;
|
public void | setDebug(boolean debug)Setter for property debug.
this.debug = debug;
|
public void | setHost(java.lang.String host)Setter for property host.
Resolves also the host name into the corresponding IP addresses, issues
a {@link #setAddresses} and resets the nextAddressIndex
variable to 0 for dealing with round-robin.
this.host = host;
setAddresses(InetAddress.getAllByName(host));
nextAddressIndex = 0;
|
public void | setMaxPings(int maxPings)Setter for property maxPings.
this.maxPings = maxPings;
|
public void | setPingIntervalMilli(int pingIntervalMilli)Setter for property pingIntervalMilli.
this.pingIntervalMilli = pingIntervalMilli;
|
public void | setPort(int port)Setter for property port.
this.port = port;
|
public void | setStreamBufferSize(int streamBufferSize)Setter for property streamBufferSize.
this.streamBufferSize = streamBufferSize;
|