commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From s...@apache.org
Subject svn commit: r1084625 - in /commons/proper/net/trunk/src: changes/ main/java/examples/mail/ main/java/org/apache/commons/net/imap/
Date Wed, 23 Mar 2011 16:21:39 GMT
Author: sebb
Date: Wed Mar 23 16:21:38 2011
New Revision: 1084625

URL: http://svn.apache.org/viewvc?rev=1084625&view=rev
Log:
NET-333 would you provide a class used for imap protocol?

Added:
    commons/proper/net/trunk/src/main/java/examples/mail/IMAPMail.java   (with props)
    commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/
    commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/AuthenticatingIMAPClient.java   (with props)
    commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAP.java   (with props)
    commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAPClient.java   (with props)
    commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAPCommand.java   (with props)
    commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAPReply.java   (with props)
    commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAPSClient.java   (with props)
Modified:
    commons/proper/net/trunk/src/changes/changes.xml

Modified: commons/proper/net/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/net/trunk/src/changes/changes.xml?rev=1084625&r1=1084624&r2=1084625&view=diff
==============================================================================
--- commons/proper/net/trunk/src/changes/changes.xml (original)
+++ commons/proper/net/trunk/src/changes/changes.xml Wed Mar 23 16:21:38 2011
@@ -57,6 +57,9 @@ The <action> type attribute can be add,u
 
     <body>
         <release version="3.0" date="TBA" description="TBA">
+            <action issue="NET-333" dev="sebb" type="add" due-to="Bogdan Drozdowski" due-to-email="bogdandr # op . pl">
+            would you provide a class used for imap protocol?
+            </action>
             <action issue="NET-390" dev="sebb" type="update">
             FTPFile.toString() should return formatted version of its fields, not the unformatted original
             </action>

Added: commons/proper/net/trunk/src/main/java/examples/mail/IMAPMail.java
URL: http://svn.apache.org/viewvc/commons/proper/net/trunk/src/main/java/examples/mail/IMAPMail.java?rev=1084625&view=auto
==============================================================================
--- commons/proper/net/trunk/src/main/java/examples/mail/IMAPMail.java (added)
+++ commons/proper/net/trunk/src/main/java/examples/mail/IMAPMail.java Wed Mar 23 16:21:38 2011
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package examples.mail;
+
+import java.io.IOException;
+
+import org.apache.commons.net.imap.IMAPClient;
+import org.apache.commons.net.imap.IMAPSClient;
+
+/**
+ * This is an example program demonstrating how to use the IMAP[S]Client class.
+ * This program connects to a IMAP[S] server, lists its capabilities and shows
+ * the status of the inbox.
+ * <p>
+ * Usage: IMAPMail <imap[s] server hostname> <username> <password> [secure protocol, e.g. TLS]
+ * <p>
+ */
+public final class IMAPMail
+{
+
+    public static final void main(String[] args)
+    {
+        if (args.length < 3)
+        {
+            System.err.println(
+                "Usage: IMAPMail <imap server hostname> <username> <password> [TLS]");
+            System.exit(1);
+        }
+
+        String server = args[0];
+        String username = args[1];
+        String password = args[2];
+
+        String proto = (args.length > 3) ? args[3] : null;
+
+        IMAPClient imap;
+
+        if (proto != null) {
+            System.out.println("Using secure protocol: " + proto);
+            imap = new IMAPSClient(proto, true); // implicit
+        } else {
+            imap = new IMAPClient();
+        }
+        System.out.println("Connecting to server " + server + " on " + imap.getDefaultPort());
+
+        // We want to timeout if a response takes longer than 60 seconds
+        imap.setDefaultTimeout(60000);
+
+        try
+        {
+            imap.connect(server);
+        }
+        catch (IOException e)
+        {
+            System.err.println("Could not connect to server.");
+            e.printStackTrace();
+            System.exit(2);
+        }
+
+        try
+        {
+            if (!imap.login(username, password))
+            {
+                System.err.println("Could not login to server. Check password.");
+                imap.disconnect();
+                System.exit(3);
+            }
+
+            if (imap.capability())
+            {
+                System.out.println("Server capabilities:");
+                System.out.println(imap.getReplyString());
+            }
+
+            if (imap.select("inbox"))
+            {
+                System.out.println("Selected inbox:");
+                System.out.println(imap.getReplyString());
+            }
+
+            if (imap.examine("inbox"))
+            {
+                System.out.println("Examined inbox:");
+                System.out.println(imap.getReplyString());
+            }
+
+            if (imap.status("inbox", null))
+            {
+                System.out.println("Inbox status:");
+                System.out.println(imap.getReplyString());
+            }
+
+            imap.logout();
+            imap.disconnect();
+        }
+        catch (IOException e)
+        {
+            e.printStackTrace();
+            System.exit(10);
+            return;
+        }
+    }
+}
+
+/* kate: indent-width 4; replace-tabs on; */

