FileDocCategorySizeDatePackage
Protocol.javaAPI DocJavaMail 1.4.312972Tue Nov 17 10:38:10 GMT 2009com.sun.mail.iap

Protocol

public class Protocol extends Object
General protocol handling code for IMAP-like protocols.

The Protocol object is multithread safe.

author
John Mani
author
Max Spivak
author
Bill Shannon

Fields Summary
protected String
host
private Socket
socket
protected boolean
debug
protected boolean
quote
protected PrintStream
out
protected Properties
props
protected String
prefix
private boolean
connected
private TraceInputStream
traceInput
private volatile ResponseInputStream
input
private TraceOutputStream
traceOutput
private volatile DataOutputStream
output
private int
tagCounter
private String
localHostName
private final Vector
handlers
private volatile long
timestamp
private static final byte[]
CRLF
Constructors Summary
public Protocol(String host, int port, boolean debug, PrintStream out, Properties props, String prefix, boolean isSSL)
Constructor.

Opens a connection to the given host at given port.

param
host host to connect to
param
port portnumber to connect to
param
debug debug mode
param
out debug output stream
param
props Properties object used by this protocol
param
prefix Prefix to prepend to property keys

 
                   	     	             	                 	          
          
		         
		         
	try {
	    this.host = host;
	    this.debug = debug;
	    this.out = out;
	    this.props = props;
	    this.prefix = prefix;

	    socket = SocketFetcher.getSocket(host, port, props, prefix, isSSL);
	    quote = PropUtil.getBooleanProperty(props,
					"mail.debug.quote", false);

	    initStreams(out);

	    // Read server greeting
	    processGreeting(readResponse());

	    timestamp = System.currentTimeMillis();
 
	    connected = true;	// must be last statement in constructor
	} finally {
	    /*
	     * If we get here because an exception was thrown, we need
	     * to disconnect to avoid leaving a connected socket that
	     * no one will be able to use because this object was never
	     * completely constructed.
	     */
	    if (!connected)
		disconnect();
	}
    
public Protocol(InputStream in, OutputStream out, boolean debug)
Constructor for debugging.

	this.host = "localhost";
	this.debug = debug;
	this.quote = false;
	this.out = System.out;

	// XXX - inlined initStreams, won't allow later startTLS
	traceInput = new TraceInputStream(in, System.out);
	traceInput.setTrace(debug);
	traceInput.setQuote(quote);
	input = new ResponseInputStream(traceInput);

	traceOutput = new TraceOutputStream(out, System.out);
	traceOutput.setTrace(debug);
	traceOutput.setQuote(quote);
	output = new DataOutputStream(new BufferedOutputStream(traceOutput));

        timestamp = System.currentTimeMillis();
    
Methods Summary
public voidaddResponseHandler(com.sun.mail.iap.ResponseHandler h)
Adds a response handler.

	handlers.addElement(h);
    
public synchronized com.sun.mail.iap.Response[]command(java.lang.String command, com.sun.mail.iap.Argument args)
Send a command to the server. Collect all responses until either the corresponding command completion response or a BYE response (indicating server failure). Return all the collected responses.

param
command the command
param
args the arguments
return
array of Response objects returned by the server

	commandStart(command);
	Vector v = new Vector();
	boolean done = false;
	String tag = null;
	Response r = null;

	// write the command
	try {
	    tag = writeCommand(command, args);
	} catch (LiteralException lex) {
	    v.addElement(lex.getResponse());
	    done = true;
	} catch (Exception ex) {
	    // Convert this into a BYE response
	    v.addElement(Response.byeResponse(ex));
	    done = true;
	}

	while (!done) {
	    try {
		r = readResponse();
	    } catch (IOException ioex) {
		// convert this into a BYE response
		r = Response.byeResponse(ioex);
	    } catch (ProtocolException pex) {
		continue; // skip this response
	    }
		
	    v.addElement(r);

	    if (r.isBYE()) // shouldn't wait for command completion response
		done = true;

	    // If this is a matching command completion response, we are done
	    if (r.isTagged() && r.getTag().equals(tag))
		done = true;
	}

	Response[] responses = new Response[v.size()];
	v.copyInto(responses);
        timestamp = System.currentTimeMillis();
	commandEnd();
	return responses;
    
private voidcommandEnd()

 
private voidcommandStart(java.lang.String command)

 
protected synchronized voiddisconnect()
Disconnect.

	if (socket != null) {
	    try {
		socket.close();
	    } catch (IOException e) {
		// ignore it
	    }
	    socket = null;
	}
    
protected voidfinalize()
Finalizer.

	super.finalize();
	disconnect();
    
protected com.sun.mail.iap.ResponseInputStreamgetInputStream()
Return the Protocol's InputStream.

	return input;
    
