noel 2003/02/04 20:31:40
Added: src/java/org/apache/james/fetchmail FetchMail.java
FetchScheduler.java FetchScheduler.xinfo
ReaderInputStream.java
Log:
Added FetchMail service
Revision Changes Path
1.1 jakarta-james/src/java/org/apache/james/fetchmail/FetchMail.java
Index: FetchMail.java
===================================================================
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.james.fetchmail;
import java.io.IOException;
import java.io.InputStream;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.Vector;
import java.util.*;
import java.io.*;
import javax.mail.*;
import javax.mail.event.*;
import javax.mail.internet.*;
import javax.activation.*;
import org.apache.avalon.cornerstone.services.scheduler.Target;
import org.apache.avalon.framework.component.ComponentException;
import org.apache.avalon.framework.component.ComponentManager;
import org.apache.avalon.framework.component.Composable;
import org.apache.avalon.framework.component.DefaultComponentManager;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.commons.net.pop3.POP3Client;
import org.apache.commons.net.pop3.POP3MessageInfo;
import org.apache.james.services.MailServer;
import org.apache.mailet.*;
import org.apache.james.core.MailImpl;
/**
*
* A class which fetches mail from a single account and inserts it
* into the incoming spool
*
* $Id: FetchMail.java,v 1.1 2003/02/05 04:31:40 noel Exp $
*
*/
public class FetchMail extends AbstractLogEnabled implements Configurable, Target {
/**
* The MailServer service
*/
private MailServer server;
/**
* The user to send the fetched mail to
*/
private MailAddress recipient;
/**
* Don't parse header looking for recipient
*/
private boolean ignoreOriginalRecipient;
/**
* The unique, identifying name for this task
*/
private String fetchTaskName;
/**
* The POP3 server host name for this fetch task
*/
private String popHost;
/**
* The POP3 user name for this fetch task
*/
private String popUser;
/**
* The POP3 user password for this fetch task
*/
private String popPass;
/**
* Flag to determine if you want to leave messages on server
* If so unseen messages will be marked as seen
*/
private boolean popLeaveOnServer = false;
/**
* The name of the javamail provider we want to user (pop3,imap,nntp,etc...)
*
*/
private String javaMailProviderName = "pop3";
/**
* The name of the folder to fetch from the javamail provider
*
*/
private String javaMailFolderName = "INBOX";
/**
* @see
org.apache.avalon.cornerstone.services.scheduler.Target#targetTriggered(String)
*/
private boolean fetching = false;
public void targetTriggered(String arg0) {
//
// if we are already fetching then just return
if (fetching) return;
fetching = true;
if (getLogger().isDebugEnabled()) {
getLogger().debug(fetchTaskName + " fetcher starting fetch");
}
Store store = null;
Session session = null;
Folder folder = null;
// Get a Properties object
Properties props = System.getProperties();
// Get a Session object
session = Session.getDefaultInstance(props, null);
// session.setDebug(debug);
// Get a Store object
try {
store = session.getStore(javaMailProviderName);
// Connect
if (popHost != null || popUser != null || popPass != null)
store.connect(popHost, popUser, popPass);
else
store.connect();
// Open the Folder
folder = store.getFolder(javaMailFolderName);
if (folder == null) {
getLogger().debug(fetchTaskName + " No default folder");
}
// // try to open read/write and if that fails try read-only
try {
folder.open(Folder.READ_WRITE);
} catch (MessagingException ex) {
try {
folder.open(Folder.READ_ONLY);
} catch (MessagingException ex2) {
getLogger().debug(fetchTaskName + " Failed to open folder!");
store.close();
}
}
int totalMessages = folder.getMessageCount();
if (totalMessages == 0) {
getLogger().debug(fetchTaskName + " Empty folder");
folder.close(false);
store.close();
fetching = false;
return;
}
Message[] msgs = folder.getMessages();
Message[] received = new Message[folder.getUnreadMessageCount()];
// Use a suitable FetchProfile
FetchProfile fp = new FetchProfile();
fp.add(FetchProfile.Item.ENVELOPE);
fp.add(FetchProfile.Item.CONTENT_INFO);
fp.add(FetchProfile.Item.FLAGS);
fp.add("X-Mailer");
folder.fetch(msgs, fp);
int j = 0;
for (int i = 0; i < msgs.length; i++) {
Flags flags = msgs[i].getFlags();
MimeMessage message = (MimeMessage) msgs[i];
if (!msgs[i].isSet(Flags.Flag.SEEN)) {
//
// saved recieved messages for furthe processing...
received[j++] = msgs[i];
Collection recipients = new ArrayList(1);
try {
if (!ignoreOriginalRecipient) {
String er = getEnvelopeRecipient(message);
if (er != null) {
recipients.add(new MailAddress(er));
getLogger().info("Using original envelope recipient
as new envelope recipient");
} else {
Address[] to = message.getAllRecipients();
if (to.length == 1) {
recipients.add(new
MailAddress((InternetAddress) to[0]));
getLogger().info("Using To: header address as
new envelope recipient");
} else {
getLogger().info("Using configured recipient as
new envelope recipient");
recipients.add(recipient);
}
}
} else {
getLogger().info("Using configured recipient as new
envelope recipient");
recipients.add(recipient);
}
} catch (ParseException pe) {
recipients.add(recipient);
}
MailImpl mail = new MailImpl(server.getId(), new
MailAddress((InternetAddress) message.getFrom()[0]),
recipients, message);
// Lets see if this mail has been bouncing by counting
// the X-fetched-from headers
// if it is then move it to the ERROR repository
Enumeration enum = message.getMatchingHeaderLines(new
String[]{"X-fetched-from"});
int count = 1;
while (enum.hasMoreElements()) {
Object o = enum.nextElement();
count++;
}
if (count > 3) {
mail.setState(mail.ERROR);
mail.setErrorMessage("This mail from FetchMail task " +
fetchTaskName + " seems to be bounceing!");
getLogger().error("A message from FetchMail task " +
fetchTaskName + " seems to be bounceing! Moved to Error repository");
}
// Send to spooler
try {
server.sendMail(mail);
getLogger().debug("Spooled message to " +
recipients.toString());
//
// logging if needed
getLogger().debug("Sent message " + msgs[i].toString());
} catch (MessagingException innerE) {
getLogger().error("can't insert message " +
msgs[i].toString());
} /*catch (IOException ioE) {
getLogger().error("can't convert message to a mime message " +
ioE.getMessage());
}*/
}
}
if (popLeaveOnServer) {
Flags f = new Flags();
f.add(Flags.Flag.SEEN);
folder.setFlags(received, f, true);
folder.close(false);
} else {
Flags f = new Flags();
f.add(Flags.Flag.DELETED);
folder.setFlags(received, f, true);
folder.close(true);
}
store.close();
} catch (MessagingException ex) {
getLogger().debug(fetchTaskName + ex.getMessage());
}
fetching = false;
}
/**
* @see
org.apache.avalon.framework.component.Composable#compose(ComponentManager)
*/
public void compose(final ComponentManager componentManager) throws
ComponentException {
try {
server = (MailServer) componentManager.lookup(MailServer.ROLE);
} catch (ClassCastException cce) {
StringBuffer errorBuffer =
new StringBuffer(128).append("Component
").append(MailServer.ROLE).append(
"does not implement the required interface.");
throw new ComponentException(errorBuffer.toString());
}
}
/**
* Try and parse the "for" parameter from a Received header
* Maybe not the most accurate parsing in the world but it should do
* I opted not to use ORO (maybe I should have)
*/
private String getEnvelopeRecipient(MimeMessage msg) {
try {
Enumeration enum = msg.getMatchingHeaderLines(new String[]{"Received"});
while (enum.hasMoreElements()) {
String received = (String) enum.nextElement();
int nextSearchAt = 0;
int i = 0;
int start = 0;
int end = 0;
boolean hasBracket = false;
boolean usableAddress = false;
while (!usableAddress && (i != -1)) {
hasBracket = false;
i = received.indexOf("for ", nextSearchAt);
if (i > 0) {
start = i + 4;
end = 0;
nextSearchAt = start;
for (int c = start; c < received.length(); c++) {
char ch = received.charAt(c);
switch (ch) {
case '<':
hasBracket = true;
continue;
case '@':
usableAddress = true;
continue;
case ' ':
end = c;
break;
case ';':
end = c;
break;
}
if (end > 0)
break;
}
}
}
if (usableAddress) {
// lets try and grab the email address
String mailFor = received.substring(start, end);
// strip the <> around the address if there are any
if (mailFor.startsWith("<") && mailFor.endsWith(">"))
mailFor = mailFor.substring(1, (mailFor.length() - 1));
return mailFor;
}
}
} catch (MessagingException me) {
getLogger().info("No Recieved headers found");
}
return null;
}
/**
* @see
org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
*/
public void configure(Configuration conf) throws ConfigurationException {
this.popHost = conf.getChild("host").getValue();
this.popUser = conf.getChild("user").getValue();
this.popPass = conf.getChild("password").getValue();
this.fetchTaskName = conf.getAttribute("name");
this.javaMailProviderName =
conf.getChild("javaMailProviderName").getValue();
this.javaMailFolderName = conf.getChild("javaMailFolderName").getValue();
try {
this.recipient = new MailAddress(conf.getChild("recipient").getValue());
} catch (ParseException pe) {
throw new ConfigurationException("Invalid recipient address specified");
}
this.ignoreOriginalRecipient =
conf.getChild("recipient").getAttributeAsBoolean("ignorercpt-header");
this.popLeaveOnServer = conf.getChild("leaveonserver").getValueAsBoolean();
if (getLogger().isDebugEnabled()) {
getLogger().info("Configured FetchMail fetch task " + fetchTaskName);
}
}
}
1.1
jakarta-james/src/java/org/apache/james/fetchmail/FetchScheduler.java
Index: FetchScheduler.java
===================================================================
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.james.fetchmail;
import org.apache.avalon.cornerstone.services.scheduler.PeriodicTimeTrigger;
import org.apache.avalon.cornerstone.services.scheduler.TimeScheduler;
import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.activity.Initializable;
import org.apache.avalon.framework.component.Component;
import org.apache.avalon.framework.component.ComponentException;
import org.apache.avalon.framework.component.ComponentManager;
import org.apache.avalon.framework.component.Composable;
import org.apache.avalon.framework.component.DefaultComponentManager;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.james.services.MailServer;
import java.util.ArrayList;
import java.util.Iterator;
/**
* A class to instantiate and schedule a set of mail fetching tasks
*
* $Id: FetchScheduler.java,v 1.1 2003/02/05 04:31:40 noel Exp $
*
* @see org.apache.james.fetchmail.FetchMail#configure(Configuration) FetchMail
*
*/
public class FetchScheduler
extends AbstractLogEnabled
implements Component, Composable, Configurable, Initializable, Disposable {
/**
* Configuration object for this service
*/
private Configuration conf;
/**
* The component manager that allows access to the system services
*/
private ComponentManager compMgr;
/**
* The scheduler service that is used to trigger fetch tasks.
*/
private TimeScheduler scheduler;
/**
* Whether this service is enabled.
*/
private volatile boolean enabled = false;
private ArrayList theFetchTaskNames = new ArrayList();
/**
* @see
org.apache.avalon.framework.component.Composable#compose(ComponentManager)
*/
public void compose(ComponentManager comp) throws ComponentException {
compMgr = comp;
}
/**
* @see
org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
*/
public void configure(Configuration conf) throws ConfigurationException {
this.conf = conf;
}
/**
* @see org.apache.avalon.framework.activity.Initializable#initialize()
*/
public void initialize() throws Exception {
enabled = conf.getAttributeAsBoolean("enabled", false);
if (enabled) {
scheduler = (TimeScheduler) compMgr.lookup(TimeScheduler.ROLE);
Configuration[] fetchConfs = conf.getChildren("fetch");
for (int i = 0; i < fetchConfs.length; i++) {
FetchMail fetcher = new FetchMail();
Configuration fetchConf = fetchConfs[i];
String fetchTaskName = fetchConf.getAttribute("name");
fetcher.enableLogging(getLogger().getChildLogger(fetchTaskName));
fetcher.compose(compMgr);
fetcher.configure(fetchConf);
Integer interval = new
Integer(fetchConf.getChild("interval").getValue());
PeriodicTimeTrigger fetchTrigger = new PeriodicTimeTrigger(0,
interval.intValue());
scheduler.addTrigger(fetchTaskName, fetchTrigger, fp);
theFetchTaskNames.add(fetchTaskName);
}
getLogger().info("FetchMail Started");
} else {
getLogger().info("FetchMail Disabled");
}
}
/**
* @see org.apache.avalon.framework.activity.Disposable#dispose()
*/
public void dispose() {
if (enabled) {
getLogger().info( "FetchMail dispose..." );
Iterator nameIterator = theFetchTaskNames.iterator();
while (nameIterator.hasNext()) {
scheduler.removeTrigger((String)nameIterator.next());
}
getLogger().info( "FetchMail ...dispose end" );
}
}
}
1.1
jakarta-james/src/java/org/apache/james/fetchmail/FetchScheduler.xinfo
Index: FetchScheduler.xinfo
===================================================================
<?xml version="1.0"?>
<blockinfo>
<!-- section to describe block -->
<block>
<version>1.0</version>
</block>
<!-- services that are offered by this block -->
<services>
<service name="org.apache.avalon.framework.component.Component" version="1.0"/>
</services>
<dependencies>
<dependency>
<service name="org.apache.james.services.MailServer" version="1.0"/>
</dependency>
<dependency>
<service name="org.apache.avalon.cornerstone.services.scheduler.TimeScheduler"
version="1.0"/>
</dependency>
</dependencies>
</blockinfo>
1.1
jakarta-james/src/java/org/apache/james/fetchmail/ReaderInputStream.java
Index: ReaderInputStream.java
===================================================================
/**
* ReaderInputStream.java
*
* Copyright (C) 24-Sep-2002 The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*
*/
package org.apache.james.fetchmail;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
/**
*
* Simple class to allow a cast from a java.io.Reader to a java.io.InputStream
*
* $Id: ReaderInputStream.java,v 1.1 2003/02/05 04:31:40 noel Exp $
*
*/
public class ReaderInputStream extends InputStream {
private Reader reader = null;
public ReaderInputStream(Reader reader) {
this.reader = reader;
}
/**
* @see java.io.InputStream#read()
*/
public int read() throws IOException {
return reader.read();
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]