Propchange: commons/proper/net/trunk/src/main/java/examples/mail/IMAPMail.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/net/trunk/src/main/java/examples/mail/IMAPMail.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/AuthenticatingIMAPClient.java
URL: http://svn.apache.org/viewvc/commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/AuthenticatingIMAPClient.java?rev=1084625&view=auto
==============================================================================
--- commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/AuthenticatingIMAPClient.java (added)
+++ commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/AuthenticatingIMAPClient.java Wed Mar 23 16:21:38 2011
@@ -0,0 +1,251 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.net.imap;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.InvalidKeySpecException;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import javax.net.ssl.SSLContext;
+import org.apache.commons.net.util.Base64;
+
+/**
+ * An IMAP Client class with authentication support.
+ * @see IMAPClient
+ */
+public class AuthenticatingIMAPClient extends IMAPSClient
+{
+    /**
+     * Constructor for AuthenticatingIMAPClient that delegates to IMAPSClient.
+     * Sets security mode to explicit (isImplicit = false).
+     */
+    public AuthenticatingIMAPClient()
+    {
+        this(DEFAULT_PROTOCOL, false);
+    }
+
+    /**
+     * Constructor for AuthenticatingIMAPClient that delegates to IMAPSClient.
+     * @param implicit The security mode (Implicit/Explicit).
+     */
+    public AuthenticatingIMAPClient(boolean implicit)
+    {
+        this(DEFAULT_PROTOCOL, implicit);
+    }
+
+    /**
+     * Constructor for AuthenticatingIMAPClient that delegates to IMAPSClient.
+     * @param proto the protocol.
+     */
+    public AuthenticatingIMAPClient(String proto)
+    {
+        this(proto, false);
+    }
+
+    /**
+     * Constructor for AuthenticatingIMAPClient that delegates to IMAPSClient.
+     * @param proto the protocol.
+     * @param implicit The security mode(Implicit/Explicit).
+     */
+    public AuthenticatingIMAPClient(String proto, boolean implicit)
+    {
+        this(proto, implicit, null);
+    }
+
+    /**
+     * Constructor for AuthenticatingIMAPClient that delegates to IMAPSClient.
+     * @param proto the protocol.
+     * @param implicit The security mode(Implicit/Explicit).
+     */
+    public AuthenticatingIMAPClient(String proto, boolean implicit, SSLContext ctx)
+    {
+        super(proto, implicit, ctx);
+    }
+
+    /**
+     * Constructor for AuthenticatingIMAPClient that delegates to IMAPSClient.
+     * @param implicit The security mode(Implicit/Explicit).
+     * @param ctx A pre-configured SSL Context.
+     */
+    public AuthenticatingIMAPClient(boolean implicit, SSLContext ctx)
+    {
+        this(DEFAULT_PROTOCOL, implicit, ctx);
+    }
+
+    /**
+     * Constructor for AuthenticatingIMAPClient that delegates to IMAPSClient.
+     * @param context A pre-configured SSL Context.
+     */
+    public AuthenticatingIMAPClient(SSLContext context)
+    {
+        this(false, context);
+    }
+
+    /**
+     * Authenticate to the IMAP server by sending the AUTHENTICATE command with the
+     * selected mechanism, using the given username and the given password.
+     * <p>
+     * @return True if successfully completed, false if not.
+     * @exception IOException  If an I/O error occurs while either sending a
+     *      command to the server or receiving a reply from the server.
+     * @exception NoSuchAlgorithmException If the CRAM hash algorithm
+     *      cannot be instantiated by the Java runtime system.
+     * @exception InvalidKeyException If the CRAM hash algorithm
+     *      failed to use the given password.
+     * @exception InvalidKeySpecException If the CRAM hash algorithm
+     *      failed to use the given password.
+     */
+    public boolean authenticate(AuthenticatingIMAPClient.AUTH_METHOD method,
+                        String username, String password)
+                        throws IOException, NoSuchAlgorithmException,
+                        InvalidKeyException, InvalidKeySpecException
+    {
+        return auth(method, username, password);
+    }
+
+    /**
+     * Authenticate to the IMAP server by sending the AUTHENTICATE command with the
+     * selected mechanism, using the given username and the given password.
+     * <p>
+     * @return True if successfully completed, false if not.
+     * @exception IOException  If an I/O error occurs while either sending a
+     *      command to the server or receiving a reply from the server.
+     * @exception NoSuchAlgorithmException If the CRAM hash algorithm
+     *      cannot be instantiated by the Java runtime system.
+     * @exception InvalidKeyException If the CRAM hash algorithm
+     *      failed to use the given password.
+     * @exception InvalidKeySpecException If the CRAM hash algorithm
+     *      failed to use the given password.
+     */
+    public boolean auth(AuthenticatingIMAPClient.AUTH_METHOD method,
+                        String username, String password)
+                        throws IOException, NoSuchAlgorithmException,
+                        InvalidKeyException, InvalidKeySpecException
+    {
+        if (sendCommand(IMAPCommand.getCommand(IMAPCommand.AUTHENTICATE)
+                + " " + AUTH_METHOD.getAuthName(method))
+            != IMAPReply.CONT)
+	{
+            return false;
+	}
+
+        if (method.equals(AUTH_METHOD.PLAIN))
+        {
+            // the server sends an empty response ("+ "), so we don't have to read it.
+            int result = sendUntaggedCommand(
+                new String(
+                    Base64.encodeBase64(("\000" + username + "\000" + password).getBytes())
+                    )
+                );
+            if (result == IMAPReply.OK)
+            {
+                setState(IMAP.IMAPState.AUTH_STATE);
+            }
+            return result == IMAPReply.OK;
+        }
+        else if (method.equals(AUTH_METHOD.CRAM_MD5))
+        {
+            // get the CRAM challenge (after "+ ")
+            byte[] serverChallenge = Base64.decodeBase64(getReplyString().substring(2).trim());
+            // get the Mac instance
+            Mac hmac_md5 = Mac.getInstance("HmacMD5");
+            hmac_md5.init(new SecretKeySpec(password.getBytes(), "HmacMD5"));
+            // compute the result:
+            byte[] hmacResult = _convertToHexString(hmac_md5.doFinal(serverChallenge)).getBytes();
+            // join the byte arrays to form the reply
+            byte[] usernameBytes = username.getBytes();
+            byte[] toEncode = new byte[usernameBytes.length + 1 /* the space */ + hmacResult.length];
+            System.arraycopy(usernameBytes, 0, toEncode, 0, usernameBytes.length);
+            toEncode[usernameBytes.length] = ' ';
+            System.arraycopy(hmacResult, 0, toEncode, usernameBytes.length + 1, hmacResult.length);
+            // send the reply and read the server code:
+            int result = sendUntaggedCommand(new String(Base64.encodeBase64(toEncode)));
+            if (result == IMAPReply.OK)
+            {
+                setState(IMAP.IMAPState.AUTH_STATE);
+            }
+            return result == IMAPReply.OK;
+        }
+        else if (method.equals(AUTH_METHOD.LOGIN))
+        {
+            // the server sends fixed responses (base64("Username") and
+            // base64("Password")), so we don't have to read them.
+            if (sendUntaggedCommand(
+                new String(Base64.encodeBase64(username.getBytes()))) != IMAPReply.CONT)
+            {
+                return false;
+            }
+            int result = sendUntaggedCommand(
+                new String(Base64.encodeBase64(password.getBytes())));
+            if (result == IMAPReply.OK)
+            {
+                setState(IMAP.IMAPState.AUTH_STATE);
+            }
+            return result == IMAPReply.OK;
+        }
+        else return false; // safety check
+    }
+
+    /**
+     * Converts the given byte array to a String containing the hex values of the bytes.
+     * For example, the byte 'A' will be converted to '41', because this is the ASCII code
+     * (and the byte value) of the capital letter 'A'.
+     * @param a The byte array to convert.
+     * @return The resulting String of hex codes.
+     */
+    private String _convertToHexString(byte[] a)
+    {
+        StringBuilder result = new StringBuilder(a.length*2);
+        for (int i = 0; i < a.length; i++)
+        {
+            if ( (a[i] & 0x0FF) <= 15 ) result.append("0");
+            result.append(Integer.toHexString(a[i] & 0x0FF));
+        }
+        return result.toString();
+    }
+
+    /**
+     * The enumeration of currently-supported authentication methods.
+     */
+    public static enum AUTH_METHOD
+    {
+        /** The standarised (RFC4616) PLAIN method, which sends the password unencrypted (insecure). */
+        PLAIN,
+        /** The standarised (RFC2195) CRAM-MD5 method, which doesn't send the password (secure). */
+        CRAM_MD5,
+        /** The unstandarised Microsoft LOGIN method, which sends the password unencrypted (insecure). */
+        LOGIN;
+
+        /**
+         * Gets the name of the given authentication method suitable for the server.
+         * @param method The authentication method to get the name for.
+         * @return The name of the given authentication method suitable for the server.
+         */
+        public static final String getAuthName(AUTH_METHOD method)
+        {
+            if (method.equals(AUTH_METHOD.PLAIN)) return "PLAIN";
+            else if (method.equals(AUTH_METHOD.CRAM_MD5)) return "CRAM-MD5";
+            else if (method.equals(AUTH_METHOD.LOGIN)) return "LOGIN";
+            else return null;
+        }
+    }
+}
+/* kate: indent-width 4; replace-tabs on; */

