All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.groupbyinc.common.apache.commons.net.imap.IMAP Maven / Gradle / Ivy

/*
 * 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.ArrayList;
import java.util.List;

import org.apache.commons.net.SocketClient;
import org.apache.commons.net.io.CRLFLineReader;


/**
 * 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 "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;

    protected BufferedReader _reader;
    private int _replyCode;
    private final List _replyLines;

    private final char[] _initialID = { 'A', 'A', 'A', 'A' };

    /**
     * The default IMAPClient constructor.  Initializes the state
     * to DISCONNECTED_STATE.
     */
    public IMAP()
    {
        setDefaultPort(DEFAULT_PORT);
        __state = IMAPState.DISCONNECTED_STATE;
        _reader = null;
        __writer = null;
        _replyLines = new ArrayList();
        createCommandSupport();
    }

    /**
     * Get the reply for a command that expects a tagged response.
     *
     * @throws IOException
     */
    private void __getReply() throws IOException
    {
        __getReply(true); // tagged response
    }

    /**
     * Get the reply for a command, reading the response until the
     * reply is found.
     *
     * @param wantTag {@code true} if the command expects a tagged response.
     * @throws IOException
     */
    private void __getReply(boolean wantTag) throws IOException
    {
        _replyLines.clear();
        String line = _reader.readLine();

        if (line == null) {
            throw new EOFException("Connection closed without indication.");
        }

        _replyLines.add(line);

        if (wantTag) {
            while(IMAPReply.isUntagged(line)) {
                int literalCount = IMAPReply.literalCount(line);
                while (literalCount >= 0) {
                    line=_reader.readLine();
                    if (line == null) {
                        throw new EOFException("Connection closed without indication.");
                    }
                    _replyLines.add(line);
                    literalCount -= (line.length() + 2); // Allow for CRLF
                }
                line = _reader.readLine();
                if (line == null) {
                    throw new EOFException("Connection closed without indication.");
                }
                _replyLines.add(line);
            }
            // check the response code on the last line
            _replyCode = IMAPReply.getReplyCode(line);
        } else {
            _replyCode = IMAPReply.getUntaggedReplyCode(line);
        }

        fireReplyReceived(_replyCode, getReplyString());
    }

    /**
     * Performs connection initialization and sets state to
     * {@link IMAPState#NOT_AUTH_STATE}.
     */
    @Override
    protected void _connectAction_() throws IOException
    {
        super._connectAction_();
        _reader =
          new CRLFLineReader(new InputStreamReader(_input_,
                                                   __DEFAULT_ENCODING));
        __writer =
          new BufferedWriter(new OutputStreamWriter(_output_,
                                                    __DEFAULT_ENCODING));
        int tmo = getSoTimeout();
        if (tmo <= 0) { // none set currently
            setSoTimeout(connectTimeout); // use connect timeout to ensure we don't block forever
        }
        __getReply(false); // untagged response
        if (tmo <= 0) {
            setSoTimeout(tmo); // restore the original value
        }
        setState(IMAPState.NOT_AUTH_STATE);
    }

    /**
     * Sets IMAP client state.  This must be one of the
     * _STATE constants.
     * 

* @param state The new state. */ protected void setState(IMAP.IMAPState state) { __state = state; } /** * Returns the current IMAP client state. *

* @return The current IMAP client state. */ public IMAP.IMAPState getState() { return __state; } /** * Disconnects the client from the server, and sets the state to * DISCONNECTED_STATE . The reply text information * from the last issued command is voided to allow garbage collection * of the memory used to store that information. *

* @exception IOException If there is an error in disconnecting. */ @Override public void disconnect() throws IOException { super.disconnect(); _reader = null; __writer = null; _replyLines.clear(); setState(IMAPState.DISCONNECTED_STATE); } /** * Sends a command an arguments to the server and returns the reply code. *

* @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). */ private int sendCommandWithID(String commandID, String command, String args) throws IOException { StringBuilder __commandBuffer = new StringBuilder(); if (commandID != null) { __commandBuffer.append(commandID); __commandBuffer.append(' '); } __commandBuffer.append(command); if (args != null) { __commandBuffer.append(' '); __commandBuffer.append(args); } __commandBuffer.append(SocketClient.NETASCII_EOL); String message = __commandBuffer.toString(); __writer.write(message); __writer.flush(); fireCommandSent(command, message); __getReply(); return _replyCode; } /** * Sends a command an arguments to the server and returns the reply code. *

* @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. *

* @param command The IMAP command to send. * @return The server reply code (see IMAPReply). */ public int sendCommand(String command) throws IOException { return sendCommand(command, null); } /** * Sends a command and arguments to the server and returns the reply code. *

* @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(IMAPCommand command, String args) throws IOException { return sendCommand(command.getIMAPCommand(), args); } /** * Sends a command and arguments to the server and return whether successful. *

* @param command The IMAP command to send * (one of the IMAPCommand constants). * @param args The command arguments. * @return {@code true} if the command was successful */ public boolean doCommand(IMAPCommand command, String args) throws IOException { return IMAPReply.isSuccess(sendCommand(command, args)); } /** * Sends a command with no arguments to the server and returns the * reply code. * * @param command The IMAP command to send * (one of the IMAPCommand constants). * @return The server reply code (see IMAPReply). **/ public int sendCommand(IMAPCommand command) throws IOException { return sendCommand(command, null); } /** * Sends a command to the server and return whether successful. * * @param command The IMAP command to send * (one of the IMAPCommand constants). * @return {@code true} if the command was successful */ public boolean doCommand(IMAPCommand command) throws IOException { return IMAPReply.isSuccess(sendCommand(command)); } /** * Sends data to the server and returns the reply code. *

* @param command The IMAP command to send. * @return The server reply code (see IMAPReply). */ public int sendData(String command) throws IOException { return sendCommandWithID(null, 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() { return _replyLines.toArray(new String[_replyLines.size()]); } /** * Returns the reply to the last command sent to the server. * The value is a single string containing all the reply lines including * newlines. *

* @return The last server response. */ public String getReplyString() { StringBuilder buffer = new StringBuilder(256); for (String s : _replyLines) { buffer.append(s); 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 carry = true; // want to increment initially for (int i = _initialID.length-1; carry && i>=0; i--) { if (_initialID[i] == 'Z') { _initialID[i] = 'A'; } else { _initialID[i]++; carry = false; // did not wrap round } } return res; } } /* kate: indent-width 4; replace-tabs on; */





© 2015 - 2025 Weber Informatics LLC | Privacy Policy