You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by ch...@apache.org on 2001/05/11 11:26:09 UTC

cvs commit: jakarta-james/src/org/apache/james/pop3server POP3Handler.java POP3Server.java POP3Server.xinfo

charlesb    01/05/11 02:26:09

  Added:       src/java/org/apache/james/mailrepository
                        AvalonMailRepository.java
                        AvalonSpoolRepository.java
                        FileMimeMessageInputStream.java
                        TownMimeMessageInputStream.java
                        TownSpoolRepository.java
               src/java/org/apache/james/pop3server POP3Handler.java
                        POP3Server.java POP3Server.xinfo
  Removed:     src/org/apache/james/mailrepository
                        AvalonMailRepository.java
                        AvalonSpoolRepository.java
                        FileMimeMessageInputStream.java
                        TownMimeMessageInputStream.java
                        TownSpoolRepository.java
               src/org/apache/james/pop3server POP3Handler.java
                        POP3Server.java POP3Server.xinfo
  Log:
  Moving from src/org to src/java/org
  
  Revision  Changes    Path
  1.1                  jakarta-james/src/java/org/apache/james/mailrepository/AvalonMailRepository.java
  
  Index: AvalonMailRepository.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.mailrepository;
  
  import java.io.InputStream;
  import java.io.OutputStream;
  import java.util.Iterator;
  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.configuration.Configurable;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.configuration.DefaultConfiguration;
  import org.apache.avalon.framework.logger.AbstractLoggable;
  import org.apache.avalon.cornerstone.services.store.ObjectRepository;
  import org.apache.avalon.cornerstone.services.store.Store;
  import org.apache.avalon.cornerstone.services.store.StreamRepository;
  import org.apache.james.core.MailImpl;
  import org.apache.james.services.MailRepository;
  import org.apache.james.services.MailStore;
  import org.apache.james.util.Lock;
  import org.apache.james.util.LockException;
  
  /**
   * Implementation of a MailRepository on a FileSystem.
   *
   * Requires a configuration element in the .conf.xml file of the form:
   *  <repository destinationURL="file://path-to-root-dir-for-repository"
   *              type="MAIL"
   *              model="SYNCHRONOUS"/>
   * Requires a logger called MailRepository.
   *
   * @version 1.0.0, 24/04/1999
   * @author  Federico Barbieri <sc...@pop.systemy.it>
   * @author Charles Benett <ch...@benett1.demon.co.uk>
   */
  public class AvalonMailRepository
      extends AbstractLoggable
      implements MailRepository, Component, Configurable, Composable {
  
      protected Lock lock;
      protected static boolean DEEP_DEBUG = true;
      private static final String TYPE = "MAIL";
      private Store store;
      private StreamRepository sr;
      private ObjectRepository or;
      private MailStore mailstore;
      private String destination;
  
  
      public void configure(Configuration conf) throws ConfigurationException {
          destination = conf.getAttribute("destinationURL");
          String checkType = conf.getAttribute("type");
          if (! (checkType.equals("MAIL") || checkType.equals("SPOOL")) ) {
              getLogger().warn( "Attempt to configure AvalonMailRepository as " +
                                checkType);
              throw new ConfigurationException("Attempt to configure AvalonMailRepository as " + checkType);
          }
          // ignore model
      }
  
      public void compose( final ComponentManager componentManager )
          throws ComponentException {
          try {
              store = (Store)componentManager.
                  lookup( "org.apache.avalon.cornerstone.services.store.Store" );
  
              //prepare Configurations for object and stream repositories
              DefaultConfiguration objectConfiguration
                  = new DefaultConfiguration( "repository",
                                              "generated:AvalonFileRepository.compose()" );
  
              objectConfiguration.addAttribute("destinationURL", destination);
              objectConfiguration.addAttribute("type", "OBJECT");
              objectConfiguration.addAttribute("model", "SYNCHRONOUS");
  
              DefaultConfiguration streamConfiguration
                  = new DefaultConfiguration( "repository",
                                              "generated:AvalonFileRepository.compose()" );
  
              streamConfiguration.addAttribute( "destinationURL", destination );
              streamConfiguration.addAttribute( "type", "STREAM" );
              streamConfiguration.addAttribute( "model", "SYNCHRONOUS" );
  
              sr = (StreamRepository) store.select(streamConfiguration);
              or = (ObjectRepository) store.select(objectConfiguration);
              lock = new Lock();
  	    getLogger().debug(this.getClass().getName() + " created in " + destination);
          } catch (Exception e) {
              final String message = "Failed to retrieve Store component:" + e.getMessage();
              getLogger().error( message, e );
              throw new ComponentException( message, e );
          }
      }
  
      public synchronized void unlock(Object key) {
  
          if (lock.unlock(key)) {
              notifyAll();
          } else {
              throw new LockException("Your thread do not own the lock of record " + key);
          }
      }
  
      public synchronized void lock(Object key) {
  
          if (lock.lock(key)) {
              notifyAll();
          } else {
              throw new LockException("Record " + key + " already locked by another thread");
          }
      }
  
      public synchronized void store(MailImpl mc) {
          try {
              String key = mc.getName();
              OutputStream out = sr.put(key);
              mc.writeMessageTo(out);
              out.close();
              or.put(key, mc);
  	    if(DEEP_DEBUG) getLogger().debug("Mail " + key + " stored." );
              notifyAll();
          } catch (Exception e) {
  	    getLogger().error("Exception storing mail: " + e);
              e.printStackTrace();
              throw new RuntimeException("Exception caught while storing Message Container: " + e);
          }
      }
  
      public MailImpl retrieve(String key) {
  	if(DEEP_DEBUG) getLogger().debug("Retrieving mail: " + key);
          MailImpl mc = (MailImpl) or.get(key);
          try {
              InputStream in = new FileMimeMessageInputStream(sr, key);
              mc.setMessage(in);
              in.close();
          } catch (Exception me) {
  	    getLogger().error("Exception retrieving mail: " + me);
              throw new RuntimeException("Exception while retrieving mail: " + me.getMessage());
          }
          return mc;
      }
  
      public void remove(MailImpl mail) {
          remove(mail.getName());
      }
  
      public void remove(String key) {
          try {
              lock( key);
              sr.remove(key);
              or.remove(key);
          } finally {
              unlock(key);
          }
      }
  
      public Iterator list() {
          return sr.list();
      }
  }
  
  
  
  1.1                  jakarta-james/src/java/org/apache/james/mailrepository/AvalonSpoolRepository.java
  
  Index: AvalonSpoolRepository.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.mailrepository;
  
  import java.util.Iterator;
  import javax.mail.MessagingException;
  import org.apache.james.util.Lock;
  import org.apache.james.core.MailImpl;
  import org.apache.james.services.MailStore;
  import org.apache.james.services.SpoolRepository;
  import org.apache.mailet.Mail;
  
  /**
   * Implementation of a MailRepository on a FileSystem.
   *
   * Requires a configuration element in the .conf.xml file of the form:
   *  <repository destinationURL="file://path-to-root-dir-for-repository"
   *              type="MAIL"
   *              model="SYNCHRONOUS"/>
   * Requires a logger called MailRepository.
   * 
   * @version 1.0.0, 24/04/1999
   * @author  Federico Barbieri <sc...@pop.systemy.it>
   * @author Charles Benett <ch...@benett1.demon.co.uk>
   */
  public class AvalonSpoolRepository 
      extends AvalonMailRepository 
      implements SpoolRepository {
  
      public synchronized String accept() {
  	if (DEEP_DEBUG) getLogger().debug("Method accept() called");
          while (true) {
              for(Iterator it = list(); it.hasNext(); ) {
                  
                  String s = it.next().toString();
  		if (DEEP_DEBUG) getLogger().debug("Found item " + s
                                                    + " in spool.");
                  if (lock.lock(s)) {
  		    if (DEEP_DEBUG) getLogger().debug("accept() has locked: "
                                                        + s);
                      return s;
                  }
                  //  Object o = it.next();
                  //if (lock.lock(o)) {
                  //  return o.toString();
                  //}
              }
              try {
                  wait();
              } catch (InterruptedException ignored) {
              }
          }
      }
  
      public synchronized String accept(long delay) {
  	if (DEEP_DEBUG) getLogger().debug("Method accept(delay) called");
          while (true) {
              long youngest = 0;
              for (Iterator it = list(); it.hasNext(); ) {
                  String s = it.next().toString();
  		if (DEEP_DEBUG) getLogger().debug("Found item " + s
                                                    + " in spool.");
                  if (lock.lock(s)) {
  		    if (DEEP_DEBUG) getLogger().debug("accept(delay) has"
                                                        + " locked: "  + s);
                      //We have a lock on this object... let's grab the message
                      //  and see if it's a valid time.
                      MailImpl mail = retrieve(s);
                      if (mail.getState().equals(Mail.ERROR)) {
                          //Test the time...
                          long timeToProcess = delay + mail.getLastUpdated().getTime();
                          if (System.currentTimeMillis() > timeToProcess) {
                              //We're ready to process this again
                              return s;
                          } else {
                              //We're not ready to process this.
                              if (youngest == 0 || youngest > timeToProcess) {
                                  //Mark this as the next most likely possible mail to process
                                  youngest = timeToProcess;
                              }
                          }
                      } else {
                          //This mail is good to go... return the key
                          return s;
                      }
                  }
              }
              //We did not find any... let's wait for a certain amount of time
              try {
                  if (youngest == 0) {
                      wait();
                  } else {
                      wait(youngest - System.currentTimeMillis());
                  }
              } catch (InterruptedException ignored) {
              }
          }
      }
  }
  
  
  
  1.1                  jakarta-james/src/java/org/apache/james/mailrepository/FileMimeMessageInputStream.java
  
  Index: FileMimeMessageInputStream.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.mailrepository;
  
  import java.io.IOException;
  import java.io.InputStream;
  import org.apache.avalon.cornerstone.services.store.StreamRepository;
  import org.apache.james.core.JamesMimeMessageInputStream;
  
  public class FileMimeMessageInputStream 
      extends JamesMimeMessageInputStream {
  
      //Define how to get to the data
      StreamRepository sr = null;
      String key = null;
  
      public FileMimeMessageInputStream( StreamRepository sr, String key) throws IOException {
          this.sr = sr;
          this.key = key;
      }
  
      public StreamRepository getStreamStore() {
          return sr;
      }
  
      public String getKey() {
          return key;
      }
  
      protected synchronized InputStream openStream() throws IOException {
          return sr.get(key);
      }
  
      public boolean equals(Object obj) {
          if (obj instanceof FileMimeMessageInputStream) {
              FileMimeMessageInputStream in = (FileMimeMessageInputStream)obj;
              return in.getStreamStore().equals(sr) && in.getKey().equals(key);
          }
          return false;
      }
  }
  
  
  
  1.1                  jakarta-james/src/java/org/apache/james/mailrepository/TownMimeMessageInputStream.java
  
  Index: TownMimeMessageInputStream.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.mailrepository;
  
  import com.workingdogs.town.ConnDefinition;
  import com.workingdogs.town.QueryDataSet;
  import com.workingdogs.town.Record;
  import java.io.ByteArrayInputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import org.apache.james.core.JamesMimeMessageInputStream;
  
  public class TownMimeMessageInputStream 
      extends JamesMimeMessageInputStream {
  
      //Define how to get to the data
      String connDefinition = null;
      String table = null;
      String key = null;
      String repository = null;
  
      public TownMimeMessageInputStream(String connDefinition, 
                                        String table, 
                                        String key, 
                                        String repository) throws IOException {
          if (connDefinition == null) {
              throw new IOException("Conn definition is null");
          }
          if (table == null) {
              throw new IOException("Table is null");
          }
          if (key == null) {
              throw new IOException("Message name (key) was not defined");
          }
          if (repository == null) {
              throw new IOException("Repository is null");
          }
          this.connDefinition = connDefinition;
          this.table = table;
          this.key = key;
          this.repository = repository;
      }
  
      public String getConnDefinition() {
          return connDefinition;
      }
  
      public String getTable() {
          return table;
      }
  
      public String getMessageName() {
          return key;
      }
  
      public String getRepository() {
          return repository;
      }
  
      protected synchronized InputStream openStream() throws IOException {
          //System.err.println("loading data for " + key + "/" + repository);
  
          //TableDataSet messages = new TableDataSet(ConnDefinition.getInstance(connDefinition), table);
          //messages.setWhere("message_name='" + key + "' and repository_name='" + repository + "'");
          //messages.setColumns("message_body");
          QueryDataSet messages = new QueryDataSet(ConnDefinition.getInstance(connDefinition),
                                                   "SELECT message_body "
                                                   + " FROM " + table
                                                   + " WHERE message_name='" + key + "' AND repository_name='" + repository + "'");
          if (messages.size() == 0) {
              throw new IOException("Could not find message");
          }
          Record message = messages.getRecord(0);
          return new ByteArrayInputStream(message.getAsBytes("message_body"));
      }
  
      public boolean equals(Object obj) {
          if (obj instanceof TownMimeMessageInputStream) {
              TownMimeMessageInputStream in = (TownMimeMessageInputStream)obj;
              return in.getConnDefinition().equals(connDefinition)
                  && in.getTable().equals(table)
                  && in.getMessageName().equals(key)
                  && in.getRepository().equals(repository);
          }
          return false;
      }
  }
  
  
  
  1.1                  jakarta-james/src/java/org/apache/james/mailrepository/TownSpoolRepository.java
  
  Index: TownSpoolRepository.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.mailrepository;
  
  import com.workingdogs.town.ConnDefinition;
  import com.workingdogs.town.QueryDataSet;
  import com.workingdogs.town.Record;
  import com.workingdogs.town.TableDataSet;
  import java.io.ByteArrayOutputStream;
  import java.io.InputStream;
  import java.util.ArrayList;
  import java.util.Date;
  import java.util.HashSet;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Set;
  import java.util.StringTokenizer;
  import javax.mail.internet.MimeMessage;
  import org.apache.avalon.framework.component.Component;
  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.AbstractLoggable;
  import org.apache.james.core.JamesMimeMessage;
  import org.apache.james.core.MailImpl;
  import org.apache.james.services.SpoolRepository;
  import org.apache.james.util.Lock;
  import org.apache.james.util.LockException;
  import org.apache.mailet.Mail;
  import org.apache.mailet.MailAddress;
  
  /**
   * Implementation of a SpoolRepository on a database.
   *
   * <p>Requires a configuration element in the .conf.xml file of the form:
   *  <br><repository destinationURL="town://path"
   *  <br>            type="MAIL"
   *  <br>            model="SYNCHRONOUS"/>
   *  <br>            <conn>file:///dev/james/dist/var/maildatabase</conn>
   *  <br>            <table>Message</table>
   *  <br></repository>
   * <p>destinationURL specifies..(Serge??)
   * <br>Type can be SPOOL or MAIL
   * <br>Model is currently not used and may be dropped
   * <br>conn is the location of the ...(Serge)
   * <br>table is the name of the table in the Database to be used
   *
   * <p>Requires a logger called MailRepository.
   *
   * @version 1.0.0, 24/04/1999
   * @author  Serge Knystautas <se...@lokitech.com>
   */
  public class TownSpoolRepository
      extends AbstractLoggable
      implements SpoolRepository, Component, Configurable {
  
      private Lock lock;
      private String destination;
      private String repositoryName;
  
      private String conndefinition;
      private String tableName;
  
      public void configure(Configuration conf) throws ConfigurationException {
          destination = conf.getAttribute("destinationURL");
          repositoryName = destination.substring(destination.indexOf("//") + 2);
          String checkType = conf.getAttribute("type");
          if (! (checkType.equals("MAIL") || checkType.equals("SPOOL")) ) {
              final String message =
                  "Attempt to configure TownSpoolRepository as " + checkType;
              getLogger().warn( message );
              throw new ConfigurationException( message );
          }
          // ignore model
          conndefinition = conf.getChild("conn").getValue();
          tableName = conf.getChild("table").getValue();
      }
  
      public synchronized void unlock(Object key) {
          if (lock.unlock(key)) {
              notifyAll();
          } else {
              throw new LockException("Your thread do not own the lock of record " + key);
          }
      }
  
      public synchronized void lock(Object key) {
          if (lock.lock(key)) {
              notifyAll();
          } else {
              throw new LockException("Record " + key + " already locked by another thread");
          }
      }
  
      public void store(MailImpl mc) {
          try {
              //System.err.println("storing " + mc.getName());
              String key = mc.getName();
              mc.setLastUpdated(new Date());
              TableDataSet messages = new TableDataSet(ConnDefinition.getInstance(conndefinition), tableName);
              messages.setWhere("message_name = '" + key + "' and repository_name = '" + repositoryName + "'");
              Record mail = null;
              boolean inserted = true;
              if (messages.size() == 0) {
                  inserted = true;
                  //insert the message
                  mail = messages.addRecord();
                  mail.setValue("message_name", key);
                  mail.setValue("repository_name", repositoryName + "");
              } else {
                  //update the message
                  inserted = false;
                  mail = messages.getRecord(0);
              }
              mail.setValue("message_state", mc.getState());
              mail.setValue("error_message", mc.getErrorMessage());
              mail.setValue("sender", mc.getSender().toString());
              StringBuffer recipients = new StringBuffer();
              for (Iterator i = mc.getRecipients().iterator(); i.hasNext(); ) {
                  recipients.append(i.next().toString());
                  if (i.hasNext()) {
                      recipients.append("\r\n");
                  }
              }
              mail.setValue("recipients", recipients.toString());
              mail.setValue("remote_host", mc.getRemoteHost());
              mail.setValue("remote_addr", mc.getRemoteAddr());
              mail.setValue("last_updated", mc.getLastUpdated());
              MimeMessage messageBody = mc.getMessage();
  
              boolean saveInRecord = false;
              if (messageBody instanceof JamesMimeMessage) {
                  JamesMimeMessage jamesmessage = (JamesMimeMessage)messageBody;
                  if (jamesmessage.isModified()) {
                      //Just save it...we can't be clever here
                      saveInRecord = true;
                  } else {
                      if (mail.toBeSavedWithUpdate()) {
                          //Do nothing... the message wasn't changed.
                          //System.err.println("Not saving message (" + toString() + "... wasn't changed");
                      } else {
                          //For now always save the record
                          saveInRecord = true;
  
  
                          //This message could be a transfer from another source
                          InputStream in = jamesmessage.getSourceStream();
                          if (in instanceof TownMimeMessageInputStream) {
                              //This must already be stored in the same database (hopefully)
  
                              //  Let's copy the record from here to there
  
                              //Once we do this, we'll no longer mark to saveInRecord
                          }
  
                      }
                  }
              } else {
                  //This is some other unknown MimeMessage
                  saveInRecord = true;
              }
              if (saveInRecord) {
                  //Update this field here
                  ByteArrayOutputStream bout = new ByteArrayOutputStream();
                  if (messageBody != null) {
                      messageBody.writeTo(bout);
                  }
                  mail.setValue("message_body", bout.toByteArray());
              }
              if (mail.toBeSavedWithUpdate() && messageBody instanceof JamesMimeMessage
                  && !((JamesMimeMessage)messageBody).isModified()) {
                  //Do nothing... the message wasn't changed.
              } else {
                  ByteArrayOutputStream bout = new ByteArrayOutputStream();
                  if (messageBody != null) {
                      messageBody.writeTo(bout);
                  }
                  mail.setValue("message_body", bout.toByteArray());
              }
              mail.save();
              synchronized (this) {
                  notifyAll();
              }
          } catch (Exception e) {
              e.printStackTrace();
              throw new RuntimeException("Exception caught while storing mail Container: " + e);
          }
      }
  
      public MailImpl retrieve(String key) {
          try {
              //System.err.println("retrieving " + key);
              //TableDataSet messages = new TableDataSet(ConnDefinition.getInstance(conndefinition), tableName);
              QueryDataSet messages = new QueryDataSet(ConnDefinition.getInstance(conndefinition),
                                                       "SELECT message_name, message_state, error_message, sender, recipients, remote_host, remote_addr, last_updated"
                                                       + " FROM " + tableName
                                                       + " WHERE message_name='" + key + "' and repository_name='" + repositoryName + "'");
              //messages.setWhere("message_name='" + key + "' and repository_name='" + repositoryName + "'");
              Record message = messages.getRecord(0);
              MailImpl mc = new MailImpl();
              mc.setName(message.getAsString("message_name"));
              mc.setState(message.getAsString("message_state"));
              mc.setErrorMessage(message.getAsString("error_message"));
              mc.setSender(new MailAddress(message.getAsString("sender")));
              StringTokenizer st = new StringTokenizer(message.getAsString("recipients"), "\r\n", false);
              Set recipients = new HashSet();
              while (st.hasMoreTokens()) {
                  recipients.add(new MailAddress(st.nextToken()));
              }
              mc.setRecipients(recipients);
              mc.setRemoteHost(message.getAsString("remote_host"));
              mc.setRemoteAddr(message.getAsString("remote_addr"));
              mc.setLastUpdated(message.getAsUtilDate("last_updated"));
              InputStream in = new TownMimeMessageInputStream(conndefinition, tableName, key, repositoryName);
              //InputStream in = new ByteArrayInputStream(message.getAsBytes("message_body"));
              JamesMimeMessage jamesmessage = new JamesMimeMessage(javax.mail.Session.getDefaultInstance(System.getProperties(), null), in);
              mc.setMessage(jamesmessage);
              //mc.setMessage(bin);
              return mc;
          } catch (Exception me) {
              me.printStackTrace();
              throw new RuntimeException("Exception while retrieving mail: " + me.getMessage());
          }
      }
  
      public void remove(MailImpl mail) {
          remove(mail.getName());
      }
  
      public void remove(String key) {
          //System.err.println("removing " + key);
          try {
              lock(key);
              TableDataSet messages = new TableDataSet(ConnDefinition.getInstance(conndefinition), tableName);
              messages.setWhere("message_name='" + key + "' and repository_name='" + repositoryName + "'");
              Record message = messages.getRecord(0);
              message.markToBeDeleted();
              message.save();
          } catch (Exception me) {
              throw new RuntimeException("Exception while removing mail: " + me.getMessage());
          } finally {
              unlock(key);
          }
      }
  
      public Iterator list() {
          try {
              QueryDataSet messages = new QueryDataSet(ConnDefinition.getInstance(conndefinition),
                                                       "SELECT message_name FROM " + tableName + " WHERE repository_name = '" + repositoryName + "' "
                                                       + "ORDER BY last_updated");
              List messageList = new ArrayList(messages.size());
              for (int i = 0; i < messages.size(); i++) {
                  messageList.add(messages.getRecord(i).getAsString("message_name"));
              }
              return messageList.iterator();
          } catch (Exception me) {
              me.printStackTrace();
              throw new RuntimeException("Exception while listing mail: " + me.getMessage());
          }
      }
  
      public synchronized String accept() {
          while (true) {
              for(Iterator it = list(); it.hasNext(); ) {
                  Object o = it.next();
                  if (lock.lock(o)) {
                      return o.toString();
                  }
              }
              try {
                  wait();
              } catch (InterruptedException ignored) {
              }
          }
      }
  
      public synchronized String accept(long delay) {
          while (true) {
              long youngest = 0;
              //Really unoptimized query here... should be much smart about this...
              for (Iterator it = list(); it.hasNext(); ) {
                  String s = it.next().toString();
                  if (lock.lock(s)) {
                      //We have a lock on this object... let's grab the message
                      //  and see if it's a valid time.
                      MailImpl mail = retrieve(s);
                      if (mail.getState().equals(Mail.ERROR)) {
                          //Test the time...
                          long timeToProcess = delay + mail.getLastUpdated().getTime();
                          if (System.currentTimeMillis() > timeToProcess) {
                              //We're ready to process this again
                              return s;
                          } else {
                              //We're not ready to process this.
                              if (youngest == 0 || youngest > timeToProcess) {
                                  //Mark this as the next most likely possible mail to process
                                  youngest = timeToProcess;
                              }
                          }
                      } else {
                          //This guy is good to go... return him
                          return s;
                      }
                  }
              }
              //We did not find any... let's wait for a certain amount of time
              try {
                  if (youngest == 0) {
                      wait();
                  } else {
                      wait(youngest - System.currentTimeMillis());
                  }
              } catch (InterruptedException ignored) {
              }
          }
      }
  }
  
  
  
  1.1                  jakarta-james/src/java/org/apache/james/pop3server/POP3Handler.java
  
  Index: POP3Handler.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.pop3server;
  
  import java.io.BufferedReader;
  import java.io.IOException;
  import java.io.InputStreamReader;
  import java.io.OutputStream;
  import java.io.PrintWriter;
  import java.net.Socket;
  import java.util.Enumeration;
  import java.util.Iterator;
  import java.util.List;
  import java.util.StringTokenizer;
  import java.util.Vector;
  import javax.mail.MessagingException;
  import org.apache.avalon.framework.activity.Initializable;
  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.configuration.Configurable;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.context.Context;
  import org.apache.avalon.framework.context.ContextException;
  import org.apache.avalon.framework.context.Contextualizable;
  import org.apache.avalon.framework.logger.AbstractLoggable;
  import org.apache.avalon.cornerstone.services.connection.ConnectionHandler;
  import org.apache.avalon.cornerstone.services.scheduler.PeriodicTimeTrigger;
  import org.apache.avalon.cornerstone.services.scheduler.Target;
  import org.apache.avalon.cornerstone.services.scheduler.TimeScheduler;
  import org.apache.avalon.excalibur.collections.ListUtils;
  import org.apache.james.Constants;
  import org.apache.james.core.MailImpl;
  import org.apache.james.services.MailRepository;
  import org.apache.james.services.MailServer;
  import org.apache.james.services.UsersRepository;
  import org.apache.james.services.UsersStore;
  import org.apache.james.BaseConnectionHandler;
  import org.apache.james.util.InternetPrintWriter;
  import org.apache.mailet.Mail;
  
  /**
   * @author Federico Barbieri <sc...@systemy.it>
   * @version 0.9
   */
  public class POP3Handler
      extends BaseConnectionHandler
      implements ConnectionHandler, Composable, Configurable, Target {
  
      private String softwaretype        = "JAMES POP3 Server " + Constants.SOFTWARE_VERSION;
  
      private ComponentManager compMgr;
      private MailServer mailServer;
      private MailRepository userInbox;
      private UsersRepository users;
      private TimeScheduler scheduler;
  
      private Socket socket;
      private BufferedReader in;
      private PrintWriter out;
      private OutputStream outs;
      private String remoteHost;
      private String remoteIP;
      private int state;
      private String user;
      private Vector userMailbox = new Vector();
      private Vector backupUserMailbox;
      private static final Mail DELETED = new MailImpl();
  
      private static int AUTHENTICATION_READY = 0;
      private static int AUTHENTICATION_USERSET = 1;
      private static int TRANSACTION = 2;
  
      private final static String OK_RESPONSE = "+OK";
      private final static String ERR_RESPONSE = "-ERR";
  
      public void compose( final ComponentManager componentManager )
          throws ComponentException {
          mailServer = (MailServer)componentManager.
              lookup( "org.apache.james.services.MailServer" );
          UsersStore usersStore = (UsersStore)componentManager.
              lookup( "org.apache.james.services.UsersStore" );
          users = usersStore.getRepository("LocalUsers");
          scheduler = (TimeScheduler)componentManager.
              lookup( "org.apache.avalon.cornerstone.services.scheduler.TimeScheduler" );
      }
  
      /**
       * Handle a connection.
       * This handler is responsible for processing connections as they occur.
       *
       * @param connection the connection
       * @exception IOException if an error reading from socket occurs
       * @exception ProtocolException if an error handling connection occurs
       */
      public void handleConnection( Socket connection )
          throws IOException {
  
          try {
              this.socket = connection;
              in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
              outs = socket.getOutputStream();
              out = new InternetPrintWriter(outs, true);
              remoteHost = socket.getInetAddress ().getHostName ();
              remoteIP = socket.getInetAddress ().getHostAddress ();
          } catch (Exception e) {
              getLogger().error( "Cannot open connection from " + remoteHost +
                                 " (" + remoteIP + "): " + e.getMessage(), e );
          }
  
          getLogger().info( "Connection from " + remoteHost + " (" + remoteIP + ")" );
  
          try {
              final PeriodicTimeTrigger trigger = new PeriodicTimeTrigger( timeout, -1 );
              scheduler.addTrigger( this.toString(), trigger, this );
              state = AUTHENTICATION_READY;
              user = "unknown";
              out.println( OK_RESPONSE + " " + this.helloName +
                           " POP3 server (" + this.softwaretype + ") ready " );
              while (parseCommand(in.readLine())) {
                  scheduler.resetTrigger(this.toString());
              }
              socket.close();
              scheduler.removeTrigger(this.toString());
              getLogger().info("Connection closed");
  
          } catch (Exception e) {
              out.println(ERR_RESPONSE + " Error closing connection.");
              out.flush();
              getLogger().error( "Exception during connection from " + remoteHost +
                                 " (" + remoteIP + ") : " + e.getMessage(), e );
              try {
                  socket.close();
              } catch (IOException ioe) {
              }
          }
      }
  
      public void targetTriggered( final String triggerName ) {
          getLogger().error("Connection timeout on socket");
          try {
              out.println("Connection timeout. Closing connection");
              socket.close();
          } catch (IOException e) {
          }
      }
  
      private void stat() {
          userMailbox = new Vector();
          userMailbox.addElement(DELETED);
          for (Iterator it = userInbox.list(); it.hasNext(); ) {
              String key = (String) it.next();
              MailImpl mc = userInbox.retrieve(key);
              userMailbox.addElement(mc);
          }
          backupUserMailbox = (Vector) userMailbox.clone();
      }
  
      private boolean parseCommand(String commandRaw) {
          if (commandRaw == null) return false;
          getLogger().info("Command received: " + commandRaw);
          String command = commandRaw.trim();
          StringTokenizer commandLine = new StringTokenizer(command, " ");
          int arguments = commandLine.countTokens();
          if (arguments == 0) {
              return true;
          } else if(arguments > 0) {
              command = commandLine.nextToken();
          }
          String argument = (String) null;
          if(arguments > 1) {
              argument = commandLine.nextToken();
          }
          String argument1 = (String) null;
          if(arguments > 2) {
              argument1 = commandLine.nextToken();
          }
  
          if (command.equalsIgnoreCase("USER"))
              doUSER(command,argument,argument1);
          else if (command.equalsIgnoreCase("PASS"))
              doPASS(command,argument,argument1);
          else if (command.equalsIgnoreCase("STAT"))
              doSTAT(command,argument,argument1);
          else if (command.equalsIgnoreCase("LIST"))
              doLIST(command,argument,argument1);
          else if (command.equalsIgnoreCase("UIDL"))
              doUIDL(command,argument,argument1);
          else if (command.equalsIgnoreCase("RSET"))
              doRSET(command,argument,argument1);
          else if (command.equalsIgnoreCase("DELE"))
              doDELE(command,argument,argument1);
          else if (command.equalsIgnoreCase("NOOP"))
              doNOOP(command,argument,argument1);
          else if (command.equalsIgnoreCase("RETR"))
              doRETR(command,argument,argument1);
          else if (command.equalsIgnoreCase("TOP"))
              doTOP(command,argument,argument1);
          else if (command.equalsIgnoreCase("QUIT"))
              doQUIT(command,argument,argument1);
          else
              doUnknownCmd(command,argument,argument1);
          return (command.equalsIgnoreCase("QUIT") == false);
      }
  
      private void doUSER(String command,String argument,String argument1) {
          if (state == AUTHENTICATION_READY && argument != null) {
              user = argument;
              state = AUTHENTICATION_USERSET;
              out.println(OK_RESPONSE);
          } else {
              out.println(ERR_RESPONSE);
          }
      }
  
      private void doPASS(String command,String argument,String argument1) {
          if (state == AUTHENTICATION_USERSET && argument != null) {
              String passArg = argument;
              if (users.test(user, passArg)) {
                  state = TRANSACTION;
                  out.println(OK_RESPONSE + " Welcome " + user);
                  userInbox = mailServer.getUserInbox(user);
                  stat();
              } else {
                  state = AUTHENTICATION_READY;
                  out.println(ERR_RESPONSE + " Authentication failed.");
              }
          } else {
              out.println(ERR_RESPONSE);
          }
      }
  
      private void doSTAT(String command,String argument,String argument1) {
          if (state == TRANSACTION) {
              long size = 0;
              int count = 0;
              try {
                  for (Enumeration e = userMailbox.elements(); e.hasMoreElements(); ) {
                      MailImpl mc = (MailImpl) e.nextElement();
                      if (mc != DELETED) {
                          size += mc.getSize();
                          count++;
                      }
                  }
                  out.println(OK_RESPONSE + " " + count + " " + size);
              } catch (MessagingException me) {
                  out.println(ERR_RESPONSE);
              }
          } else {
              out.println(ERR_RESPONSE);
          }
      }
      private void doLIST(String command,String argument,String argument1) {
          if (state == TRANSACTION) {
              if (argument == null) {
                  long size = 0;
                  int count = 0;
                  try {
                      for (Enumeration e = userMailbox.elements(); e.hasMoreElements(); ) {
                          MailImpl mc = (MailImpl) e.nextElement();
                          if (mc != DELETED) {
                              size += mc.getSize();
                              count++;
                          }
                      }
                      out.println(OK_RESPONSE + " " + count + " " + size);
                      count = 0;
                      for (Enumeration e = userMailbox.elements(); e.hasMoreElements(); count++) {
                          MailImpl mc = (MailImpl) e.nextElement();
                          if (mc != DELETED) {
                              out.println(count + " " + mc.getSize());
                          }
                      }
                      out.println(".");
                  } catch (MessagingException me) {
                      out.println(ERR_RESPONSE);
                  }
              } else {
                  int num = 0;
                  try {
                      num = Integer.parseInt(argument);
                      MailImpl mc = (MailImpl) userMailbox.elementAt(num);
                      if (mc != DELETED) {
                          out.println(OK_RESPONSE + " " + num + " " + mc.getSize());
                      } else {
                          out.println(ERR_RESPONSE + " Message (" + num + ") does not exist.");
                      }
                  } catch (ArrayIndexOutOfBoundsException npe) {
                      out.println(ERR_RESPONSE + " Message (" + num + ") does not exist.");
                  } catch (NumberFormatException nfe) {
                      out.println(ERR_RESPONSE + " " + argument + " is not a valid number");
                  } catch (MessagingException me) {
                      out.println(ERR_RESPONSE);
                  }
              }
          } else {
              out.println(ERR_RESPONSE);
          }
      }
  
      private void doUIDL(String command,String argument,String argument1) {
          if (state == TRANSACTION) {
              if (argument == null) {
                  out.println(OK_RESPONSE + " unique-id listing follows");
                  int count = 0;
                  for (Enumeration e = userMailbox.elements(); e.hasMoreElements(); count++) {
                      MailImpl mc = (MailImpl) e.nextElement();
                      if (mc != DELETED) {
                          out.println(count + " " + mc.getName());
                      }
                  }
                  out.println(".");
              } else {
                  int num = 0;
                  try {
                      num = Integer.parseInt(argument);
                      MailImpl mc = (MailImpl) userMailbox.elementAt(num);
                      if (mc != DELETED) {
                          out.println(OK_RESPONSE + " " + num + " " + mc.getName());
                      } else {
                          out.println(ERR_RESPONSE + " Message (" + num + ") does not exist.");
                      }
                  } catch (ArrayIndexOutOfBoundsException npe) {
                      out.println(ERR_RESPONSE + " Message (" + num + ") does not exist.");
                  } catch (NumberFormatException nfe) {
                      out.println(ERR_RESPONSE + " " + argument + " is not a valid number");
                  }
              }
          } else {
              out.println(ERR_RESPONSE);
          }
      }
      private void doRSET(String command,String argument,String argument1) {
          if (state == TRANSACTION) {
              stat();
              out.println(OK_RESPONSE);
          } else {
              out.println(ERR_RESPONSE);
          }
      }
  
      private void doDELE(String command,String argument,String argument1) {
          if (state == TRANSACTION) {
              int num = 0;
              try {
                  num = Integer.parseInt(argument);
              } catch (Exception e) {
                  out.println(ERR_RESPONSE + " Usage: DELE [mail number]");
                  return;
              }
              try {
                  MailImpl mc = (MailImpl) userMailbox.elementAt(num);
                  if (mc == DELETED) {
                      out.println(ERR_RESPONSE + " Message (" + num + ") does not exist.");
                  } else {
                      userMailbox.setElementAt(DELETED, num);
                      out.println(OK_RESPONSE + " Message removed");
                  }
              } catch (ArrayIndexOutOfBoundsException iob) {
                  out.println(ERR_RESPONSE + " Message (" + num + ") does not exist.");
              }
          } else {
              out.println(ERR_RESPONSE);
          }
      }
      private void doNOOP(String command,String argument,String argument1) {
          if (state == TRANSACTION) {
              out.println(OK_RESPONSE);
          } else {
              out.println(ERR_RESPONSE);
          }
      }
      private void doRETR(String command,String argument,String argument1) {
          if (state == TRANSACTION) {
              int num = 0;
              try {
                  num = Integer.parseInt(argument.trim());
              } catch (Exception e) {
                  out.println(ERR_RESPONSE + " Usage: RETR [mail number]");
                  return;
              }
              //?May be written as
              //return parseCommand("TOP " + num + " " + Integer.MAX_VALUE);?
              try {
                  MailImpl mc = (MailImpl) userMailbox.elementAt(num);
                  if (mc != DELETED) {
                      out.println(OK_RESPONSE + " Message follows");
                      mc.writeMessageTo(outs);
                      out.println();
                      out.println(".");
                  } else {
                      out.println(ERR_RESPONSE + " Message (" + num + ") deleted.");
                  }
              } catch (IOException ioe) {
                  out.println(ERR_RESPONSE + " Error while retrieving message.");
              } catch (MessagingException me) {
                  out.println(ERR_RESPONSE + " Error while retrieving message.");
              } catch (ArrayIndexOutOfBoundsException iob) {
                  out.println(ERR_RESPONSE + " Message (" + num + ") does not exist.");
              }
              // -------------------------------------------?
          } else {
              out.println(ERR_RESPONSE);
          }
      }
      private void doTOP(String command,String argument,String argument1) {
          if (state == TRANSACTION) {
              int num = 0;
              int lines = 0;
              try {
                  num = Integer.parseInt(argument);
                  lines = Integer.parseInt(argument1);
              } catch (NumberFormatException nfe) {
                  out.println(ERR_RESPONSE + " Usage: TOP [mail number] [Line number]");
                  return;
              }
              try {
                  MailImpl mc = (MailImpl) userMailbox.elementAt(num);
                  if (mc != DELETED) {
                      out.println(OK_RESPONSE + " Message follows");
                      for (Enumeration e = mc.getMessage().getAllHeaderLines(); e.hasMoreElements(); ) {
                          out.println(e.nextElement());
                      }
                      out.println("");
                      mc.writeContentTo(outs, lines);
                      out.println(".");
                  } else {
                      out.println(ERR_RESPONSE + " Message (" + num + ") already deleted.");
                  }
              } catch (IOException ioe) {
                  out.println(ERR_RESPONSE + " Error while retrieving message.");
              } catch (MessagingException me) {
                  out.println(ERR_RESPONSE + " Error while retrieving message.");
              } catch (ArrayIndexOutOfBoundsException iob) {
                  out.println(ERR_RESPONSE + " Message (" + num + ") does not exist.");
              }
          } else {
              out.println(ERR_RESPONSE);
          }
      }
      private void doQUIT(String command,String argument,String argument1) {
          if (state == AUTHENTICATION_READY ||  state == AUTHENTICATION_USERSET) {
              return;
          }
          List toBeRemoved =  ListUtils.subtract(backupUserMailbox, userMailbox);
          try {
              for (Iterator it = toBeRemoved.iterator(); it.hasNext(); ) {
                  MailImpl mc = (MailImpl) it.next();
                  userInbox.remove(mc.getName());
              }
              out.println(OK_RESPONSE + " Apache James POP3 Server signing off.");
          } catch (Exception ex) {
              out.println(ERR_RESPONSE + " Some deleted messages were not removed");
              getLogger().error("Some deleted messages were not removed: " + ex.getMessage());
          }
      }
      private void doUnknownCmd(String command,String argument,String argument1) {
          out.println(ERR_RESPONSE);
      }
  }
  
  
  
  
  1.1                  jakarta-james/src/java/org/apache/james/pop3server/POP3Server.java
  
  Index: POP3Server.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.pop3server;
  
  import java.net.InetAddress;
  import java.net.UnknownHostException;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.cornerstone.services.connection.AbstractService;
  import org.apache.avalon.cornerstone.services.connection.ConnectionHandlerFactory;
  import org.apache.avalon.cornerstone.services.connection.DefaultHandlerFactory;
  
  /**
   * @version 1.0.0, 24/04/1999
   * @author  Federico Barbieri <sc...@pop.systemy.it>
   */
  public class POP3Server 
      extends AbstractService {
  
      protected ConnectionHandlerFactory createFactory()
      {
          return new DefaultHandlerFactory( POP3Handler.class );
      }
  
      public void configure( final Configuration configuration )
          throws ConfigurationException {
  
          m_port = configuration.getChild( "port" ).getValueAsInteger( 25 );
  
          try 
          { 
              final String bindAddress = configuration.getChild( "bind" ).getValue( null );
              if( null != bindAddress )
              {
                  m_bindTo = InetAddress.getByName( bindAddress ); 
              }
          }
          catch( final UnknownHostException unhe ) 
          {
              throw new ConfigurationException( "Malformed bind parameter", unhe );
          }
  
          final String useTLS = configuration.getChild("useTLS").getValue( "" );
          if( useTLS.equals( "TRUE" ) ) m_serverSocketType = "ssl";
  
          super.configure( configuration.getChild( "handler" ) );
      }
  
      public void initialize() throws Exception {
  
          getLogger().info( "POP3Server init..." );
          getLogger().info( "POP3Listener using " + m_serverSocketType + " on port " + m_port );
          super.initialize();
          getLogger().info( "POP3Server ...init end" );
          System.out.println("Started POP3 Server "+m_connectionName);
      }
  }
      
  
  
  
  1.1                  jakarta-james/src/java/org/apache/james/pop3server/POP3Server.xinfo
  
  Index: POP3Server.xinfo
  ===================================================================
  <?xml version="1.0"?>
  
  <blockinfo>
    <services>
      <service name="org.apache.avalon.framework.component.Component" version="1.0"/>
    </services>
  
    <dependencies>
      <dependency>
        <role>org.apache.james.services.MailStore</role>
        <service name="org.apache.james.services.MailStore" version="1.0"/>
      </dependency>
      <dependency>
        <role>org.apache.james.services.UsersStore</role>
        <service name="org.apache.james.services.UsersStore" version="1.0"/>
      </dependency>
      <dependency>
        <role>org.apache.avalon.cornerstone.services.connection.ConnectionManager</role>
        <service name="org.apache.avalon.cornerstone.services.connection.ConnectionManager" 
                 version="1.0"/>
      </dependency>
      <dependency>
        <role>org.apache.avalon.cornerstone.services.sockets.SocketManager</role>
        <service name="org.apache.avalon.cornerstone.services.sockets.SocketManager" version="1.0"/>
      </dependency>
      <dependency>
        <role>org.apache.avalon.cornerstone.services.scheduler.TimeScheduler</role>
        <service name="org.apache.avalon.cornerstone.services.scheduler.TimeScheduler" version="1.0"/>
      </dependency> 
      <dependency>
        <role>org.apache.james.services.MailServer</role>
        <service name="org.apache.james.services.MailServer" version="1.0"/>
      </dependency> 
    </dependencies>  
  </blockinfo>
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: james-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: james-dev-help@jakarta.apache.org