Propchange: commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/AuthenticatingIMAPClient.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/AuthenticatingIMAPClient.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAP.java
URL: http://svn.apache.org/viewvc/commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAP.java?rev=1084625&view=auto
==============================================================================
--- commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAP.java (added)
+++ commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAP.java Wed Mar 23 16:21:38 2011
@@ -0,0 +1,514 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.net.imap;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.EOFException;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.apache.commons.net.MalformedServerReplyException;
+import org.apache.commons.net.ProtocolCommandListener;
+import org.apache.commons.net.ProtocolCommandSupport;
+import org.apache.commons.net.SocketClient;
+
+
+/**
+ * The IMAP class provides the basic the functionality necessary to implement your
+ * own IMAP client.
+ */
+public class IMAP extends SocketClient
+{
+    /** The default IMAP port (RFC 3501). */
+    public static final int DEFAULT_PORT = 143;
+
+    public enum IMAPState
+    {
+        /** A constant representing the state where the client is not yet connected to a server. */
+        DISCONNECTED_STATE,
+        /**  A constant representing the initial state. */
+        INITIAL_STATE,
+        /**  A constant representing the "not authenticated" state. */
+        NOT_AUTH_STATE,
+        /**  A constant representing the "authenticated" state. */
+        AUTH_STATE,
+        /**  A constant representing the "logout" state. */
+        LOGOUT_STATE;
+    }
+
+    // RFC 3501, section 5.1.3. It should be "modified UTF-7".
+    /**
+     * The default control socket ecoding.
+     */
+    protected static final String __DEFAULT_ENCODING = "ISO-8859-1";
+
+    private IMAPState __state;
+    protected BufferedWriter __writer;
+    private StringBuffer __commandBuffer;
+
+    protected BufferedReader _reader;
+    private int _replyCode;
+    private Vector<String> _replyLines;
+
+    private char[] _initialID = { 'A', 'A', 'A', 'A' };
+
+    /**
+     * A ProtocolCommandSupport object used to manage the registering of
+     * ProtocolCommandListeners and te firing of ProtocolCommandEvents.
+     */
+    protected ProtocolCommandSupport _commandSupport_;
+
+    /**
+     * The default IMAPClient constructor.  Initializes the state
+     * to <code>DISCONNECTED_STATE</code>.
+     */
+    public IMAP()
+    {
+        setDefaultPort(DEFAULT_PORT);
+        __commandBuffer = new StringBuffer();
+        __state = IMAPState.DISCONNECTED_STATE;
+        _reader = null;
+        __writer = null;
+        _replyLines = new Vector<String>();
+        _commandSupport_ = new ProtocolCommandSupport(this);
+    }
+
+    private void __getReply() throws IOException
+    {
+        String line;
+
+        _replyLines.setSize(0);
+        line = _reader.readLine();
+
+        if (line == null)
+            throw new EOFException("Connection closed without indication.");
+
+        _replyLines.add(line);
+
+        // Get extra lines if message continues.
+        if (line.charAt(0) == IMAPReply.OK_INT_String.charAt(0)
+            // can be untagged:
+            && ! line.substring(2).startsWith(IMAPReply.OK_String))
+        {
+            do
+            {
+                line = _reader.readLine();
+
+                if (line == null)
+                    throw new EOFException(
+                        "Connection closed without indication.");
+
+                _replyLines.add(line);
+
+                // The length() check handles problems that could arise from readLine()
+                // returning too soon after encountering a naked CR or some other
+                // anomaly.
+            }
+            while (line.charAt(0) == IMAPReply.OK_INT_String.charAt(0)
+                // can be untagged:
+                && ! line.substring(2).startsWith(IMAPReply.OK_String));
+        }
+
+        String _lastReplyLine = _replyLines.lastElement();
+        _lastReplyLine = _lastReplyLine.substring(_lastReplyLine.indexOf(' ')+1).toUpperCase();
+
+        // check the response code on the last line
+        if (_lastReplyLine.startsWith(IMAPReply.OK_String))
+        {
+            _replyCode = IMAPReply.OK;
+        }
+        else if (_lastReplyLine.startsWith(IMAPReply.NO_String))
+        {
+            _replyCode = IMAPReply.NO;
+        }
+        else if (_lastReplyLine.startsWith(IMAPReply.BAD_String))
+        {
+            _replyCode = IMAPReply.BAD;
+        }
+        // response code not found - read the last line's type
+        else if (line.startsWith(IMAPReply.OK_INT_String))
+        {
+            _replyCode = IMAPReply.OK_INT;
+        }
+        else if (line.startsWith(IMAPReply.CONT_String))
+        {
+            _replyCode = IMAPReply.CONT;
+        }
+        else
+        {
+            throw new
+            MalformedServerReplyException(
+                "Received invalid IMAP protocol response from server: '"
+                + getReplyString() + "'.");
+        }
+
+        if (_commandSupport_.getListenerCount() > 0)
+            _commandSupport_.fireReplyReceived(_replyCode, getReplyString());
+    }
+
+    /**
+     * Performs connection initialization and sets state to
+     * <code> AUTHORIZATION_STATE </code>.
+     */
+    @Override
+    protected void _connectAction_() throws IOException
+    {
+        super._connectAction_();
+        _reader =
+          new BufferedReader(new InputStreamReader(_input_,
+                                                   __DEFAULT_ENCODING));
+        __writer =
+          new BufferedWriter(new OutputStreamWriter(_output_,
+                                                    __DEFAULT_ENCODING));
+        setSoTimeout(connectTimeout); // TODO
+        System.out.println("Connected");
+        __getReply();
+        setState(IMAPState.NOT_AUTH_STATE);
+    }
+
+    /**
+     * Adds a ProtocolCommandListener.  Delegates this task to
+     * {@link #_commandSupport_  _commandSupport_ }.
+     * <p>
+     * @param listener  The ProtocolCommandListener to add.
+     */
+    public void addProtocolCommandListener(ProtocolCommandListener listener)
+    {
+        _commandSupport_.addProtocolCommandListener(listener);
+    }
+
+    /**
+     * Removes a ProtocolCommandListener.  Delegates this task to
+     * {@link #_commandSupport_  _commandSupport_ }.
+     * <p>
+     * @param listener  The ProtocolCommandListener to remove.
+     */
+    public void removeProtocolCommandistener(ProtocolCommandListener listener)
+    {
+        _commandSupport_.removeProtocolCommandListener(listener);
+    }
+
+
+    /**
+     * Sets IMAP client state.  This must be one of the
+     * <code>_STATE</code> constants.
+     * <p>
+     * @param state  The new state.
+     */
+    protected void setState(IMAP.IMAPState state)
+    {
+        __state = state;
+    }
+
+
+    /**
+     * Returns the current IMAP client state.
+     * <p>
+     * @return The current IMAP client state.
+     */
+    public IMAP.IMAPState getState()
+    {
+        return __state;
+    }
+
+
+    /**
+     * Retrieves the additional lines of a multi-line server reply.
+     */
+    public void getAdditionalReply() throws IOException
+    {
+        String line;
+
+        line = _reader.readLine();
+        while (line != null)
+        {
+            _replyLines.addElement(line);
+            if (line.equals("."))
+                break;
+            line = _reader.readLine();
+        }
+    }
+
+
+    /**
+     * Disconnects the client from the server, and sets the state to
+     * <code> DISCONNECTED_STATE </code>.  The reply text information
+     * from the last issued command is voided to allow garbage collection
+     * of the memory used to store that information.
+     * <p>
+     * @exception IOException  If there is an error in disconnecting.
+     */
+    @Override
+    public void disconnect() throws IOException
+    {
+        super.disconnect();
+        _reader = null;
+        __writer = null;
+        _replyLines.setSize(0);
+        setState(IMAPState.DISCONNECTED_STATE);
+    }
+
+
+    /**
+     * Sends a command an arguments to the server and returns the reply code.
+     * <p>
+     * @param commandID The ID (tag) of the command.
+     * @param command  The IMAP command to send.
+     * @param args     The command arguments.
+     * @return  The server reply code (either IMAPReply.OK, IMAPReply.NO or IMAPReply.BAD).
+     */
+    public int sendCommandWithID(String commandID, String command, String args) throws IOException
+    {
+        String message;
+
+        __commandBuffer.setLength(0);
+        if (commandID != null)
+        {
+            __commandBuffer.append(commandID);
+            __commandBuffer.append(' ');
+        }
+        __commandBuffer.append(command);
+
+        if (args != null)
+        {
+            __commandBuffer.append(' ');
+            __commandBuffer.append(args);
+        }
+        __commandBuffer.append(SocketClient.NETASCII_EOL);
+
+        __writer.write(message = __commandBuffer.toString());
+        __writer.flush();
+
+        if (_commandSupport_.getListenerCount() > 0)
+            _commandSupport_.fireCommandSent(command, message);
+
+        __getReply();
+        return _replyCode;
+    }
+
+    /**
+     * Sends a command with no arguments to the server and returns the
+     * reply code.
+     * <p>
+     * @param commandID The ID (tag) of the command.
+     * @param command  The IMAP command to send.
+     * @return  The server reply code (see IMAPReply).
+     */
+    public int sendCommandWithID(String commandID, String command) throws IOException
+    {
+        return sendCommandWithID(commandID, command, null);
+    }
+
+    /**
+     * Sends a command an arguments to the server and returns the reply code.
+     * <p>
+     * @param commandID The ID (tag) of the command.
+     * @param command  The IMAP command to send
+     *                  (one of the IMAPCommand constants).
+     * @param args     The command arguments.
+     * @return  The server reply code (see IMAPReply).
+     */
+    public int sendCommandWithID(String commandID, int command, String args) throws IOException
+    {
+        return sendCommandWithID(commandID, IMAPCommand._commands[command], args);
+    }
+
+    /**
+     * Sends a command with no arguments to the server and returns the
+     * reply code.
+     * <p>
+     * @param commandID The ID (tag) of the command.
+     * @param command  The IMAP command to send
+     *                  (one of the IMAPCommand constants).
+     * @return  The server reply code (see IMAPReply).
+    **/
+    public int sendCommandWithID(String commandID, int command) throws IOException
+    {
+        return sendCommandWithID(commandID, IMAPCommand._commands[command], null);
+    }
+
+    /**
+     * Sends a command an arguments to the server and returns the reply code.
+     * <p>
+     * @param command  The IMAP command to send.
+     * @param args     The command arguments.
+     * @return  The server reply code (see IMAPReply).
+     */
+    public int sendCommand(String command, String args) throws IOException
+    {
+        return sendCommandWithID(generateCommandID(), command, args);
+    }
+
+    /**
+     * Sends a command with no arguments to the server and returns the
+     * reply code.
+     * <p>
+     * @param command  The IMAP command to send.
+     * @return  The server reply code (see IMAPReply).
+     */
+    public int sendCommand(String command) throws IOException
+    {
+        return sendCommandWithID(generateCommandID(), command, null);
+    }
+
+    /**
+     * Sends a command an arguments to the server and returns the reply code.
+     * <p>
+     * @param command  The IMAP command to send
+     *                  (one of the IMAPCommand constants).
+     * @param args     The command arguments.
+     * @return  The server reply code (see IMAPReply).
+     */
+    public int sendCommand(int command, String args) throws IOException
+    {
+        return sendCommandWithID(generateCommandID(), IMAPCommand._commands[command], args);
+    }
+
+    /**
+     * Sends a command with no arguments to the server and returns the
+     * reply code.
+     * <p>
+     * @param command  The IMAP command to send
+     *                  (one of the IMAPCommand constants).
+     * @return  The server reply code (see IMAPReply).
+    **/
+    public int sendCommand(int command) throws IOException
+    {
+        return sendCommandWithID(generateCommandID(), IMAPCommand._commands[command], null);
+    }
+
+    /**
+     * Sends an untagged command an arguments to the server and returns the reply code.
+     * <p>
+     * @param command  The IMAP command to send.
+     * @param args     The command arguments.
+     * @return  The server reply code (see IMAPReply).
+     */
+    public int sendUntaggedCommand(String command, String args) throws IOException
+    {
+        return sendCommandWithID(null, command, args);
+    }
+
+    /**
+     * Sends an untagged command with no arguments to the server and returns the
+     * reply code.
+     * <p>
+     * @param command  The IMAP command to send.
+     * @return  The server reply code (see IMAPReply).
+     */
+    public int sendUntaggedCommand(String command) throws IOException
+    {
+        return sendCommandWithID(null, command, null);
+    }
+
+    /**
+     * Sends an untagged command an arguments to the server and returns the reply code.
+     * <p>
+     * @param command  The IMAP command to send
+     *                  (one of the IMAPCommand constants).
+     * @param args     The command arguments.
+     * @return  The server reply code (see IMAPReply).
+     */
+    public int sendUntaggedCommand(int command, String args) throws IOException
+    {
+        return sendCommandWithID(null, IMAPCommand._commands[command], args);
+    }
+
+    /**
+     * Sends an untagged command with no arguments to the server and returns the
+     * reply code.
+     * <p>
+     * @param command  The IMAP command to send
+     *                  (one of the IMAPCommand constants).
+     * @return  The server reply code (see IMAPReply).
+    **/
+    public int sendUntaggedCommand(int command) throws IOException
+    {
+        return sendCommandWithID(null, IMAPCommand._commands[command], null);
+    }
+
+    /**
+     * Returns an array of lines received as a reply to the last command
+     * sent to the server.  The lines have end of lines truncated.
+     * @return The last server response.
+     */
+    public String[] getReplyStrings()
+    {
+        String[] lines;
+        lines = new String[_replyLines.size()];
+        _replyLines.copyInto(lines);
+        return lines;
+    }
+
+    /**
+     * Returns the reply to the last command sent to the server.
+     * The value is a single string containing all the reply lines including
+     * newlines.
+     * <p>
+     * @return The last server response.
+     */
+    public String getReplyString()
+    {
+        Enumeration<String> en;
+        StringBuilder buffer = new StringBuilder(256);
+
+        en = _replyLines.elements();
+        while (en.hasMoreElements())
+        {
+            buffer.append(en.nextElement());
+            buffer.append(SocketClient.NETASCII_EOL);
+        }
+
+        return buffer.toString();
+    }
+
+    /**
+     * Generates a new command ID (tag) for a command.
+     * @return a new command ID (tag) for an IMAP command.
+     */
+    protected String generateCommandID()
+    {
+        String res = new String (_initialID);
+        // "increase" the ID for the next call
+        boolean wasIncr = false;
+        for (int i = _initialID.length-1; i>=0; i--)
+        {
+            if (_initialID[i] >= 'Z')
+            {
+                _initialID[i] = 'A';
+                if ( i > 0 )
+                {
+                    _initialID[i-1]++;
+                    wasIncr = true;
+                }
+            }
+            else
+            {
+                if (! wasIncr) _initialID[i]++;
+                break;
+            }
+        }
+        return res;
+    }
+}
+
+/* kate: indent-width 4; replace-tabs on; */