protected synchronized java.lang.StringgetLocalHost()
Get the name of the local host. The property .localhost overrides .localaddress, which overrides what InetAddress would tell us.

	// get our hostname and cache it for future use
	if (localHostName == null || localHostName.length() <= 0)
	    localHostName =
		    props.getProperty(prefix + ".localhost");
	if (localHostName == null || localHostName.length() <= 0)
	    localHostName =
		    props.getProperty(prefix + ".localaddress");
	try {
	    if (localHostName == null || localHostName.length() <= 0) {
		InetAddress localHost = InetAddress.getLocalHost();
		localHostName = localHost.getCanonicalHostName();
		// if we can't get our name, use local address literal
		if (localHostName == null)
		    // XXX - not correct for IPv6
		    localHostName = "[" + localHost.getHostAddress() + "]";
	    }
	} catch (UnknownHostException uhex) {
	}

	// last chance, try to get our address from our socket
	if (localHostName == null || localHostName.length() <= 0) {
	    if (socket != null && socket.isBound()) {
		InetAddress localHost = socket.getLocalAddress();
		localHostName = localHost.getCanonicalHostName();
		// if we can't get our name, use local address literal
		if (localHostName == null)
		    // XXX - not correct for IPv6
		    localHostName = "[" + localHost.getHostAddress() + "]";
	    }
	}
	return localHostName;
    
protected java.io.OutputStreamgetOutputStream()
Return the Protocol's OutputStream

	return output;
    
protected com.sun.mail.iap.ByteArraygetResponseBuffer()
Return a buffer to be used to read a response. The default implementation returns null, which causes a new buffer to be allocated for every response.

since
JavaMail 1.4.1

	return null;
    
public longgetTimestamp()
Returns the timestamp.

        return timestamp;
    
public voidhandleResult(com.sun.mail.iap.Response response)
Convenience routine to handle OK, NO, BAD and BYE responses.

	if (response.isOK())
	    return;
	else if (response.isNO())
	    throw new CommandFailedException(response);
	else if (response.isBAD())
	    throw new BadCommandException(response);
	else if (response.isBYE()) {
	    disconnect();
	    throw new ConnectionException(this, response);
	}
    
private voidinitStreams(java.io.PrintStream out)

	traceInput = new TraceInputStream(socket.getInputStream(), out);
	traceInput.setTrace(debug);
	traceInput.setQuote(quote);
	input = new ResponseInputStream(traceInput);

	traceOutput = new TraceOutputStream(socket.getOutputStream(), out);
	traceOutput.setTrace(debug);
	traceOutput.setQuote(quote);
	output = new DataOutputStream(new BufferedOutputStream(traceOutput));
    
public voidnotifyResponseHandlers(com.sun.mail.iap.Response[] responses)
Notify response handlers

	if (handlers.size() == 0)
	    return;
	
	for (int i = 0; i < responses.length; i++) { // go thru responses
	    Response r = responses[i];

	    // skip responses that have already been handled
	    if (r == null)
		continue;

	    // Need to copy handlers list because handlers can be removed
	    // when handling a response.
	    Object[] h = handlers.toArray();

	    // dispatch 'em
	    for (int j = 0; j < h.length; j++) {
		if (h[j] != null)
		    ((ResponseHandler)h[j]).handleResponse(r);
	    }
	}
    
protected voidprocessGreeting(com.sun.mail.iap.Response r)

	if (r.isBYE())
	    throw new ConnectionException(this, r);
    
public com.sun.mail.iap.ResponsereadResponse()

	return new Response(this);
    
public voidremoveResponseHandler(com.sun.mail.iap.ResponseHandler h)
Removed the specified response handler.

	handlers.removeElement(h);
    
public voidsimpleCommand(java.lang.String cmd, com.sun.mail.iap.Argument args)
Convenience routine to handle simple IAP commands that do not have responses specific to that command.

	// Issue command
	Response[] r = command(cmd, args);

	// dispatch untagged responses
	notifyResponseHandlers(r);

	// Handle result of this command
	handleResult(r[r.length-1]);
    
public synchronized voidstartTLS(java.lang.String cmd)
Start TLS on the current connection. cmd is the command to issue to start TLS negotiation. If the command succeeds, we begin TLS negotiation.

	simpleCommand(cmd, null);
	socket = SocketFetcher.startTLS(socket, host, props, prefix);
	initStreams(out);
    
protected synchronized booleansupportsNonSyncLiterals()
Returns whether this Protocol supports non-synchronizing literals Default is false. Subclasses should override this if required

	return false;
    
public java.lang.StringwriteCommand(java.lang.String command, com.sun.mail.iap.Argument args)

	// assert Thread.holdsLock(this);
	// can't assert because it's called from constructor
	String tag = "A" + Integer.toString(tagCounter++, 10); // unique tag

	output.writeBytes(tag + " " + command);
    
	if (args != null) {
	    output.write(' ");
	    args.write(this);
	}

	output.write(CRLF);
	output.flush();
	return tag;