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/06/14 15:05:03 UTC

cvs commit: jakarta-james/src/java/org/apache/james/util Base64.java

charlesb    01/06/14 06:05:03

  Modified:    src/conf james-config.xml
               src/java/org/apache/james/smtpserver SMTPHandler.java
  Added:       src/java/org/apache/james/util Base64.java
  Log:
  Added Jason Borden s SMTP AUTH code to main tree. Seems to work fine.
  
  Revision  Changes    Path
  1.3       +46 -31    jakarta-james/src/conf/james-config.xml
  
  Index: james-config.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-james/src/conf/james-config.xml,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- james-config.xml	2001/06/11 09:29:23	1.2
  +++ james-config.xml	2001/06/14 13:05:02	1.3
  @@ -13,6 +13,8 @@
       CONFIRM? comment in the left
       margin.
   
  +    This is $Revision: 1.3 $
  +    Committed on $Date: 2001/06/14 13:05:02 $ by: $Author: charlesb $ 
   -->
   <config>
   
  @@ -243,7 +245,9 @@
             NOTE 1: the order of matcher-mailets is important: it must come after 
             valid local recipients have been dealt with but before any attempt is 
             made to delivery the mail remotely.
  -          NOTE 2: Add your own network, if you want to relay mail outwards -->
  +          NOTE 2: Add your own network, if you want to relay mail outwards 
  +          NOTE 3: If you use SMTP AUTH, you may want to comment this
  +          so users who are on the road can still use the server -->
             <mailet match="RemoteAddrNotInNetwork=127.0.0.1" class="ToProcessor">
               <processor> spam </processor>
             </mailet>
  @@ -300,7 +304,6 @@
           <authoritative>false</authoritative>
     </dnsserver>
   
  -<!-- CHECKME! Change the default password! -->
     <remotemanager>
           <port>4555</port>
           <!-- <bind>  </bind> uncomment this if you want to bind to a specific
  @@ -308,14 +311,15 @@
           <!-- <useTLS>TRUE</useTLS> uncomment this if you want to use TLS (SSL)
           on this port -->
           <handler>
  -          <!-- helloName is the single host name this instance of James will use to
  -           identify itself  for example, in SMTP and POP3 greetings.
  -           If autodetect is TRUE, James will attempt to discover its own name OR
  -           use 'localhost'. If autodetect is FALSE, James will use the value given
  -           OR 'localhost' -->
  +          <!-- helloName is the single host name this instance of James will
  +          use to identify itself  for example, in SMTP and POP3 greetings. If
  +          autodetect is TRUE, James will attempt to discover its own name OR
  +          use 'localhost'. If autodetect is FALSE, James will use the value
  +          given OR 'localhost' -->
             <helloName autodetect="TRUE">myMailServer</helloName>
             <administrator_accounts>
   
  +<!-- CHECKME! Change the default password! -->
               <!-- FILL ME!!!!!!  You must provide a password for your
                administrator accounts (cannot be blank) -->
               <account login="root" password="root"/>
  @@ -336,11 +340,11 @@
           <!-- <useTLS>TRUE</useTLS> uncomment this if you want to use TLS (SSL)
           on this port -->
           <handler>
  -          <!-- helloName is the single host name this instance of James will use to
  -            identify itself  for example, in SMTP and POP3 greetings.
  -            If autodetect is TRUE, James will attempt to discover its own name OR
  -            use 'localhost'. If autodetect is FALSE, James will use the value given
  -            OR 'localhost' -->
  +          <!-- helloName is the single host name this instance of James will
  +          use to identify itself  for example, in SMTP and POP3 greetings. If
  +          autodetect is TRUE, James will attempt to discover its own name OR
  +          use 'localhost'. If autodetect is FALSE, James will use the value
  +          given OR 'localhost' -->
             <helloName autodetect="TRUE">myMailServer</helloName>
             <connectiontimeout>1800000</connectiontimeout>
   	</handler>
  @@ -356,11 +360,11 @@
           <!-- <useTLS>TRUE</useTLS> uncomment this if you want to use TLS (SSL)
           on this port -->
           <handler>
  -          <!-- helloName is the single host name this instance of James will use to
  -            identify itself  for example, in SMTP and POP3 greetings.
  -            If autodetect is TRUE, James will attempt to discover its own name OR
  -            use 'localhost'. If autodetect is FALSE, James will use the value given
  -            OR 'localhost' -->
  +          <!-- helloName is the single host name this instance of James will
  +          use to identify itself  for example, in SMTP and POP3 greetings. If
  +          autodetect is TRUE, James will attempt to discover its own name OR
  +          use 'localhost'. If autodetect is FALSE, James will use the value
  +          given OR 'localhost' -->
             <helloName autodetect="TRUE">myMailServer</helloName>
             <connectiontimeout>120000</connectiontimeout>
           </handler>
  @@ -373,16 +377,26 @@
           <!--<useTLS>TRUE</useTLS> uncomment this if you want to use TLS (SSL)
           on this port -->
           <handler>
  -          <!-- helloName is the single host name this instance of James will use to
  -            identify itself  for example, in SMTP and POP3 greetings.
  -            If autodetect is TRUE, James will attempt to discover its own name OR
  -            use 'localhost'. If autodetect is FALSE, James will use the value given
  -            OR 'localhost' -->
  +          <!-- helloName is the single host name this instance of James will
  +          use to identify itself  for example, in SMTP and POP3 greetings. If
  +          autodetect is TRUE, James will attempt to discover its own name OR
  +          use 'localhost'. If autodetect is FALSE, James will use the value
  +          given OR 'localhost' -->
             <helloName autodetect="TRUE">myMailServer</helloName>
             <connectiontimeout>360000</connectiontimeout>
  +
  +	  <!--<authRequired>true</authRequired> uncomment this if you want
  +          SMTP AUTH support. This is useful if you have users who need to use
  +          the email server on the road, while not having your server act as an
  +          open relay! -->
  +
  +	  <!--<verifyIdentity>true</verifyIdentity> uncomment this if you want
  +          to verify that the MAIL FROM: address is the same user that
  +          authenticated. This prevents a user of your mail server from acting
  +          as somebody else -->
  +
             <!-- This sets the maximum allowed message size for the smtphandler
  -          in KBytes.
  -          The value defaults to 0, which means no limit.
  +          in KBytes. The value defaults to 0, which means no limit.
             <maxmessagesize>0</maxmessagesize>
              -->
           </handler>
  @@ -398,11 +412,11 @@
           <!-- <useTLS>TRUE</useTLS> uncomment this if you want to use TLS (SSL)
           on this port -->
           <handler>
  -          <!-- helloName is the single host name this instance of James will use to
  -            identify itself  for example, in SMTP and POP3 greetings.
  -            If autodetect is TRUE, James will attempt to discover its own name OR
  -            use 'localhost'. If autodetect is FALSE, James will use the value given
  -            OR 'localhost' -->
  +          <!-- helloName is the single host name this instance of James will
  +          use to identify itself  for example, in SMTP and POP3 greetings. If
  +          autodetect is TRUE, James will attempt to discover its own name OR
  +          use 'localhost'. If autodetect is FALSE, James will use the value
  +          given OR 'localhost' -->
             <helloName autodetect="TRUE">myMailServer</helloName>
             <connectiontimeout>120000</connectiontimeout>
   	  <!-- make this true, if you want only authenticated users to access NNTP-->
  @@ -502,8 +516,9 @@
           <table>Users</table>
         </repository>
         -->
  -      <!-- The following are examples of database connections which have been tested.
  -           Theses should provided a guide to setting up other databases as well.
  +      <!-- The following are examples of database connections which have been
  +           tested.
  +           These should provided a guide to setting up other databases as well.
              The driver.class and destination.URL properties are require,
              but destination.user and destination.password are optional. -->
         <!-- Mssql server with Inet Sprinta
  
  
  
  1.2       +190 -42   jakarta-james/src/java/org/apache/james/smtpserver/SMTPHandler.java
  
  Index: SMTPHandler.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/src/java/org/apache/james/smtpserver/SMTPHandler.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- SMTPHandler.java	2001/05/11 09:47:16	1.1
  +++ SMTPHandler.java	2001/06/14 13:05:03	1.2
  @@ -30,6 +30,8 @@
   import org.apache.james.*;
   import org.apache.james.core.*;
   import org.apache.james.services.MailServer;
  +import org.apache.james.services.UsersRepository;
  +import org.apache.james.services.UsersStore;
   import org.apache.james.util.*;
   import org.apache.mailet.*;
   
  @@ -38,11 +40,14 @@
    * commands, and when it receives a message, adds it to the spool.
    * @author Serge Knystautas <se...@lokitech.com>
    * @author Federico Barbieri <sc...@systemy.it>
  - * @version 0.9
  + * @author Jason Borden <jb...@javasense.com>
  + *
  + * This is $Revision: 1.2 $
  + * Committed on $Date: 2001/06/14 13:05:03 $ by: $Author: charlesb $ 
    */
   public class SMTPHandler
       extends BaseConnectionHandler
  -    implements ConnectionHandler, Composable, Configurable, Target  {
  +    implements ConnectionHandler, Composable, Configurable, Target {
   
       public final static String SERVER_NAME = "SERVER_NAME";
       public final static String SERVER_TYPE = "SERVER_TYPE";
  @@ -53,6 +58,7 @@
       public final static String SENDER = "SENDER_ADDRESS";
       public final static String RCPT_VECTOR = "RCPT_VECTOR";
       public final static String SMTP_ID = "SMTP_ID";
  +    public final static String AUTH = "AUTHENTICATED";
       public final static char[] SMTPTerminator = {'\r','\n','.','\r','\n'};
   
       private Socket socket;
  @@ -65,20 +71,41 @@
       private String messageID;
       private String smtpID;
   
  +    private boolean authRequired = false;
  +    private boolean verifyIdentity = false;
  +
       private Configuration conf;
       private TimeScheduler scheduler;
  +    private UsersRepository users;
       private MailServer mailServer;
  +    private James parentJames;
   
  -    private String softwaretype = "JAMES SMTP Server " + Constants.SOFTWARE_VERSION;
  +    private String softwaretype = "JAMES SMTP Server "
  +                                   + Constants.SOFTWARE_VERSION;
       private static long count;
       private Hashtable state     = new Hashtable();
       private Random random       = new Random();
   
  +    public void configure ( Configuration configuration )
  +           throws ConfigurationException {
  +        super.configure(configuration);
  +        authRequired
  +           = configuration.getChild("authRequired").getValueAsBoolean(false);
  +        verifyIdentity
  +           = configuration.getChild("verifyIdentity").getValueAsBoolean(false);
  +    }
  +
       public void compose( final ComponentManager componentManager )
           throws ComponentException {
  -        mailServer = (MailServer)componentManager.lookup("org.apache.james.services.MailServer");
  -        scheduler = (TimeScheduler)componentManager.
  -            lookup("org.apache.avalon.cornerstone.services.scheduler.TimeScheduler");
  +        mailServer = (MailServer)componentManager.lookup(
  +                                 "org.apache.james.services.MailServer");
  +        parentJames = (James)componentManager.lookup(
  +                             "org.apache.james.services.MailServer");
  +        scheduler = (TimeScheduler)componentManager.lookup(
  +            "org.apache.avalon.cornerstone.services.scheduler.TimeScheduler");
  +        UsersStore usersStore = (UsersStore)componentManager.lookup(
  +            "org.apache.james.services.UsersStore" );
  +        users = usersStore.getRepository("LocalUsers");   
       }
   
       /**
  @@ -108,19 +135,25 @@
               state.put(REMOTE_IP, remoteIP);
               state.put(SMTP_ID, smtpID);
           } catch (Exception e) {
  -            getLogger().error("Cannot open connection from " + remoteHost + " (" + remoteIP + "): " + e.getMessage(), e );
  -            throw new RuntimeException("Cannot open connection from " + remoteHost + " (" + remoteIP + "): " + e.getMessage());
  +            getLogger().error("Cannot open connection from " + remoteHost
  +                              + " (" + remoteIP + "): " + e.getMessage(), e );
  +            throw new RuntimeException("Cannot open connection from "
  +                      + remoteHost + " (" + remoteIP + "): " + e.getMessage());
           }
   
  -        getLogger().info("Connection from " + remoteHost + " (" + remoteIP + ")");
  +        getLogger().info("Connection from " + remoteHost + " ("
  +                         + remoteIP + ")");
   
           try {
               // Initially greet the connector
               // Format is:  Sat,  24 Jan 1998 13:16:09 -0500
   
  -            final PeriodicTimeTrigger trigger = new PeriodicTimeTrigger( timeout, -1 );
  +            final PeriodicTimeTrigger trigger
  +                  = new PeriodicTimeTrigger( timeout, -1 );
               scheduler.addTrigger( this.toString(), trigger, this );
  -            out.println("220 " + this.helloName + " SMTP Server (" + softwaretype + ") ready " + RFC822DateFormat.toString(new Date()));
  +            out.println("220 " + this.helloName + " SMTP Server ("
  +                        + softwaretype + ") ready "
  +                        + RFC822DateFormat.toString(new Date()));
   
               while  (parseCommand(in.readLine())) {
                   scheduler.resetTrigger(this.toString());
  @@ -128,19 +161,22 @@
               socket.close();
               scheduler.removeTrigger(this.toString());
           } catch (SocketException se) {
  -            getLogger().debug("Socket to " + remoteHost + " closed remotely.", se );
  +            getLogger().debug("Socket to " + remoteHost
  +                              + " closed remotely.", se );
           } catch ( InterruptedIOException iioe ) {
               getLogger().debug( "Socket to " + remoteHost + " timeout.", iioe );
           } catch ( IOException ioe ) {
  -            getLogger().debug( "Exception handling socket to " + remoteHost + ":"
  -                               + ioe.getMessage(), ioe );
  +            getLogger().debug( "Exception handling socket to " + remoteHost
  +                               + ":" + ioe.getMessage(), ioe );
           } catch (Exception e) {
  -            getLogger().debug( "Exception opening socket: " + e.getMessage(), e );
  +            getLogger().debug( "Exception opening socket: "
  +                               + e.getMessage(), e );
           } finally {
               try {
                   socket.close();
               } catch (IOException e) {
  -                getLogger().error("Exception closing socket: " + e.getMessage());
  +                getLogger().error("Exception closing socket: "
  +                                  + e.getMessage());
               }
           }
       }
  @@ -168,7 +204,8 @@
   
           if (command == null) return false;
           getLogger().info("Command received: " + command);
  -        StringTokenizer commandLine = new StringTokenizer(command.trim(), " :");
  +        StringTokenizer commandLine
  +            = new StringTokenizer(command.trim(), " :");
           int arguments = commandLine.countTokens();
           if (arguments == 0) {
               return true;
  @@ -188,6 +225,8 @@
               doHELO(command,argument,argument1);
           else if (command.equalsIgnoreCase("EHLO"))
               doEHLO(command,argument,argument1);
  +        else if (command.equalsIgnoreCase("AUTH"))
  +            doAUTH(command,argument,argument1);        
           else if (command.equalsIgnoreCase("MAIL"))
               doMAIL(command,argument,argument1);
           else if (command.equalsIgnoreCase("RCPT"))
  @@ -207,20 +246,83 @@
   
       private void doHELO(String command,String argument,String argument1) {
           if (state.containsKey(CURRENT_HELO_MODE)) {
  -            out.println("250 " + state.get(SERVER_NAME) + " Duplicate HELO/EHLO");
  +            out.println("250 " + state.get(SERVER_NAME)
  +                        + " Duplicate HELO/EHLO");
           } else if (argument == null) {
               out.println("501 domain address required: " + command);
           } else {
               state.put(CURRENT_HELO_MODE, command);
               state.put(NAME_GIVEN, argument);
  -            out.println("250 " + state.get(SERVER_NAME) + " Hello " + argument +
  -                        " (" + state.get(REMOTE_NAME) +
  -                        " [" + state.get(REMOTE_IP) + "])");
  +            out.println(((authRequired) ? "250-AUTH LOGIN PLAIN\r\n" : "")
  +                        + "250 " + state.get(SERVER_NAME) + " Hello "
  +                        + argument + " (" + state.get(REMOTE_NAME)
  +                        + " [" + state.get(REMOTE_IP) + "])");
           }
       }
       private void doEHLO(String command,String argument,String argument1) {
           doHELO(command,argument,argument1);
       }
  +
  +    private void doAUTH(String command,String argument,String argument1)
  +            throws Exception {
  +        if (state.containsKey(AUTH)) {
  +            out.println("503 User has previously authenticated." 
  +                        + " Further authentication is not required!");
  +            return;        
  +        } else if (argument == null) {
  +            out.println("501 Usage: AUTH (authentication type) <challenge>");
  +            return;        
  +        } else if (argument.equalsIgnoreCase("PLAIN")) {
  +            String userpass, user, pass;
  +            StringTokenizer authTokenizer;
  +            if (argument1 == null) {
  +                out.println("334 OK. Continue authentication");
  +                userpass = in.readLine().trim();
  +            } else
  +                userpass = argument1.trim();
  +            authTokenizer = new StringTokenizer(
  +                              Base64.decode(userpass).readLine().trim(), "\0");
  +            user = authTokenizer.nextToken();
  +            pass = authTokenizer.nextToken();
  +            // Authenticate user
  +            if (users.test(user, pass)) {
  +                state.put(AUTH, user);
  +                out.println("235 Authentication Successful");
  +                getLogger().info("AUTH method PLAIN succeeded");
  +            } else {                
  +                out.println("535 Authentication Failed");
  +                getLogger().error("AUTH method PLAIN failed");
  +            }
  +            return;
  +        } else if (argument.equalsIgnoreCase("LOGIN")) {
  +            String user, pass;
  +
  +            if (argument1 == null) {
  +                out.println("334 VXNlcm5hbWU6"); // base64 encoded "Username:" 
  +                user = in.readLine().trim();
  +            } else
  +                user = argument1.trim();
  +            user = Base64.decode(user).readLine().trim();
  +            out.println("334 UGFzc3dvcmQ6"); // base64 encoded "Password:" 
  +            pass = Base64.decode(in.readLine().trim()).readLine().trim();
  +            //Authenticate user
  +            if (users.test(user, pass)) {
  +                state.put(AUTH, user);
  +                out.println("235 Authentication Successful");
  +                getLogger().info("AUTH method LOGIN succeeded");
  +            } else {                
  +                out.println("535 Authentication Failed");
  +                getLogger().error("AUTH method LOGIN failed");
  +            }
  +            return;
  +        } else {
  +            out.println("504 Unrecognized Authentication Type");
  +            getLogger().error("AUTH method " + argument
  +                              + " is an unrecognized authentication type");
  +            return;
  +        }
  +    }
  +
       private void doMAIL(String command,String argument,String argument1) {
           if (state.containsKey(SENDER)) {
               out.println("503 Sender already specified");
  @@ -254,7 +356,8 @@
       private void doRCPT(String command,String argument,String argument1) {
           if (!state.containsKey(SENDER)) {
               out.println("503 Need MAIL before RCPT");
  -        } else if (argument == null || !argument.equalsIgnoreCase("TO") || argument1 == null) {
  +        } else if (argument == null || !argument.equalsIgnoreCase("TO")
  +                   || argument1 == null) {
               out.println("501 Usage: RCPT TO:<recipient>");
           } else {
               Collection rcptColl = (Collection) state.get(RCPT_VECTOR);
  @@ -280,6 +383,46 @@
                                     + recipient + ": " + pe.getMessage());
                   return;
               }
  +            if (authRequired) {
  +                // Make sure the mail is being sent locally if not
  +                // authenticated else reject
  +                if (!state.containsKey(AUTH)) {
  +                    String toDomain
  +                         = recipient.substring(recipient.indexOf('@') + 1);
  +                    
  +                    if (!parentJames.isLocalServer(toDomain)) {
  +                        out.println("530 Authentication Required");
  +                        getLogger().error(
  +                            "Authentication is required for mail request");
  +                        return;
  +                    }
  +                } else {                    
  +                    // Identity verification checking
  +                    if (verifyIdentity) {
  +                      String authUser = (String)state.get(AUTH);                                
  +                      MailAddress senderAddress
  +                          = (MailAddress)state.get(SENDER);
  +                      boolean domainExists = false;
  +
  +                      if (!authUser.equalsIgnoreCase(
  +                                    senderAddress.getUser())) {
  +                        out.println("503 Incorrect Authentication for Specified Email Address");
  +                        getLogger().error("User " + authUser
  +                            + " authenticated, however tried sending email as "
  +                            + senderAddress);
  +                        return;
  +                      }                        
  +                      if (!parentJames.isLocalServer(
  +                                       senderAddress.getHost())) {
  +                        out.println("503 Incorrect Authentication for Specified Email Address");
  +                        getLogger().error("User " + authUser
  +                            + " authenticated, however tried sending email as "
  +                            + senderAddress);
  +                            return;
  +                        }                                                        
  +                    }
  +                }
  +            }
               rcptColl.add(recipientAddress);
               state.put(RCPT_VECTOR, rcptColl);
               out.println("250 Recipient <" + recipient + "> OK");
  @@ -302,44 +445,48 @@
               out.println("354 Ok Send data ending with <CRLF>.<CRLF>");
               try {
                   // parse headers
  -                InputStream msgIn = new CharTerminatedInputStream(in, SMTPTerminator);
  +                InputStream msgIn
  +                    = new CharTerminatedInputStream(in, SMTPTerminator);
                   MailHeaders headers = new MailHeaders(msgIn);
  -                // if headers do not contains minimum REQUIRED headers fields add them
  +                // if headers do not contains minimum REQUIRED headers fields
  +		// add them
                   if (!headers.isSet("Date")) {
  -                    headers.setHeader("Date", RFC822DateFormat.toString (new Date ()));
  +                    headers.setHeader("Date",
  +                                      RFC822DateFormat.toString(new Date ()));
                   }
  -                /*
  -                  We no longer add To as this in practice is not set (from what I've seen)
  -                  if (!headers.isSet("To")) {
  -                  headers.setHeader("To", );
  -                  }
  -                */
  +
                   if (!headers.isSet("From")) {
                       headers.setHeader("From", state.get(SENDER).toString());
                   }
   
  -                String received = "from " + state.get(REMOTE_NAME) + " ([" + state.get(REMOTE_IP)
  +                String received = "from " + state.get(REMOTE_NAME) + " (["
  +                    + state.get(REMOTE_IP)
                       + "])\r\n          by " + this.helloName + " ("
                       + softwaretype + ") with SMTP ID " + state.get(SMTP_ID);
                   if (((Collection)state.get(RCPT_VECTOR)).size () == 1) {
                       //Only indicate a recipient if they're the only recipient
  -                    //(prevents email address harvesting and large headers in bulk email)
  +                    //(prevents email address harvesting and large headers in
  +                    // bulk email)
                       received += "\r\n          for <"
  -                        + ((Vector)state.get(RCPT_VECTOR)).elementAt(0).toString() + ">";
  +                     + ((Vector)state.get(RCPT_VECTOR)).elementAt(0).toString()
  +                     + ">";
                   }
  -                received += ";\r\n          " + RFC822DateFormat.toString (new Date ());
  +                received += ";\r\n          "
  +                         + RFC822DateFormat.toString (new Date ());
                   headers.addHeader ("Received", received);
   
  -                // headers.setReceivedStamp("Unknown", (String) helloName.elementAt(0));
  -                ByteArrayInputStream headersIn = new ByteArrayInputStream(headers.toByteArray());
  -                MailImpl mail = new MailImpl(mailServer.getId(), (MailAddress)state.get(SENDER),
  -                                             (Vector)state.get(RCPT_VECTOR),
  -                                             new SequenceInputStream(headersIn, msgIn));
  +                ByteArrayInputStream headersIn
  +                    = new ByteArrayInputStream(headers.toByteArray());
  +                MailImpl mail = new MailImpl(mailServer.getId(),
  +                                    (MailAddress)state.get(SENDER),
  +                                    (Vector)state.get(RCPT_VECTOR),
  +                                    new SequenceInputStream(headersIn, msgIn));
                   mail.setRemoteHost((String)state.get(REMOTE_NAME));
                   mail.setRemoteAddr((String)state.get(REMOTE_IP));
                   mailServer.sendMail(mail);
               } catch (MessagingException me) {
  -                out.println("451 Error processing message: " + me.getMessage());
  +                out.println("451 Error processing message: "
  +                            + me.getMessage());
                   getLogger().error("Error processing message: "
                                     + me.getMessage());
                   return;
  @@ -350,7 +497,8 @@
           }
       }
       private void doQUIT(String command,String argument,String argument1) {
  -        out.println("221 " + state.get(SERVER_NAME) + " Service closing transmission channel");
  +        out.println("221 " + state.get(SERVER_NAME)
  +                    + " Service closing transmission channel");
       }
   
       private void doUnknownCmd(String command,String argument,String argument1) {
  
  
  
  1.1                  jakarta-james/src/java/org/apache/james/util/Base64.java
  
  Index: Base64.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.util;
  
  import java.io.*;
  import javax.mail.internet.*;
  
  /**
   * Simple Base64 string decoding function
   * @author Jason Borden <jb...@javasense.com>
   *
   * This is $Revision: 1.1 $
   * Committed on $Date: 2001/06/14 13:05:03 $ by: $Author: charlesb $ 
   */
  
  public class Base64 {
  
      public static BufferedReader decode(String b64string) throws Exception {
          return new BufferedReader(
                     new InputStreamReader(
                         MimeUtility.decode(
                              new ByteArrayInputStream(
                                  b64string.getBytes()), "base64")));
      }
  }
  
  
  

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