Propchange: commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAP.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAP.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAPClient.java
URL: http://svn.apache.org/viewvc/commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAPClient.java?rev=1084625&view=auto
==============================================================================
--- commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAPClient.java (added)
+++ commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAPClient.java Wed Mar 23 16:21:38 2011
@@ -0,0 +1,613 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.net.imap;
+
+import java.io.IOException;
+
+/**
+ * The IMAPClient class provides the basic functionalities found in an
+ * IMAP client.
+ */
+public class IMAPClient extends IMAP
+{
+
+    // --------- commands available in all states
+
+    /**
+     * Send a CAPABILITY command to the server.
+     * @return True if the command was successful, false if not.
+     * @exception IOException If a network I/O error occurs in the process of
+     *            logging in.
+     */
+    public boolean capability() throws IOException
+    {
+        return sendCommand (IMAPCommand.getCommand(IMAPCommand.CAPABILITY))
+            == IMAPReply.OK;
+    }
+
+    /**
+     * Send a NOOP command to the server.  This is useful for keeping
+     * a connection alive since most IMAP servers will timeout after 10
+     * minutes of inactivity.
+     * @return True if the command was successful, false if not.
+     * @exception IOException If a network I/O error occurs in the process of
+     *            logging in.
+     */
+    public boolean noop() throws IOException
+    {
+        return sendCommand (IMAPCommand.getCommand(IMAPCommand.NOOP))
+            == IMAPReply.OK;
+    }
+
+    /**
+     * Send a LOGOUT command to the server.  To fully disconnect from the server
+     * you must call disconnect().
+     * A logout attempt is valid in any state.  If
+     * the client is in the not authenticated or authenticated state, it enters the
+     * logout on a successful logout.
+     * @return True if the command was successful, false if not.
+     * @exception IOException If a network I/O error occurs in the process of
+     *            logging in.
+     */
+    public boolean logout() throws IOException
+    {
+        return sendCommand (IMAPCommand.getCommand(IMAPCommand.LOGOUT))
+            == IMAPReply.OK;
+    }
+
+    // --------- commands available in the not-authenticated state
+    // STARTTLS skipped - see IMAPSClient.
+    // AUTHENTICATE skipped - see AuthenticatingIMAPClient.
+
+    /**
+     * Login to the IMAP server with the given username and password.  You
+     * must first connect to the server with
+     * {@link org.apache.commons.net.SocketClient#connect  connect }
+     * before attempting to login.  A login attempt is only valid if
+     * the client is in the NOT_AUTH_STATE.
+     * After logging in, the client enters the AUTH_STATE.
+     * <p>
+     * @param username  The account name being logged in to.
+     * @param password  The plain text password of the account.
+     * @return True if the login attempt was successful, false if not.
+     * @exception IOException If a network I/O error occurs in the process of
+     *            logging in.
+     */
+    public boolean login(String username, String password) throws IOException
+    {
+        if (getState() != IMAP.IMAPState.NOT_AUTH_STATE)
+        {
+            return false;
+        }
+
+        if (sendCommand(IMAPCommand.getCommand(IMAPCommand.LOGIN),
+            username + " " + password) != IMAPReply.OK)
+        {
+            return false;
+        }
+
+        setState(IMAP.IMAPState.AUTH_STATE);
+
+        return true;
+    }
+
+    // --------- commands available in the authenticated state
+
+    /**
+     * Send a SELECT command to the server.
+     * @param mailboxName The mailbox name to select.
+     * @return True if the command was successful, false if not.
+     * @exception IOException If a network I/O error occurs in the process of
+     *            logging in.
+     */
+    public boolean select(String mailboxName) throws IOException
+    {
+        return sendCommand (IMAPCommand.getCommand(IMAPCommand.SELECT),
+                            mailboxName)
+            == IMAPReply.OK;
+    }
+
+    /**
+     * Send an EXAMINE command to the server.
+     * @param mailboxName The mailbox name to examine.
+     * @return True if the command was successful, false if not.
+     * @exception IOException If a network I/O error occurs in the process of
+     *            logging in.
+     */
+    public boolean examine(String mailboxName) throws IOException
+    {
+        return sendCommand (IMAPCommand.getCommand(IMAPCommand.EXAMINE),
+                            mailboxName)
+            == IMAPReply.OK;
+    }
+
+    /**
+     * Send a CREATE command to the server.
+     * @param mailboxName The mailbox name to create.
+     * @return True if the command was successful, false if not.
+     * @exception IOException If a network I/O error occurs in the process of
+     *            logging in.
+     */
+    public boolean create(String mailboxName) throws IOException
+    {
+        return sendCommand (IMAPCommand.getCommand(IMAPCommand.CREATE),
+                            mailboxName)
+            == IMAPReply.OK;
+    }
+
+    /**
+     * Send a DELETE command to the server.
+     * @param mailboxName The mailbox name to delete.
+     * @return True if the command was successful, false if not.
+     * @exception IOException If a network I/O error occurs in the process of
+     *            logging in.
+     */
+    public boolean delete(String mailboxName) throws IOException
+    {
+        return sendCommand (IMAPCommand.getCommand(IMAPCommand.DELETE),
+                            mailboxName)
+            == IMAPReply.OK;
+    }
+
+    /**
+     * Send a RENAME command to the server.
+     * @param oldMailboxName The existing mailbox name to rename.
+     * @param newMailboxName The new mailbox name.
+     * @return True if the command was successful, false if not.
+     * @exception IOException If a network I/O error occurs in the process of
+     *            logging in.
+     */
+    public boolean rename(String oldMailboxName, String newMailboxName) throws IOException
+    {
+        return sendCommand (IMAPCommand.getCommand(IMAPCommand.RENAME),
+                            oldMailboxName + " " + newMailboxName)
+            == IMAPReply.OK;
+    }
+
+    /**
+     * Send a SUBSCRIBE command to the server.
+     * @param mailboxName The mailbox name to subscribe to.
+     * @return True if the command was successful, false if not.
+     * @exception IOException If a network I/O error occurs in the process of
+     *            logging in.
+     */
+    public boolean subscribe(String mailboxName) throws IOException
+    {
+        return sendCommand (IMAPCommand.getCommand(IMAPCommand.SUBSCRIBE),
+                            mailboxName)
+            == IMAPReply.OK;
+    }
+
+    /**
+     * Send a UNSUBSCRIBE command to the server.
+     * @param mailboxName The mailbox name to unsubscribe from.
+     * @return True if the command was successful, false if not.
+     * @exception IOException If a network I/O error occurs in the process of
+     *            logging in.
+     */
+    public boolean unsubscribe(String mailboxName) throws IOException
+    {
+        return sendCommand (IMAPCommand.getCommand(IMAPCommand.UNSUBSCRIBE),
+                            mailboxName)
+            == IMAPReply.OK;
+    }
+
+    /**
+     * Send a LIST command to the server.
+     * @param refName The reference name.
+     * @param mailboxName The mailbox name.
+     * @return True if the command was successful, false if not.
+     * @exception IOException If a network I/O error occurs in the process of
+     *            logging in.
+     */
+    public boolean list(String refName, String mailboxName) throws IOException
+    {
+        return sendCommand (IMAPCommand.getCommand(IMAPCommand.LIST),
+                            refName + " " + mailboxName)
+            == IMAPReply.OK;
+    }
+
+    /**
+     * Send an LSUB command to the server.
+     * @param refName The reference name.
+     * @param mailboxName The mailbox name.
+     * @return True if the command was successful, false if not.
+     * @exception IOException If a network I/O error occurs in the process of
+     *            logging in.
+     */
+    public boolean lsub(String refName, String mailboxName) throws IOException
+    {
+        return sendCommand (IMAPCommand.getCommand(IMAPCommand.LSUB),
+                            refName + " " + mailboxName)
+            == IMAPReply.OK;
+    }
+
+    /**
+     * Send a STATUS command to the server.
+     * @param mailboxName The reference name.
+     * @param itemNames The status data item names.
+     * @return True if the command was successful, false if not.
+     * @exception IOException If a network I/O error occurs in the process of
+     *            logging in.
+     */
+    public boolean status(String mailboxName, String[] itemNames) throws IOException
+    {
+        String statusNames = "";
+        if (itemNames != null)
+        {
+            statusNames += " (";
+            for ( int i = 0; i < itemNames.length; i++ )
+            {
+                statusNames += itemNames[i];
+                if (i < itemNames.length-1) statusNames += " ";
+            }
+            statusNames += ")";
+        }
+        return sendCommand (IMAPCommand.getCommand(IMAPCommand.STATUS),
+                            statusNames)
+            == IMAPReply.OK;
+    }
+
+    /**
+     * Send an APPEND command to the server.
+     * @param mailboxName The mailbox name.
+     * @param flags The flag parenthesized list (optional).
+     * @param datetime The date/time string (optional).
+     * @return True if the command was successful, false if not.
+     * @exception IOException If a network I/O error occurs in the process of
+     *            logging in.
+     */
+    public boolean append(String mailboxName, String flags, String datetime) throws IOException
+    {
+        String args = mailboxName;
+        if (flags != null) args += " " + flags;
+        if (datetime != null)
+        {
+            if (datetime.charAt(0) == '{') args += " " + datetime;
+            else args += " {" + datetime + "}";
+        }
+        return sendCommand (IMAPCommand.getCommand(IMAPCommand.APPEND), args)
+            == IMAPReply.OK;
+    }
+
+    /**
+     * Send an APPEND command to the server.
+     * @param mailboxName The mailbox name.
+     * @return True if the command was successful, false if not.
+     * @exception IOException If a network I/O error occurs in the process of
+     *            logging in.
+     */
+    public boolean append(String mailboxName) throws IOException
+    {
+        return append(mailboxName, null, null);
+    }
+
+    // --------- commands available in the selected state
+
+    /**
+     * Send a CHECK command to the server.
+     * @return True if the command was successful, false if not.
+     * @exception IOException If a network I/O error occurs in the process of
+     *            logging in.
+     */
+    public boolean check() throws IOException
+    {
+        return sendCommand (IMAPCommand.getCommand(IMAPCommand.CHECK))
+            == IMAPReply.OK;
+    }
+
+    /**
+     * Send a CLOSE command to the server.
+     * @return True if the command was successful, false if not.
+     * @exception IOException If a network I/O error occurs in the process of
+     *            logging in.
+     */
+    public boolean close() throws IOException
+    {
+        return sendCommand (IMAPCommand.getCommand(IMAPCommand.CLOSE))
+            == IMAPReply.OK;
+    }
+
+    /**
+     * Send an EXPUNGE command to the server.
+     * @return True if the command was successful, false if not.
+     * @exception IOException If a network I/O error occurs in the process of
+     *            logging in.
+     */
+    public boolean expunge() throws IOException
+    {
+        return sendCommand (IMAPCommand.getCommand(IMAPCommand.EXPUNGE))
+            == IMAPReply.OK;
+    }
+
+    /**
+     * Send a SEARCH command to the server.
+     * @param charset The charset (optional).
+     * @param criteria The search criteria.
+     * @return True if the command was successful, false if not.
+     * @exception IOException If a network I/O error occurs in the process of
+     *            logging in.
+     */
+    public boolean search(String charset, String criteria) throws IOException
+    {
+        String args = "";
+        if (charset != null) args += "CHARSET " + charset;
+        args += criteria;
+        return sendCommand (IMAPCommand.getCommand(IMAPCommand.SEARCH), args)
+            == IMAPReply.OK;
+    }
+
+    /**
+     * Send a SEARCH command to the server.
+     * @param criteria The search criteria.
+     * @return True if the command was successful, false if not.
+     * @exception IOException If a network I/O error occurs in the process of
+     *            logging in.
+     */
+    public boolean search(String criteria) throws IOException
+    {
+        return search(null, criteria);
+    }
+
+    /**
+     * Send a FETCH command to the server.
+     * @param sequenceSet The sequence set to fetch.
+     * @param itemNames The item names for the FETCH command.
+     * @return True if the command was successful, false if not.
+     * @exception IOException If a network I/O error occurs in the process of
+     *            logging in.
+     */
+    public boolean fetch(String sequenceSet, String itemNames) throws IOException
+    {
+        return sendCommand (IMAPCommand.getCommand(IMAPCommand.FETCH),
+                            sequenceSet + " " + itemNames)
+            == IMAPReply.OK;
+    }
+
+    /**
+     * Send a STORE command to the server.
+     * @param sequenceSet The sequence set to store.
+     * @param itemNames The item names for the STORE command.
+     * @param itemValues The item values for the STORE command.
+     * @return True if the command was successful, false if not.
+     * @exception IOException If a network I/O error occurs in the process of
+     *            logging in.
+     */
+    public boolean store(String sequenceSet, String itemNames, String itemValues)
+        throws IOException
+    {
+        return sendCommand (IMAPCommand.getCommand(IMAPCommand.STORE),
+                            sequenceSet + " " + itemNames + " " + itemValues)
+            == IMAPReply.OK;
+    }
+
+    /**
+     * Send a COPY command to the server.
+     * @param sequenceSet The sequence set to fetch.
+     * @param mailboxName The mailbox name.
+     * @return True if the command was successful, false if not.
+     * @exception IOException If a network I/O error occurs in the process of
+     *            logging in.
+     */
+    public boolean copy(String sequenceSet, String mailboxName) throws IOException
+    {
+        return sendCommand (IMAPCommand.getCommand(IMAPCommand.COPY),
+                            sequenceSet + " " + mailboxName)
+            == IMAPReply.OK;
+    }
+
+    /**
+     * Send a UID command to the server.
+     * @param command The command for UID.
+     * @param commandArgs The arguments for the command.
+     * @return True if the command was successful, false if not.
+     * @exception IOException If a network I/O error occurs in the process of
+     *            logging in.
+     */
+    public boolean uid(String command, String commandArgs) throws IOException
+    {
+        return sendCommand (IMAPCommand.getCommand(IMAPCommand.UID),
+                            command + " " + commandArgs)
+            == IMAPReply.OK;
+    }
+
+    /**
+     * The status data items defined in RFC 3501.
+     */
+    public enum STATUS_DATA_ITEMS
+    {
+        /** The number of messages in the mailbox. */
+        MESSAGES,
+        /** The number of messages with the \Recent flag set. */
+        RECENT,
+        /** The next unique identifier value of the mailbox. */
+        UIDNEXT,
+        /** The unique identifier validity value of the mailbox. */
+        UIDVALIDITY,
+        /** The number of messages which do not have the \Seen flag set. */
+        UNSEEN;
+    }
+
+    /**
+     * The search criteria defined in RFC 3501.
+     */
+    public enum SEARCH_CRITERIA
+    {
+        /** All messages in the mailbox. */
+        ALL,
+        /** Messages with the \Answered flag set. */
+        ANSWERED,
+        /**
+         * Messages that contain the specified string in the envelope
+         * structure's BCC field.
+         */
+        BCC,
+        /**
+         * Messages whose internal date (disregarding time and timezone)
+         * is earlier than the specified date.
+         */
+        BEFORE,
+        /**
+         * Messages that contain the specified string in the body of the
+         * message.
+         */
+        BODY,
+        /**
+         * Messages that contain the specified string in the envelope
+         * structure's CC field.
+         */
+        CC,
+        /** Messages with the \Deleted flag set. */
+        DELETED,
+        /** Messages with the \Draft flag set. */
+        DRAFT,
+        /** Messages with the \Flagged flag set. */
+        FLAGGED,
+        /**
+         * Messages that contain the specified string in the envelope
+         * structure's FROM field.
+         */
+        FROM,
+        /**
+         * Messages that have a header with the specified field-name (as
+         * defined in [RFC-2822]) and that contains the specified string
+         * in the text of the header (what comes after the colon).  If the
+         * string to search is zero-length, this matches all messages that
+         * have a header line with the specified field-name regardless of
+         * the contents.
+         */
+        HEADER,
+        /** Messages with the specified keyword flag set. */
+        KEYWORD,
+        /**
+         * Messages with an [RFC-2822] size larger than the specified
+         * number of octets.
+         */
+        LARGER,
+        /**
+         * Messages that have the \Recent flag set but not the \Seen flag.
+         * This is functionally equivalent to "(RECENT UNSEEN)".
+         */
+        NEW,
+        /** Messages that do not match the specified search key. */
+        NOT,
+        /**
+         * Messages that do not have the \Recent flag set.  This is
+         * functionally equivalent to "NOT RECENT" (as opposed to "NOT
+         * NEW").
+         */
+        OLD,
+        /**
+         * Messages whose internal date (disregarding time and timezone)
+         * is within the specified date.
+         */
+        ON,
+        /** Messages that match either search key. */
+        OR,
+        /** Messages that have the \Recent flag set. */
+        RECENT,
+        /** Messages that have the \Seen flag set. */
+        SEEN,
+        /**
+         * Messages whose [RFC-2822] Date: header (disregarding time and
+         * timezone) is earlier than the specified date.
+         */
+        SENTBEFORE,
+        /**
+         * Messages whose [RFC-2822] Date: header (disregarding time and
+         * timezone) is within the specified date.
+         */
+        SENTON,
+        /**
+         * Messages whose [RFC-2822] Date: header (disregarding time and
+         * timezone) is within or later than the specified date.
+         */
+        SENTSINCE,
+        /**
+         * Messages whose internal date (disregarding time and timezone)
+         * is within or later than the specified date.
+         */
+        SINCE,
+        /**
+         * Messages with an [RFC-2822] size smaller than the specified
+         * number of octets.
+         */
+        SMALLER,
+        /**
+         * Messages that contain the specified string in the envelope
+         * structure's SUBJECT field.
+         */
+        SUBJECT,
+        /**
+         * Messages that contain the specified string in the header or
+         * body of the message.
+         */
+        TEXT,
+        /**
+         * Messages that contain the specified string in the envelope
+         * structure's TO field.
+         */
+        TO,
+        /**
+         * Messages with unique identifiers corresponding to the specified
+         * unique identifier set.  Sequence set ranges are permitted.
+         */
+        UID,
+        /** Messages that do not have the \Answered flag set. */
+        UNANSWERED,
+        /** Messages that do not have the \Deleted flag set. */
+        UNDELETED,
+        /** Messages that do not have the \Draft flag set. */
+        UNDRAFT,
+        /** Messages that do not have the \Flagged flag set. */
+        UNFLAGGED,
+        /** Messages that do not have the specified keyword flag set. */
+        UNKEYWORD,
+        /** Messages that do not have the \Seen flag set. */
+        UNSEEN;
+    }
+
+    /**
+     * The message data item names for the FETCH command defined in RFC 3501.
+     */
+    public enum FETCH_ITEM_NAMES
+    {
+        /** Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE). */
+        ALL,
+        /** Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE). */
+        FAST,
+        /** Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE BODY). */
+        FULL,
+        /** Non-extensible form of BODYSTRUCTURE or the text of a particular body section. */
+        BODY,
+        /** The [MIME-IMB] body structure of the message. */
+        BODYSTRUCTURE,
+        /** The envelope structure of the message. */
+        ENVELOPE,
+        /** The flags that are set for this message. */
+        FLAGS,
+        /** The internal date of the message. */
+        INTERNALDATE,
+        /** A prefix for RFC-822 item names. */
+        RFC822,
+        /** The unique identifier for the message. */
+        UID;
+    }
+
+}
+/* kate: indent-width 4; replace-tabs on; */

