dmose%mozilla.org 9fc7780ead updating license boilerplate to xPL v1.1
git-svn-id: svn://10.0.0.236/trunk@52523 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-02 06:20:05 +00:00

2024 lines
61 KiB
Java

/*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (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.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the Netscape Messaging Access SDK Version 3.5 code,
* released on or about June 15, 1998. *
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s): ______________________________________.
*/
/*
* Copyright (c) 1997 and 1998 Netscape Communications Corporation
* (http://home.netscape.com/misc/trademarks.html)
*/
package netscape.messaging.imap4;
import java.io.*;
import java.net.*;
import java.util.*;
import netscape.messaging.IO;
/**
* Dispatcher parses incoming data and dispatches it to the appropriate
* method on the sink
*/
class Dispatcher
{
/**Create a Dispatcher object*/
public Dispatcher( IO in_io, IIMAP4Sink in_sink, Vector in_pendingCommands,
SystemPreferences in_systemPrefs)
{
int l_index = 0, i = 0;
//Internal variables
m_io = in_io;
m_sink = in_sink;
m_pendingCommands = in_pendingCommands;
m_systemPrefs = in_systemPrefs;
//Re-usable buffers
m_data = new byte[m_systemPrefs.getBlockSize()];
m_buffers = new StringBuffer[5];
m_fieldValues = new StringBuffer[10];
for(l_index = 0; l_index < m_buffers.length; l_index++)
{
m_buffers[l_index] = new StringBuffer();
}
//Note: The starting point for the index is dependent on how many
//of the StringBuffers in m_buffers are used while processing
//ENVELOPE.. only used in fetchEnvelope
for(i = 0, l_index = 2; l_index < m_buffers.length; i++, l_index++)
{
m_fieldValues[i] = m_buffers[l_index];
}
for(; i < m_fieldValues.length; i++)
{
m_fieldValues[i] = new StringBuffer();
}
m_readHeader = false;
m_appendStream = null;
}
///////////////////////////////////////////////////////////////////////////////
//Parsing methods for each server response type
/**
* Indicates the end of response(s) for successful commands
* @param in_data The data to be parsed
*/
public void taggedLine(StringBuffer in_data) throws IMAP4Exception
{
parseTaggedLine(in_data);
m_pendingCommands.removeElement((m_buffers[0]).toString());
m_sink.taggedLine(m_buffers[0], m_buffers[1], m_buffers[2]);
}
/**
* Indicates the response for unsuccessful commands (error responses)
* @param in_data The data to be parsed
*/
public void error(StringBuffer in_data) throws IMAP4Exception
{
parseTaggedLine(in_data);
m_pendingCommands.removeElement((m_buffers[0]).toString());
m_sink.error(m_buffers[0], m_buffers[1], m_buffers[2]);
}
/**
* Indicates an untagged error for NO and BAD
* @param in_data The data to be parsed
*/
public void untaggedError(StringBuffer in_data) throws IMAP4Exception
{
int l_begin = 0, l_end = -1;
//Initialize buffers
for(int i = 0; i < m_buffers.length; i++)
{
m_buffers[i].setLength(0);
}
//Skip over the *
l_end = indexOf(in_data, ' ', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
//This error is untagged
m_buffers[0].append(IGlobals.UNTAGGED);
//Store the status: NO or BAD
l_end = storeSegment(in_data, m_buffers[1], ' ', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
//Store the human-readable information
if((l_begin == -1) || (l_end == -1))
{
l_begin = 0;
l_begin = indexOf(in_data, ' ', l_begin);
if(l_begin == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_begin = indexOf(in_data, ' ', l_begin + 1);
if(l_begin == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_begin++;
}
else
{
l_begin = indexOf(in_data, ' ', l_end);
if(l_begin == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_begin++;
}
m_buffers[2].setLength(0);
for(int i = l_begin; i < in_data.length(); i++)
{
m_buffers[2].append(in_data.charAt(i));
}
m_sink.error(m_buffers[0], m_buffers[1], m_buffers[2]);
}
/**
* Parses an unsolicited ok response
* @param in_data The data to be parsed
* @param IMAP4Exception A parsing error occured
*/
public void ok(StringBuffer in_data) throws IMAP4Exception
{
int l_begin = 0, l_end = -1;
//Retrieve the response code
m_buffers[0].setLength(0);
l_begin = indexOf(in_data, '[', l_begin);
if(l_begin != -1)
{
l_end = indexOf(in_data, ']', l_begin);
if(l_end != -1)
{
for(int i = l_begin; i < (l_end + 1); i++)
{
m_buffers[0].append(in_data.charAt(i));
}
}
}
//Store the human-readable information
if((l_begin == -1) || (l_end == -1))
{
l_begin = 0;
l_begin = indexOf(in_data, ' ', l_begin);
if(l_begin == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_begin = indexOf(in_data, ' ', l_begin + 1);
if(l_begin == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_begin++;
}
else
{
l_begin = indexOf(in_data, ' ', l_end);
if(l_begin == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_begin++;
}
m_buffers[1].setLength(0);
for(int i = l_begin; i < in_data.length(); i++)
{
m_buffers[1].append(in_data.charAt(i));
}
m_sink.ok(m_buffers[0], m_buffers[1]);
}
/**
* Parses the tagged line
* @param in_data The data to be parsed
*/
protected void parseTaggedLine(StringBuffer in_data) throws IMAP4Exception
{
int l_begin = 0, l_end = -1;
//Initialize buffers
for(int i = 0; i < m_buffers.length; i++)
{
m_buffers[i].setLength(0);
}
//Store the tag
l_end = storeSegment(in_data, m_buffers[0], ' ', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
//Store the status
l_end = storeSegment(in_data, m_buffers[1], ' ', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
//Store the reason
l_end = in_data.length();
for(int i = l_begin; i < l_end; i++)
{
m_buffers[2].append(in_data.charAt(i));
}
}
/**
* The capability of the IMAP server
* @param in_data The data to be parsed
*/
public void capability(StringBuffer in_data) throws IMAP4Exception
{
int l_begin = 0, l_end = -1;
//Skip over the *
l_end = indexOf(in_data, ' ', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
//Skip over CAPABILITY
l_end = indexOf(in_data, ' ', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
//The rest is the capability listing
m_buffers[0].setLength(0);
l_end = in_data.length();
for(int i = l_begin; i < l_end; i++)
{
m_buffers[0].append(in_data.charAt(i));
}
m_sink.capability(m_buffers[0]);
}
/**
* Mailboxes that matched the search criteria
* @param in_data The data to be parsed
*/
public void list(StringBuffer in_data)
{
m_buffers[0].setLength(0);
m_buffers[1].setLength(0);
m_buffers[2].setLength(0);
extractMailboxInfo(in_data, m_buffers[0], m_buffers[1], m_buffers[2]);
m_sink.list(m_buffers[0], m_buffers[1], m_buffers[2]);
}
/**
* Subscribed or active mailboxes that matched the search criteria
* @param in_data The data to be parsed
*/
public void lsub(StringBuffer in_data)
{
m_buffers[0].setLength(0);
m_buffers[1].setLength(0);
m_buffers[2].setLength(0);
extractMailboxInfo(in_data, m_buffers[0], m_buffers[1], m_buffers[2]);
m_sink.lsub(m_buffers[0], m_buffers[1], m_buffers[2]);
}
/**
* The response to a status command
* @param in_data The data to be parsed
*/
public void status(StringBuffer in_data) throws IMAP4Exception
{
int l_begin = 0, l_end = -1;
//Skip over the *
l_end = indexOf(in_data, ' ', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
//Skip over STATUS
l_end = indexOf(in_data, ' ', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
//Skip the opening parenthesis
l_end = indexOf(in_data, '(', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
while(l_begin < in_data.length())
{
//Extract the data items
m_buffers[0].setLength(0);
m_buffers[1].setLength(0);
l_begin = skipWhite(in_data, l_begin);
l_end = storeSegment(in_data, m_buffers[0], ' ', l_begin);
if(l_end == -1)
{
break;
}
l_end++;
l_begin = l_end;
//Extract the value of the data item
l_begin = skipWhite(in_data, l_begin);
l_end = storeSegment(in_data, m_buffers[1], ' ', l_begin);
if(l_end == -1)
{
l_end = storeSegment(in_data, m_buffers[1], ')', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
}
l_end++;
l_begin = l_end;
switch(resolveStatusDataItem(m_buffers[0]))
{
case IGlobals.StatusMessages:
{
m_sink.statusMessages(atoi(m_buffers[1], 0, m_buffers[1].length()));
break;
}
case IGlobals.StatusRecent:
{
m_sink.statusRecent(atoi(m_buffers[1], 0, m_buffers[1].length()));
break;
}
case IGlobals.StatusUidNext:
{
m_sink.statusUidnext(atoi(m_buffers[1], 0, m_buffers[1].length()));
break;
}
case IGlobals.StatusUidValidity:
{
m_sink.statusUidvalidity(atoi(m_buffers[1], 0, m_buffers[1].length()));
break;
}
case IGlobals.StatusUnSeen:
{
m_sink.statusUnseen(atoi(m_buffers[1], 0, m_buffers[1].length()));
break;
}
default:
{
break;
}
}
}
}
/**
* The messages that matched the search criteria
* @param in_data The data to be parsed
*/
public void search(StringBuffer in_data) throws IMAP4Exception
{
int l_begin = 0, l_end = -1;
Object l_reference = null;
//Skip over the *
l_end = indexOf(in_data, ' ', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
//Skip over SEARCH
l_end = indexOf(in_data, ' ', l_begin);
if(l_end == -1)
{
l_end =in_data.length();
l_begin = l_end;
}
else
{
l_end++;
l_begin = l_end;
}
l_reference = m_sink.searchStart();
while(l_begin < in_data.length())
{
//Extract the message number
m_buffers[0].setLength(0);
l_end = storeSegment(in_data, m_buffers[0], ' ', l_begin);
if(l_end == -1)
{
for(int i = l_begin; i < in_data.length(); i++)
{
m_buffers[0].append(in_data.charAt(i));
}
l_end = in_data.length();
l_begin = l_end;
}
else
{
l_end++;
l_begin = l_end;
}
m_sink.search(l_reference, atoi(m_buffers[0], 0, m_buffers[0].length()));
}
m_sink.searchEnd(l_reference);
}
/**
* The flags that are applicable for the selected mailbox
* @param in_data The data to be parsed
*/
public void flags(StringBuffer in_data) throws IMAP4Exception
{
int l_begin = 0, l_end = -1;
m_buffers[0].setLength(0);
//Skip over the *
l_end = indexOf(in_data, ' ', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
//Skip over FLAGS
l_end = indexOf(in_data, ' ', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
l_end = matchBrackets(in_data, m_buffers[0], l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
m_sink.flags(m_buffers[0]);
}
/**
* The total number of messages in the selected mailbox
* @param in_data The data to be parsed
*/
public void exists(StringBuffer in_data)
{
m_sink.exists(getNumber(in_data));
}
/**
* The message number of the expunged message
* @param in_data The data to be parsed
*/
public void expunge(StringBuffer in_data)
{
m_sink.expunge(getNumber(in_data));
}
/**
* The total number of messages with the \Recent flag set
* @param in_data The data to be parsed
*/
public void recent(StringBuffer in_data)
{
m_sink.recent(getNumber(in_data));
}
/**
* The reason why the connection was closed
* @param in_data The data to be parsed
*/
public void bye(StringBuffer in_data) throws IMAP4Exception
{
int l_begin = 0, l_end = -1;
m_buffers[0].setLength(0);
//Skip over the *
l_end = indexOf(in_data, ' ', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
//Skip over BYE
l_end = indexOf(in_data, ' ', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
//The rest is the capability listing
l_end = in_data.length();
for(int i = l_begin; i < l_end; i++)
{
m_buffers[0].append(in_data.charAt(i));
}
m_sink.bye(m_buffers[0]);
}
/**
* Parse the fetch data and pass into the appropriate data sink
* @param in_data The data to be parsed. "* msg FETCH (....)"
*/
public void fetch(StringBuffer in_data) throws IOException
{
int l_begin = 0, l_end = -1, l_msg = 0;
Object l_reference = null;
boolean l_readName = true;
for(int i=0; i<m_buffers.length; i++)
{
m_buffers[i].setLength(0);
}
//Skip over the *
l_end = indexOf(in_data, ' ', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
//Store the message number in m_buffers[0]
l_end = storeSegment(in_data, m_buffers[0], ' ', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
l_reference = m_sink.fetchStart(atoi(m_buffers[0], 0, m_buffers[0].length()));
//Skip over FETCH
l_end = indexOf(in_data, ' ', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
//Skip the first bracket
l_end = indexOf(in_data, '(', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
while(l_begin < in_data.length())
{
//Extract the data item
l_begin = skipWhite(in_data, l_begin);
m_buffers[0].setLength(0);
l_end = storeSegment(in_data, m_buffers[0], ' ', l_begin);
if(l_end == -1)
{
break;
}
l_end++;
l_begin = l_end;
//Extract the value of the data item
l_begin = skipWhite(in_data, l_begin);
switch(resolveFetchDataItem(m_buffers[0]))
{
case IGlobals.BodyStructure:
{
l_end = matchBrackets(in_data, m_buffers[1], l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
m_sink.fetchBodyStructure(l_reference, m_buffers[1]);
m_buffers[1].setLength(0);
break;
}
case IGlobals.Message:
case IGlobals.Rfc822Text:
{
//Extract the size of the message block
int l_totalSize = 0;
int l_bytesRead = 0;
int l_readChunk = 0;
int l_index = -1;
byte[] l_dataChunklet = null;
l_end = indexOf(in_data, '{', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
l_end = storeSegment(in_data, m_buffers[1], '}', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_totalSize = atoi(m_buffers[1], 0, m_buffers[1].length());
//Read in a block of l_totalSize from the IO
while(l_bytesRead < l_totalSize)
{
//Determine the size of the next chunk to read
if((l_bytesRead + m_systemPrefs.getBlockSize()) > l_totalSize)
{
l_readChunk = l_totalSize - l_bytesRead;
l_dataChunklet = new byte[l_readChunk];
}
else
{
l_readChunk = m_systemPrefs.getBlockSize();
l_dataChunklet = m_data;
}
//Read the chunk in
l_readChunk = m_io.read(l_dataChunklet, l_readChunk);
if(l_readChunk == -1)
{
throw new IOException(IGlobals.ConnectionLost);
}
l_bytesRead += l_readChunk;
//Parse the field and value out
if(m_readHeader)
{
int l_fieldIndex = -1;
for(int j = 0; j < l_readChunk; j++)
{
j = readHeaderLine(l_dataChunklet, j, m_buffers[2]);
if(j == -1)
{
break;
}
if( (m_buffers[2].charAt(0) == '\r') &&
(m_buffers[2].charAt(1) == '\n'))
{
m_readHeader = false;
break;
}
l_fieldIndex = getFieldName(m_buffers[2], 0, m_buffers[3]);
if(l_fieldIndex == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_fieldIndex++;
getFieldValue(m_buffers[2], l_fieldIndex, m_buffers[4]);
m_sink.fetchHeader(l_reference, m_buffers[3], m_buffers[4]);
m_buffers[2].setLength(0);
m_buffers[3].setLength(0);
m_buffers[4].setLength(0);
}
}
m_sink.fetchData(l_reference, l_dataChunklet, l_bytesRead, l_totalSize);
}
m_io.readLine(in_data);
l_begin = 0;
break;
}
case IGlobals.Rfc822Size:
{
l_end = storeSegment(in_data, m_buffers[1], ' ', l_begin);
if(l_end == -1)
{
l_end = storeSegment(in_data, m_buffers[1], ')', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
}
l_end++;
l_begin = l_end;
m_sink.fetchSize(l_reference, atoi(m_buffers[1], 0, m_buffers[1].length()));
m_buffers[1].setLength(0);
break;
}
case IGlobals.Uid:
{
l_end = storeSegment(in_data, m_buffers[1], ' ', l_begin);
if(l_end == -1)
{
l_end = storeSegment(in_data, m_buffers[1], ')', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
}
l_end++;
l_begin = l_end;
m_sink.fetchUid(l_reference, atoi(m_buffers[1], 0, m_buffers[1].length()));
m_buffers[1].setLength(0);
break;
}
case IGlobals.Flags:
{
m_buffers[1].setLength(0);
l_end = matchBrackets(in_data, m_buffers[1], l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
m_sink.fetchFlags(l_reference, m_buffers[1]);
m_buffers[1].setLength(0);
break;
}
case IGlobals.Envelope:
{
//Get the closed value of the entire envelope
int l_fieldBegin = 0, l_fieldEnd = -1, l_fieldIndex = -1;
m_buffers[1].setLength(0);
for(int i = 0; i < m_fieldValues.length; i++)
{
m_fieldValues[i].setLength(0);
}
l_end = matchBrackets(in_data, m_buffers[1], l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
//Extract the date
l_fieldBegin++; //Skip the opening bracket
l_fieldEnd = matchFieldQuotes(m_buffers[1], m_fieldValues[0], l_fieldBegin);
if(l_fieldEnd == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_fieldEnd++;
l_fieldBegin = l_fieldEnd;
//Extract the subject
l_fieldEnd = matchFieldQuotes(m_buffers[1], m_fieldValues[1], l_fieldBegin);
if(l_fieldEnd == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_fieldEnd++;
l_fieldBegin = l_fieldEnd;
for(int i = 2; i < 8; i++)
{
//Extract the from, sender, reply-to, to, cc, bcc
l_fieldEnd = matchFieldBrackets(m_buffers[1], m_fieldValues[i], l_fieldBegin);
if(l_fieldEnd == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_fieldEnd++;
l_fieldBegin = l_fieldEnd;
}
//Extract the in-reply-to
l_fieldEnd = matchFieldQuotes(m_buffers[1], m_fieldValues[8], l_fieldBegin);
if(l_fieldEnd == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_fieldEnd++;
l_fieldBegin = l_fieldEnd;
//Extract the message-id
l_fieldEnd = matchFieldQuotes(m_buffers[1], m_fieldValues[9], l_fieldBegin);
if(l_fieldEnd == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_fieldEnd++;
l_fieldBegin = l_fieldEnd;
m_sink.fetchEnvelope(l_reference, m_fieldValues);
break;
}
case IGlobals.InternalDate:
{
l_end = indexOf(in_data, '"', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
l_end = storeSegment(in_data, m_buffers[1], '"', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
m_sink.fetchInternalDate(l_reference, m_buffers[1]);
m_buffers[1].setLength(0);
break;
}
default:
{
break;
}
}
}
m_sink.fetchEnd(l_reference);
}
/**
* Parse the data continuation request
* @param in_data The data to be parsed
*/
public void plus(StringBuffer in_data) throws IOException
{
//Wait for the continuation response
//Send out message data
int l_bytesRead = 0, l_readChunk = 0, l_totalSize;
if(m_appendStream == null)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_totalSize = m_appendStream.available();
while(l_bytesRead < l_totalSize)
{
//Determine the size of the next chunk to read
if((l_bytesRead + m_systemPrefs.getBlockSize()) > l_totalSize)
{
l_readChunk = l_totalSize - l_bytesRead;
}
else
{
l_readChunk = m_systemPrefs.getBlockSize();
}
//Read the chunk in
m_appendStream.read(m_data, 0, l_readChunk);
l_bytesRead += l_readChunk;
//Write the data out
m_io.write(m_data, 0, l_readChunk);
}
m_io.write(IGlobals.CarriageNewLine);
m_io.flush();
}
/**
* Parse the namespace data
* @param in_data The data to be parsed
*/
public void namespace(StringBuffer in_data) throws IMAP4Exception
{
int l_begin = 0, l_end = -1;
int l_beginNS = 0, l_endNS = -1;
Object l_reference = null;
//Skip over the *
l_end = indexOf(in_data, ' ', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
//Skip over NAMESPACE
l_end = indexOf(in_data, ' ', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
l_reference = m_sink.nameSpaceStart();
//Extract the personal namespace
m_buffers[0].setLength(0);
l_end = matchFieldBrackets(in_data, m_buffers[0], l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
//Extract each field
l_beginNS = 1;
while(l_beginNS < m_buffers[0].length())
{
m_buffers[1].setLength(0);
l_endNS = matchFieldBrackets(m_buffers[0], m_buffers[1], l_beginNS);
if(l_endNS == -1)
{
break;
}
l_endNS++;
l_beginNS = l_endNS;
m_sink.nameSpacePersonal(l_reference, m_buffers[1]);
}
//Extract the other user's namespace
m_buffers[0].setLength(0);
l_end = matchFieldBrackets(in_data, m_buffers[0], l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
//Extract each field
l_beginNS = 1;
while(l_beginNS < m_buffers[0].length())
{
m_buffers[1].setLength(0);
l_endNS = matchFieldBrackets(m_buffers[0], m_buffers[1], l_beginNS);
if(l_endNS == -1)
{
break;
}
l_endNS++;
l_beginNS = l_endNS;
m_sink.nameSpaceOtherUsers(l_reference, m_buffers[1]);
}
//Extract the shared namespace
l_end = matchFieldBrackets(in_data, m_buffers[0], l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
//Extract each field
l_beginNS = 1;
while(l_beginNS < m_buffers[0].length())
{
m_buffers[1].setLength(0);
l_endNS = matchFieldBrackets(m_buffers[0], m_buffers[1], l_beginNS);
if(l_endNS == -1)
{
break;
}
l_endNS++;
l_beginNS = l_endNS;
m_sink.nameSpaceShared(l_reference, m_buffers[1]);
}
m_sink.nameSpaceEnd(l_reference);
}
/**
* Parse the acl data
* @param in_data The data to be parsed
*/
public void acl(StringBuffer in_data) throws IMAP4Exception
{
int l_begin = 0, l_end = -1;
Object l_reference = null;
//Skip over the *
l_end = indexOf(in_data, ' ', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
//Skip over ACL
l_end = indexOf(in_data, ' ', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
//Get the mailbox name
m_buffers[0].setLength(0);
l_end = storeSegment(in_data, m_buffers[0], ' ', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
l_reference = m_sink.aclStart(m_buffers[0]);
while(l_begin < in_data.length())
{
//Get identifier
m_buffers[0].setLength(0);
l_end = storeSegment(in_data, m_buffers[0], ' ', l_begin);
if(l_end == -1)
{
break;
}
l_end++;
l_begin = l_end;
//Get the rights
m_buffers[1].setLength(0);
l_end = storeSegment(in_data, m_buffers[1], ' ', l_begin);
if(l_end == -1)
{
l_end = storeSegment(in_data, m_buffers[1], '\n', l_begin);
if(l_end == -1)
{
break;
}
}
l_end++;
l_begin = l_end;
m_sink.aclIdentifierRight(l_reference, m_buffers[0], m_buffers[1]);
}
m_sink.aclEnd(l_reference);
}
/**
* Parse the listrights data
* @param in_data The data to be parsed
*/
public void listrights(StringBuffer in_data) throws IMAP4Exception
{
int l_begin = 0, l_end = -1;
Object l_reference = null;
//Skip over the *
l_end = indexOf(in_data, ' ', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
//Skip over LISTRIGHTS
l_end = indexOf(in_data, ' ', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
//Get the mailbox name
m_buffers[0].setLength(0);
l_end = storeSegment(in_data, m_buffers[0], ' ', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
//Get the identifier
m_buffers[1].setLength(0);
l_end = storeSegment(in_data, m_buffers[1], ' ', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
l_reference = m_sink.listRightsStart(m_buffers[0], m_buffers[1]);
//Get the required rights
m_buffers[0].setLength(0);
l_end = storeSegment(in_data, m_buffers[0], ' ', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
m_sink.listRightsRequiredRights(l_reference, m_buffers[0]);
while(l_begin < in_data.length())
{
//Get the optional rights
m_buffers[0].setLength(0);
l_end = storeSegment(in_data, m_buffers[0], ' ', l_begin);
if(l_end == -1)
{
l_end = storeSegment(in_data, m_buffers[0], '\n', l_begin);
if(l_end == -1)
{
break;
}
}
l_end++;
l_begin = l_end;
m_sink.listRightsOptionalRights(l_reference, m_buffers[0]);
}
m_sink.listRightsEnd(l_reference);
}
/**
* Parse the myrights data
* @param in_data The data to be parsed
*/
public void myrights(StringBuffer in_data) throws IMAP4Exception
{
int l_begin = 0, l_end = -1;
//Skip over the *
l_end = indexOf(in_data, ' ', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
//Skip over MYRIGHTS
l_end = indexOf(in_data, ' ', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
//Get the mailbox name
m_buffers[0].setLength(0);
l_end = storeSegment(in_data, m_buffers[0], ' ', l_begin);
if(l_end == -1)
{
throw new IMAP4Exception(IGlobals.UnexpectedServerData);
}
l_end++;
l_begin = l_end;
//Get the rights
m_buffers[1].setLength(0);
for(int i = l_begin; i < in_data.length(); i++)
{
m_buffers[1].append(in_data.charAt(i));
}
m_sink.myRights(m_buffers[0], m_buffers[1]);
}
/**
* Raw (unparsed) data is pushed into here. Note: Matches up with sendCommand
* and will also be used as a default method to push information that doesn't
* belong anywhere else
* @param in_data The data to be parsed
*/
public void rawResponse(StringBuffer in_data)
{
m_sink.rawResponse(in_data);
}
///////////////////////////////////////////////////////////////////////////////
//General methods
/**
* Sets the append stream
* @param in_iStream The message data
*/
public void setAppendStream(InputStream in_iStream)
{
m_appendStream = in_iStream;
}
/**
* Sets the sink
* @param in_iStream The message data
*/
public void setResponseSink(IIMAP4Sink in_sink)
{
m_sink = in_sink;
}
///////////////////////////////////////////////////////////////////////////////
//Parsing Utilities
/**
* Finds the first occurrence of in_find after in_index in in_src
* @param in_src The StringBuffer to search through
* @param in_find The character to find
* @param in_index The to begin the search from
* @return int The index of in_find or -1 if not found
*/
public int indexOf(StringBuffer in_src, char in_find, int in_index)
{
for(int i = in_index; i < in_src.length(); i++)
{
if(in_src.charAt(i) == in_find)
{
//Found in_find
return i;
}
}
return -1;
}
/**
* Returns the index of the next position that is not white space
* @param in_src The StringBuffer to search through
* @param in_start The index to begin the search from
* @return int The index of the next non-white space
*/
public int skipWhite(StringBuffer in_src, int in_start)
{
for(int i = in_start; i < in_src.length(); i++)
{
if(in_src.charAt(i) != ' ')
{
//Found in_find
return i;
}
}
return -1;
}
/**
* Reads a line of the header into out_line
* @param in_src The data to search through
* @param in_index The index to begin searching from
* @param out_field The storage for the line
* @returns int The index of the end of the line (\r,\n,\r\n) or -1 if
* end of line not found
*/
public int readHeaderLine(byte[] in_src, int in_index, StringBuffer out_line)
{
char l_nextChar;
for(int i = in_index; i < in_src.length; i++)
{
l_nextChar = (char)in_src[i];
out_line.append(l_nextChar);
if(l_nextChar == '\n')
{
if((i+1) < in_src.length)
{
l_nextChar = (char)in_src[i + 1];
}
if((l_nextChar != '\t')&&(l_nextChar != ' '))
{
return i;
}
}
}
return -1;
}
/**
* Extracts the next field name after in_index and places it in out_field
* @param in_src The data to search through
* @param in_index The index to begin searching from
* @param out_field The storage for the field name
* @returns int The index of the last position of the field name (index of :)
* or -1 if the name is not complete
*/
public int getFieldName(StringBuffer in_src, int in_index, StringBuffer out_field)
{
char l_nextChar;
for(int i = in_index; i < in_src.length(); i++)
{
l_nextChar = in_src.charAt(i);
if(l_nextChar == ':')
{
return i;
}
else
{
out_field.append(l_nextChar);
}
}
return -1;
}
/**
* Copies all data from in_index in in_src to out_value
* @param in_src The data to search through
* @param in_index The index to begin searching from
* @param out_value The storage for the field value
*/
public void getFieldValue(StringBuffer in_src, int in_index, StringBuffer out_value)
{
int l_index = in_index;
l_index = skipWhite(in_src, l_index);
for(int i = l_index; i < in_src.length(); i++)
{
//Don't store the new line at the end of the field value
if( ((i + 1) < in_src.length()) &&
((i + 2) == in_src.length()) &&
(in_src.charAt(i) == '\r') &&
(in_src.charAt(i + 1) == '\n'))
{
return;
}
out_value.append(in_src.charAt(i));
}
}
/**
* Finds the first occurrence of in_find after in_index in in_src
* @param in_src The StringBuffer to search through
* @param in_dest The StringBuffer to store the block in_index to in_find
* @param in_find The character to find
* @param in_index The to begin the search from
* @return int The index of in_find or -1 if not found
*/
public int storeSegment(StringBuffer in_src, StringBuffer in_dest, char in_find, int in_index)
{
int l_initialLength = in_dest.length();
for(int i = in_index; i < in_src.length(); i++)
{
if(in_src.charAt(i) == in_find)
{
//Found in_find
return i;
}
else
{
in_dest.append(in_src.charAt(i));
}
}
in_dest.setLength(l_initialLength);
return -1;
}
/**
* Same as matchBrackets, but also counts NIL value as a bracketed value
* @param in_data The data to be parsed
* @param in_value The data within the brackets
* @param in_start The index to begin parsing from
* @return int The index where the quoted value ended or -1 on error
*/
public int matchFieldQuotes(StringBuffer in_data, StringBuffer in_value, int in_start)
{
int l_index = in_start;
int l_fieldEnd = -1, l_fieldBegin = -1;
l_index = skipWhite(in_data, l_index);
if( (in_data.charAt(l_index) == 'N') &&
(in_data.charAt(l_index + 1) == 'I') &&
(in_data.charAt(l_index + 2) == 'L'))
{
in_value.append('N');
in_value.append('I');
in_value.append('L');
return (l_index + 2);
}
//Extract the quoted value
l_fieldEnd = indexOf(in_data, '"', in_start);
if(l_fieldEnd == -1)
{
return -1;
}
l_fieldEnd++;
l_fieldBegin = l_fieldEnd;
l_fieldEnd = storeSegment(in_data, in_value, '"', l_fieldBegin);
if(l_fieldEnd == -1)
{
return -1;
}
return l_fieldEnd;
}
/**
* Extract the number out the server response
* @param in_data Server response of the form * 233 EXISTS
* @return int The number at the second token position or -1 if n/a
*/
protected int getNumber(StringBuffer in_data)
{
int l_begin = 0, l_end = -1;
//Skip over the *
l_end = indexOf(in_data, ' ', l_begin);
if(l_end == -1)
{
return -1;
}
l_end++;
l_begin = l_end;
//Get the number of messages
l_end = indexOf(in_data, ' ', l_begin);
if(l_end == -1)
{
return -1;
}
return atoi(in_data, l_begin, l_end);
}
/**
* Resolves the value of in_dataItem without allocating space for a new String
* @param in_dataItem The fetch data item
* @return int A constant representing the data item
*/
protected int resolveFetchDataItem(StringBuffer in_dataItem)
{
int l_dataLength = in_dataItem.length();
if(l_dataLength < 1)
{
return IGlobals.Unknown;
}
switch(in_dataItem.charAt(0))
{
case 'B':
{
if( (l_dataLength > 12) &&
(in_dataItem.charAt(1) == 'O') &&
(in_dataItem.charAt(2) == 'D') &&
(in_dataItem.charAt(3) == 'Y') &&
(in_dataItem.charAt(4) == 'S') &&
(in_dataItem.charAt(5) == 'T') &&
(in_dataItem.charAt(6) == 'R') &&
(in_dataItem.charAt(7) == 'U') &&
(in_dataItem.charAt(8) == 'C') &&
(in_dataItem.charAt(9) == 'T') &&
(in_dataItem.charAt(10) == 'U') &&
(in_dataItem.charAt(11) == 'R') &&
(in_dataItem.charAt(12) == 'E'))
{
return IGlobals.BodyStructure;
}
else if((l_dataLength > 3) &&
(in_dataItem.charAt(1) == 'O') &&
(in_dataItem.charAt(2) == 'D') &&
(in_dataItem.charAt(3) == 'Y'))
{
if( (l_dataLength > 4) &&
(in_dataItem.charAt(4) == '['))
{
if( (in_dataItem.charAt(5) == ']') ||
(in_dataItem.charAt(5) == '0') ||
(in_dataItem.charAt(5) == 'H'))
{
m_readHeader = true;
}
}
else if((l_dataLength > 10) &&
(in_dataItem.charAt(4) == '.') &&
(in_dataItem.charAt(5) == 'P') &&
(in_dataItem.charAt(6) == 'E') &&
(in_dataItem.charAt(7) == 'E') &&
(in_dataItem.charAt(8) == 'K') &&
(in_dataItem.charAt(9) == '['))
{
if( (in_dataItem.charAt(10) == ']') ||
(in_dataItem.charAt(10) == '0') ||
(in_dataItem.charAt(10) == 'H'))
{
m_readHeader = true;
}
}
return IGlobals.Message;
}
break;
}
case 'R':
{
if( (l_dataLength > 5) &&
(in_dataItem.charAt(1) == 'F') &&
(in_dataItem.charAt(2) == 'C') &&
(in_dataItem.charAt(3) == '8') &&
(in_dataItem.charAt(4) == '2') &&
(in_dataItem.charAt(5) == '2'))
{
if( (l_dataLength > 10) &&
(in_dataItem.charAt(6) == '.') &&
(in_dataItem.charAt(7) == 'S') &&
(in_dataItem.charAt(8) == 'I') &&
(in_dataItem.charAt(9) == 'Z') &&
(in_dataItem.charAt(10) == 'E'))
{
return IGlobals.Rfc822Size;
}
else if((l_dataLength > 10) &&
(in_dataItem.charAt(6) == '.') &&
(in_dataItem.charAt(7) == 'T') &&
(in_dataItem.charAt(8) == 'E') &&
(in_dataItem.charAt(9) == 'X') &&
(in_dataItem.charAt(10) == 'T'))
{
return IGlobals.Rfc822Text;
}
else if((l_dataLength > 12) &&
(in_dataItem.charAt(6) == '.') &&
(in_dataItem.charAt(7) == 'H') &&
(in_dataItem.charAt(8) == 'E') &&
(in_dataItem.charAt(9) == 'A') &&
(in_dataItem.charAt(10) == 'D') &&
(in_dataItem.charAt(11) == 'E') &&
(in_dataItem.charAt(12) == 'R'))
{
m_readHeader = true;
return IGlobals.Message;
}
m_readHeader = true;
return IGlobals.Message;
}
break;
}
case 'U':
{
if( (l_dataLength > 2) &&
(in_dataItem.charAt(1) == 'I') &&
(in_dataItem.charAt(2) == 'D'))
{
return IGlobals.Uid;
}
break;
}
case 'F':
{
if( (l_dataLength > 4) &&
(in_dataItem.charAt(1) == 'L') &&
(in_dataItem.charAt(2) == 'A') &&
(in_dataItem.charAt(3) == 'G') &&
(in_dataItem.charAt(4) == 'S'))
{
return IGlobals.Flags;
}
break;
}
case 'E':
{
if( (l_dataLength > 7) &&
(in_dataItem.charAt(1) == 'N') &&
(in_dataItem.charAt(2) == 'V') &&
(in_dataItem.charAt(3) == 'E') &&
(in_dataItem.charAt(4) == 'L') &&
(in_dataItem.charAt(5) == 'O') &&
(in_dataItem.charAt(6) == 'P') &&
(in_dataItem.charAt(7) == 'E'))
{
return IGlobals.Envelope;
}
break;
}
case 'I':
{
if( (l_dataLength > 11) &&
(in_dataItem.charAt(1) == 'N') &&
(in_dataItem.charAt(2) == 'T') &&
(in_dataItem.charAt(3) == 'E') &&
(in_dataItem.charAt(4) == 'R') &&
(in_dataItem.charAt(5) == 'N') &&
(in_dataItem.charAt(6) == 'A') &&
(in_dataItem.charAt(7) == 'L') &&
(in_dataItem.charAt(8) == 'D') &&
(in_dataItem.charAt(9) == 'A') &&
(in_dataItem.charAt(10) == 'T') &&
(in_dataItem.charAt(11) == 'E'))
{
return IGlobals.InternalDate;
}
break;
}
default:
{
break;
}
}
return IGlobals.Unknown;
}
/**
* Resolves the value of in_dataItem without allocating space for a new String
* @param in_dataItem The status data item
* @return int A constant representing the data item
*/
protected int resolveStatusDataItem(StringBuffer in_dataItem)
{
int l_dataLength = in_dataItem.length();
if(l_dataLength < 1)
{
return IGlobals.Unknown;
}
switch(in_dataItem.charAt(0))
{
case 'M':
{
if( (l_dataLength > 7) &&
(in_dataItem.charAt(1) == 'E') &&
(in_dataItem.charAt(2) == 'S') &&
(in_dataItem.charAt(3) == 'S') &&
(in_dataItem.charAt(4) == 'A') &&
(in_dataItem.charAt(5) == 'G') &&
(in_dataItem.charAt(6) == 'E') &&
(in_dataItem.charAt(7) == 'S'))
{
return IGlobals.StatusMessages;
}
break;
}
case 'R':
{
if( (l_dataLength > 5) &&
(in_dataItem.charAt(1) == 'E') &&
(in_dataItem.charAt(2) == 'C') &&
(in_dataItem.charAt(3) == 'E') &&
(in_dataItem.charAt(4) == 'N') &&
(in_dataItem.charAt(5) == 'T'))
{
return IGlobals.StatusRecent;
}
break;
}
case 'U':
{
if( (l_dataLength > 6) &&
(in_dataItem.charAt(1) == 'I') &&
(in_dataItem.charAt(2) == 'D') &&
(in_dataItem.charAt(3) == 'N') &&
(in_dataItem.charAt(4) == 'E') &&
(in_dataItem.charAt(5) == 'X') &&
(in_dataItem.charAt(6) == 'T'))
{
return IGlobals.StatusUidNext;
}
else if((l_dataLength > 10) &&
(in_dataItem.charAt(1) == 'I') &&
(in_dataItem.charAt(2) == 'D') &&
(in_dataItem.charAt(3) == 'V') &&
(in_dataItem.charAt(4) == 'A') &&
(in_dataItem.charAt(5) == 'L') &&
(in_dataItem.charAt(6) == 'I') &&
(in_dataItem.charAt(7) == 'D') &&
(in_dataItem.charAt(8) == 'I') &&
(in_dataItem.charAt(9) == 'T') &&
(in_dataItem.charAt(10) == 'Y'))
{
return IGlobals.StatusUidValidity;
}
else if((l_dataLength > 5) &&
(in_dataItem.charAt(1) == 'N') &&
(in_dataItem.charAt(2) == 'S') &&
(in_dataItem.charAt(3) == 'E') &&
(in_dataItem.charAt(4) == 'E') &&
(in_dataItem.charAt(5) == 'N'))
{
return IGlobals.StatusUnSeen;
}
break;
}
default:
{
break;
}
}
return IGlobals.Unknown;
}
/**
* Convert the ascii number to an int
* @param in_data The buffer with the number to convert
* @param in_begin The beginning of the number
* @param in_end The end of the number
* @return int The number
*/
protected int atoi(StringBuffer in_data, int in_begin, int in_end)
{
int i;
int n;
int sign;
for ( i = in_begin; Character.isSpaceChar(in_data.charAt(i)); i++ )
{
}
sign = (in_data.charAt(i) == '-') ? -1 : 1;
if ( in_data.charAt(i) == '+' || in_data.charAt(i) == '-' )
{
i++;
}
for ( n = 0; (i < in_end) && Character.isDigit(in_data.charAt(i)); i++ )
{
n = 10 * n + ( in_data.charAt(i) - '0');
}
return sign * n;
}
protected int itoa( int in_number, byte[] io_string )
{
int i;
int sign;
if ((sign = in_number) < 0)
{
in_number = -in_number;
}
i = 0;
do
{
io_string[i++] = (byte)(in_number % 10 + '0');
}
while ((in_number /= 10) > 0);
if ( sign < 0 )
{
io_string[i] = '-';
}
reverse(io_string, i );
return i;
}
protected void reverse( byte[] io_string, int in_length )
{
int c, i, j;
for ( i = 0, j = in_length - 1; i < j; i++, j-- )
{
c = io_string[i];
io_string[i] = io_string[j];
io_string[j] = (byte)c;
}
}
/**
* Same as matchBrackets, but also counts NIL value as a bracketed value
* @param in_data The data to be parsed
* @param in_value The data within the brackets
* @param in_start The index to begin parsing from
* @return int The index where the bracketed value ended or -1 on error
*/
public int matchFieldBrackets(StringBuffer in_data, StringBuffer in_value, int in_start)
{
int l_index = in_start;
l_index = skipWhite(in_data, l_index);
if( (in_data.charAt(l_index) == 'N') &&
(in_data.charAt(l_index + 1) == 'I') &&
(in_data.charAt(l_index + 2) == 'L'))
{
in_value.append('N');
in_value.append('I');
in_value.append('L');
return (l_index + 2);
}
return matchBrackets(in_data, in_value, in_start);
}
/**
* Stores the value of the next closed set of brackets within in_value
* @param in_data The data to be parsed
* @param in_value The data within the brackets
* @param in_start The index to begin parsing from
* @return int The index where the bracketed value ended or -1 on error
*/
public int matchBrackets(StringBuffer in_data, StringBuffer in_value, int in_start)
{
//Indexes used to help find the bracketed value
int l_nIndex = -1;
int l_nLeftBraces = 0;
//Flag to indicate when the Left brace at l_nLeft should be recounted
boolean l_bRecount = false;
//Verify the first position is a left bracket
l_nIndex = indexOf(in_data, '(', in_start);
if(l_nIndex == -1)
{
return -1;
}
in_value.append(in_data.charAt(l_nIndex));
l_nIndex++;
l_nLeftBraces++;
for(; l_nIndex < in_data.length(); l_nIndex++)
{
in_value.append(in_data.charAt(l_nIndex));
if(in_data.charAt(l_nIndex) == '(')
{
l_nLeftBraces++;
}
else if(in_data.charAt(l_nIndex) == ')')
{
l_nLeftBraces--;
if(l_nLeftBraces < 1)
{
//Found the closing bracket
return l_nIndex;
}
}
}
in_value.setLength(0);
return -1;
}
/**
* Extracts the mailbox info
* @param in_data The data to parse
* @param out_buffer1 Storage for the attributes
* @param out_buffer2 Storage for the delimeter
* @param out_buffer3 Storage for the name
*/
public void extractMailboxInfo( StringBuffer in_data, StringBuffer out_buffer1,
StringBuffer out_buffer2, StringBuffer out_buffer3)
{
int l_begin = 0, l_end = -1;
//Skip over the *
l_end = indexOf(in_data, ' ', l_begin);
if(l_end == -1)
{
return;
}
l_end++;
l_begin = l_end;
//Skip over LIST
l_end = indexOf(in_data, ' ', l_begin);
if(l_end == -1)
{
return;
}
l_end++;
l_begin = l_end;
//Extract the attributes
l_end = matchBrackets(in_data, m_buffers[0], l_begin);
if(l_end == -1)
{
return;
}
l_end++;
l_begin = l_end;
//Extract the delimeter
l_end = indexOf(in_data, '"', l_begin);
if(l_end == -1)
{
return;
}
l_end++;
l_begin = l_end;
l_end = storeSegment(in_data, m_buffers[1], '"', l_begin);
if(l_end == -1)
{
return;
}
l_end++;
l_begin = l_end;
//Extract the name: The rest is the name of the mailbox
l_begin = skipWhite(in_data, l_begin);
l_end = in_data.length();
for(int i = l_begin; i < l_end; i++)
{
m_buffers[2].append(in_data.charAt(i));
}
}
//Data members
///////////////////////////////////////////////////////////////////////
/** The io object*/
private IO m_io;
/** The data sink*/
private IIMAP4Sink m_sink;
/* Re-usable buffers for data sink*/
private StringBuffer[] m_buffers;
/** Re-usable buffer for fetchData*/
private byte[] m_data;
/** Storage for envelope field values;*/
private StringBuffer[] m_fieldValues;
/** The message data*/
private InputStream m_appendStream;
/** The commands awaiting responses*/
private Vector m_pendingCommands;
/** The system preferences*/
private SystemPreferences m_systemPrefs;
/** Parsing flags*/
private boolean m_readHeader;
}