Propchange: commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAPClient.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAPClient.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAPCommand.java
URL: http://svn.apache.org/viewvc/commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAPCommand.java?rev=1084625&view=auto
==============================================================================
--- commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAPCommand.java (added)
+++ commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAPCommand.java Wed Mar 23 16:21:38 2011
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.net.imap;
+
+/**
+ * IMAPCommand stores IMAP command code constants.
+ */
+public class IMAPCommand
+{
+    /** The  command. */
+    public static final int CAPABILITY = 0;
+    /** The  command. */
+    public static final int NOOP = 1;
+    /** The  command. */
+    public static final int LOGOUT = 2;
+    /** The  command. */
+    public static final int STARTTLS = 3;
+    /** The  command. */
+    public static final int AUTHENTICATE = 4;
+    /** The  command. */
+    public static final int LOGIN = 5;
+    /** The  command. */
+    public static final int SELECT = 6;
+    /** The  command. */
+    public static final int EXAMINE = 7;
+    /** The  command. */
+    public static final int CREATE = 8;
+    /** The  command. */
+    public static final int DELETE = 9;
+    /** The  command. */
+    public static final int RENAME = 10;
+    /** The  command. */
+    public static final int SUBSCRIBE = 11;
+    /** The  command. */
+    public static final int UNSUBSCRIBE = 12;
+    /** The  command. */
+    public static final int LIST = 13;
+    /** The  command. */
+    public static final int LSUB = 14;
+    /** The  command. */
+    public static final int STATUS = 15;
+    /** The  command. */
+    public static final int APPEND = 16;
+    /** The  command. */
+    public static final int CHECK = 17;
+    /** The  command. */
+    public static final int CLOSE = 18;
+    /** The  command. */
+    public static final int EXPUNGE = 19;
+    /** The  command. */
+    public static final int SEARCH = 20;
+    /** The  command. */
+    public static final int FETCH = 21;
+    /** The  command. */
+    public static final int STORE = 22;
+    /** The  command. */
+    public static final int COPY = 23;
+    /** The  command. */
+    public static final int UID = 24;
+
+
+
+    static final String[] _commands = {
+                                          "CAPABILITY",
+                                          "NOOP",
+                                          "LOGOUT",
+                                          "STARTTLS",
+                                          "AUTHENTICATE",
+                                          "LOGIN",
+                                          "SELECT",
+                                          "EXAMINE",
+                                          "CREATE",
+                                          "DELETE",
+                                          "RENAME",
+                                          "SUBSCRIBE",
+                                          "UNSUBSCRIBE",
+                                          "LIST",
+                                          "LSUB",
+                                          "STATUS",
+                                          "APPEND",
+                                          "CHECK",
+                                          "CLOSE",
+                                          "EXPUNGE",
+                                          "SEARCH",
+                                          "FETCH",
+                                          "STORE",
+                                          "COPY",
+                                          "UID",
+                                      };
+
+    // Cannot be instantiated.
+    private IMAPCommand()
+    {}
+
+    /**
+     * Get the IMAP protocol string command corresponding to a command code.
+     * <p>
+     * @return The IMAP protocol string command corresponding to a command code.
+     */
+    public static final String getCommand(int command)
+    {
+        return _commands[command];
+    }
+
+}
+
+/* kate: indent-width 4; replace-tabs on; */

Propchange: commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAPCommand.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAPCommand.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAPReply.java
URL: http://svn.apache.org/viewvc/commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAPReply.java?rev=1084625&view=auto
==============================================================================
--- commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAPReply.java (added)
+++ commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAPReply.java Wed Mar 23 16:21:38 2011
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.net.imap;
+
+/**
+ * IMAPReply stores IMAP reply code constants.
+ */
+
+public final class IMAPReply
+{
+    /** The reply code indicating success of an operation. */
+    public static final int OK = 0;
+
+    /** The reply code indicating failure of an operation. */
+    public static final int NO = 1;
+
+    /** The reply code indicating command rejection. */
+    public static final int BAD = 2;
+
+    /** The reply code indicating intermediate command processing stage. */
+    public static final int OK_INT = 3;
+
+    /** The reply code indicating a continuation mark. */
+    public static final int CONT = 4;
+
+    /** The reply String indicating success of an operation. */
+    public static final String OK_String = "OK";
+
+    /** The reply String indicating failure of an operation. */
+    public static final String NO_String = "NO";
+
+    /** The reply String indicating command rejection. */
+    public static final String BAD_String = "BAD";
+
+    /** The reply String indicating intermediate command processing stage. */
+    public static final String OK_INT_String = "*";
+
+    /** The reply String indicating a continuation mark. */
+    public static final String CONT_String = "+";
+
+    // Cannot be instantiated.
+    private IMAPReply()
+    {}
+}
+
+/* kate: indent-width 4; replace-tabs on; */

Propchange: commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAPReply.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAPReply.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAPSClient.java
URL: http://svn.apache.org/viewvc/commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAPSClient.java?rev=1084625&view=auto
==============================================================================
--- commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAPSClient.java (added)
+++ commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAPSClient.java Wed Mar 23 16:21:38 2011
@@ -0,0 +1,317 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.net.imap;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.net.Socket;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+
+import org.apache.commons.net.util.SSLContextUtils;
+
+/**
+ * The IMAPSClient class provides SSL/TLS connection encryption to IMAPClient.
+ *  Copied from FTPSClient.java and modified to suit IMAP.
+ * If implicit mode is selected (NOT the default), SSL/TLS negotiation starts right
+ * after the connection has been established. In explicit mode (the default), SSL/TLS
+ * negotiation starts when the user calls execTLS() and the server accepts the command.
+ * Implicit usage:
+ *               IMAPSClient c = new IMAPSClient(true);
+ *               c.connect("127.0.0.1", 993);
+ * Explicit usage:
+ *               IMAPSClient c = new IMAPSClient();
+ *               c.connect("127.0.0.1", 143);
+ *               if (c.execTLS()) { /rest of the commands here/ }
+ */
+public class IMAPSClient extends IMAPClient
+{
+    /** The default IMAP over SSL port. */
+    public static final int DEFAULT_IMAPS_PORT = 993;
+
+    /** Default secure socket protocol name. */
+    public static final String DEFAULT_PROTOCOL = "TLS";
+
+    /** The security mode. True - Implicit Mode / False - Explicit Mode. */
+    private final boolean isImplicit;
+    /** The secure socket protocol to be used, like SSL/TLS. */
+    private final String protocol;
+    /** The context object. */
+    private SSLContext context = null;
+    /** The cipher suites. SSLSockets have a default set of these anyway,
+        so no initialization required. */
+    private String[] suites = null;
+    /** The protocol versions. */
+    private String[] protocols = //null;
+        null;//{"SSLv2", "SSLv3", "TLSv1", "TLSv1.1", "SSLv2Hello"};
+
+    /** The IMAPS {@link TrustManager} implementation, default null. */
+    private TrustManager trustManager = null;
+
+    /** The {@link KeyManager}, default null. */
+    private KeyManager keyManager = null;
+
+    /**
+     * Constructor for IMAPSClient.
+     * Sets security mode to explicit (isImplicit = false).
+     */
+    public IMAPSClient()
+    {
+        this(DEFAULT_PROTOCOL, false);
+    }
+
+    /**
+     * Constructor for IMAPSClient.
+     * @param implicit The security mode (Implicit/Explicit).
+     */
+    public IMAPSClient(boolean implicit)
+    {
+        this(DEFAULT_PROTOCOL, implicit);
+    }
+
+    /**
+     * Constructor for IMAPSClient.
+     * @param proto the protocol.
+     */
+    public IMAPSClient(String proto)
+    {
+        this(proto, false);
+    }
+
+    /**
+     * Constructor for IMAPSClient.
+     * @param proto the protocol.
+     * @param implicit The security mode(Implicit/Explicit).
+     */
+    public IMAPSClient(String proto, boolean implicit)
+    {
+        this(proto, implicit, null);
+    }
+
+    /**
+     * Constructor for IMAPSClient.
+     * @param proto the protocol.
+     * @param implicit The security mode(Implicit/Explicit).
+     */
+    public IMAPSClient(String proto, boolean implicit, SSLContext ctx)
+    {
+        super();
+        setDefaultPort(DEFAULT_IMAPS_PORT);
+        protocol = proto;
+        isImplicit = implicit;
+        context = ctx;
+    }
+
+    /**
+     * Constructor for IMAPSClient.
+     * @param implicit The security mode(Implicit/Explicit).
+     * @param ctx A pre-configured SSL Context.
+     */
+    public IMAPSClient(boolean implicit, SSLContext ctx)
+    {
+        this(DEFAULT_PROTOCOL, implicit, ctx);
+    }
+
+    /**
+     * Constructor for IMAPSClient.
+     * @param context A pre-configured SSL Context.
+     */
+    public IMAPSClient(SSLContext context)
+    {
+        this(false, context);
+    }
+
+    /**
+     * Because there are so many connect() methods,
+     * the _connectAction_() method is provided as a means of performing
+     * some action immediately after establishing a connection,
+     * rather than reimplementing all of the connect() methods.
+     * @throws IOException If it is thrown by _connectAction_().
+     * @see org.apache.commons.net.SocketClient#_connectAction_()
+     */
+    @Override
+    protected void _connectAction_() throws IOException
+    {
+        // Implicit mode.
+        if (isImplicit) performSSLNegotiation();
+        super._connectAction_();
+        // Explicit mode - don't do anything. The user calls execTLS()
+    }
+
+    /**
+     * Performs a lazy init of the SSL context.
+     * @throws IOException When could not initialize the SSL context.
+     */
+    private void initSSLContext() throws IOException
+    {
+        if (context == null)
+        {
+            context = SSLContextUtils.createSSLContext(protocol, getKeyManager(), getTrustManager());
+        }
+    }
+
+    /**
+     * SSL/TLS negotiation. Acquires an SSL socket of a
+     * connection and carries out handshake processing.
+     * @throws IOException If server negotiation fails.
+     */
+    private void performSSLNegotiation() throws IOException
+    {
+        initSSLContext();
+
+        SSLSocketFactory ssf = context.getSocketFactory();
+        String ip = _socket_.getInetAddress().getHostAddress();
+        int port = _socket_.getPort();
+        SSLSocket socket =
+            (SSLSocket) ssf.createSocket(_socket_, ip, port, true);
+        socket.setEnableSessionCreation(true);
+        socket.setUseClientMode(true);
+
+        if (protocols != null) socket.setEnabledProtocols(protocols);
+        if (suites != null) socket.setEnabledCipherSuites(suites);
+        socket.startHandshake();
+
+        _socket_ = socket;
+        _input_ = socket.getInputStream();
+        _output_ = socket.getOutputStream();
+        _reader =
+          new BufferedReader(new InputStreamReader(_input_,
+                                                   __DEFAULT_ENCODING));
+        __writer =
+          new BufferedWriter(new OutputStreamWriter(_output_,
+                                                    __DEFAULT_ENCODING));
+    }
+
+    /**
+     * Get the {@link KeyManager} instance.
+     * @return The current {@link KeyManager} instance.
+     */
+    private KeyManager getKeyManager()
+    {
+        return keyManager;
+    }
+
+    /**
+     * Set a {@link KeyManager} to use.
+     * @param newKeyManager The KeyManager implementation to set.
+     * @see org.apache.commons.net.util.KeyManagerUtils
+     */
+    public void setKeyManager(KeyManager newKeyManager)
+    {
+        keyManager = newKeyManager;
+    }
+
+    /**
+     * Controls which particular cipher suites are enabled for use on this
+     * connection. Called before server negotiation.
+     * @param cipherSuites The cipher suites.
+     */
+    public void setEnabledCipherSuites(String[] cipherSuites)
+    {
+        suites = new String[cipherSuites.length];
+        System.arraycopy(cipherSuites, 0, suites, 0, cipherSuites.length);
+    }
+
+    /**
+     * Returns the names of the cipher suites which could be enabled
+     * for use on this connection.
+     * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns null.
+     * @return An array of cipher suite names, or <code>null</code>.
+     */
+    public String[] getEnabledCipherSuites()
+    {
+        if (_socket_ instanceof SSLSocket)
+        {
+            return ((SSLSocket)_socket_).getEnabledCipherSuites();
+        }
+        return null;
+    }
+
+    /**
+     * Controls which particular protocol versions are enabled for use on this
+     * connection. I perform setting before a server negotiation.
+     * @param protocolVersions The protocol versions.
+     */
+    public void setEnabledProtocols(String[] protocolVersions)
+    {
+        protocols = new String[protocolVersions.length];
+        System.arraycopy(protocolVersions, 0, protocols, 0, protocolVersions.length);
+    }
+
+    /**
+     * Returns the names of the protocol versions which are currently
+     * enabled for use on this connection.
+     * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns null.
+     * @return An array of protocols, or <code>null</code>.
+     */
+    public String[] getEnabledProtocols()
+    {
+        if (_socket_ instanceof SSLSocket)
+        {
+            return ((SSLSocket)_socket_).getEnabledProtocols();
+        }
+        return null;
+    }
+
+    /**
+     * The TLS command execution.
+     * @throws SSLException If the server reply code is not positive.
+     * @throws IOException If an I/O error occurs while sending
+     * the command or performing the negotiation.
+     * @return TRUE if the command and negotiation succeeded.
+     */
+    public boolean execTLS() throws SSLException, IOException
+    {
+        if (sendCommand(IMAPCommand.getCommand(IMAPCommand.STARTTLS)) != IMAPReply.OK)
+        {
+            return false;
+            //throw new SSLException(getReplyString());
+        }
+        performSSLNegotiation();
+        return true;
+    }
+
+    /**
+     * Get the currently configured {@link TrustManager}.
+     * @return A TrustManager instance.
+     */
+    public TrustManager getTrustManager()
+    {
+        return trustManager;
+    }
+
+    /**
+     * Override the default {@link TrustManager} to use.
+     * @param newTrustManager The TrustManager implementation to set.
+     * @see org.apache.commons.net.util.TrustManagerUtils
+     */
+    public void setTrustManager(TrustManager newTrustManager)
+    {
+        trustManager = newTrustManager;
+    }
+
+}
+/* kate: indent-width 4; replace-tabs on; */

Propchange: commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAPSClient.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/net/trunk/src/main/java/org/apache/commons/net/imap/IMAPSClient.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision



Mime
View raw message