GERONIMO-5326 Geronimo javamail does not work on non-ASCII platforms
git-svn-id: https://svn.apache.org/repos/asf/geronimo/javamail/trunk@946314 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/authentication/CramMD5Authenticator.java b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/authentication/CramMD5Authenticator.java
index 17da4db..c62deac 100644
--- a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/authentication/CramMD5Authenticator.java
+++ b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/authentication/CramMD5Authenticator.java
@@ -19,6 +19,7 @@
package org.apache.geronimo.javamail.authentication;
+import java.nio.charset.Charset;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@@ -40,7 +41,7 @@
/**
* Main constructor.
- *
+ *
* @param username
* The login user name.
* @param password
@@ -54,7 +55,7 @@
/**
* Respond to the hasInitialResponse query. This mechanism does not have an
* initial response.
- *
+ *
* @return Always returns false.
*/
public boolean hasInitialResponse() {
@@ -63,7 +64,7 @@
/**
* Indicate whether the challenge/response process is complete.
- *
+ *
* @return True if the last challenge has been processed, false otherwise.
*/
public boolean isComplete() {
@@ -72,7 +73,7 @@
/**
* Retrieve the authenticator mechanism name.
- *
+ *
* @return Always returns the string "CRAM-MD5"
*/
public String getMechanismName() {
@@ -82,10 +83,10 @@
/**
* Evaluate a CRAM-MD5 login challenge, returning the a result string that
* should satisfy the clallenge.
- *
+ *
* @param challenge
* The decoded challenge data, as a byte array.
- *
+ *
* @return A formatted challege response, as an array of bytes.
* @exception MessagingException
*/
@@ -102,9 +103,9 @@
// create a unified string using the user name and the hex encoded
// digest
- String responseString = username + " " + new String(Hex.encode(digest));
+ String responseString = username + " " + new String(Hex.encode(digest), "ISO8859-1");
complete = true;
- return responseString.getBytes();
+ return responseString.getBytes("ISO8859-1");
} catch (UnsupportedEncodingException e) {
// got an error, fail this
throw new MessagingException("Invalid character encodings");
@@ -115,12 +116,12 @@
/**
* Compute a CRAM digest using the hmac_md5 algorithm. See the description
* of RFC 2104 for algorithm details.
- *
+ *
* @param key
* The key (K) for the calculation.
* @param input
* The encrypted text value.
- *
+ *
* @return The computed digest, as a byte array value.
* @exception NoSuchAlgorithmException
*/
diff --git a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/authentication/DigestMD5Authenticator.java b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/authentication/DigestMD5Authenticator.java
index c762f70..5784ec3 100644
--- a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/authentication/DigestMD5Authenticator.java
+++ b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/authentication/DigestMD5Authenticator.java
@@ -74,7 +74,7 @@
/**
* Main constructor.
- *
+ *
* @param host
* The server host name.
* @param username
@@ -94,7 +94,7 @@
/**
* Respond to the hasInitialResponse query. This mechanism does not have an
* initial response.
- *
+ *
* @return Always returns false.
*/
public boolean hasInitialResponse() {
@@ -103,7 +103,7 @@
/**
* Indicate whether the challenge/response process is complete.
- *
+ *
* @return True if the last challenge has been processed, false otherwise.
*/
public boolean isComplete() {
@@ -112,7 +112,7 @@
/**
* Retrieve the authenticator mechanism name.
- *
+ *
* @return Always returns the string "DIGEST-MD5"
*/
public String getMechanismName() {
@@ -122,10 +122,10 @@
/**
* Evaluate a DIGEST-MD5 login challenge, returning the a result string that
* should satisfy the clallenge.
- *
+ *
* @param challenge
* The decoded challenge data, as a string.
- *
+ *
* @return A formatted challege response, as an array of bytes.
* @exception MessagingException
*/
@@ -161,10 +161,10 @@
/**
* Evaluate a DIGEST-MD5 login server authentication challenge, returning
* the a result string that should satisfy the clallenge.
- *
+ *
* @param challenge
* The decoded challenge data, as a string.
- *
+ *
* @return A formatted challege response, as an array of bytes.
* @exception MessagingException
*/
@@ -180,11 +180,11 @@
// first add in the URI information.
digest.update((":smtp/" + host).getBytes("US-ASCII"));
// now mix in the response we sent originally
- String responseString = clientResponse + new String(Hex.encode(digest.digest()));
+ String responseString = clientResponse + new String(Hex.encode(digest.digest()), "US-ASCII");
digest.update(responseString.getBytes("US-ASCII"));
// now convert that into a hex encoded string.
- String validationText = new String(Hex.encode(digest.digest()));
+ String validationText = new String(Hex.encode(digest.digest()), "US-ASCII");
// if everything went well, this calculated value should match what
// we got back from the server.
@@ -202,10 +202,10 @@
/**
* Evaluate a DIGEST-MD5 login client authentication challenge, returning
* the a result string that should satisfy the clallenge.
- *
+ *
* @param challenge
* The decoded challenge data, as a string.
- *
+ *
* @return A formatted challege response, as an array of bytes.
* @exception MessagingException
*/
@@ -242,13 +242,13 @@
byte[] cnonceBytes = new byte[32];
randomGenerator.nextBytes(cnonceBytes);
- // and get this as a base64 encoded string.
- String cnonce = new String(Base64.encode(cnonceBytes));
-
- // Now the digest computation part. This gets a bit tricky, and must be
- // done in strict order.
try {
+ // and get this as a base64 encoded string.
+ String cnonce = new String(Base64.encode(cnonceBytes), "US-ASCII");
+
+ // Now the digest computation part. This gets a bit tricky, and must be
+ // done in strict order.
// this identifies where we're logging into.
String idString = username + ":" + realm + ":" + password;
// we get a digest for this string, then use the digest for the
@@ -265,20 +265,20 @@
// (qop). We save this in an
// instance variable because we'll need this to validate the
// response back from the server.
- clientResponse = new String(Hex.encode(digest.digest())) + ":" + nonce + ":00000001:" + cnonce + ":auth:";
+ clientResponse = new String(Hex.encode(digest.digest()), "US-ASCII") + ":" + nonce + ":00000001:" + cnonce + ":auth:";
// now we add in identification values to the hash.
String authString = "AUTHENTICATE:smtp/" + host;
digest.update(authString.getBytes("US-ASCII"));
// this gets added on to the client response
- String responseString = clientResponse + new String(Hex.encode(digest.digest()));
+ String responseString = clientResponse + new String(Hex.encode(digest.digest()), "US_ASCII");
// and this gets fed back into the digest
digest.update(responseString.getBytes("US-ASCII"));
// and FINALLY, the challege digest is hex encoded for sending back
// to the server (whew).
- String challengeResponse = new String(Hex.encode(digest.digest()));
+ String challengeResponse = new String(Hex.encode(digest.digest()), "US-ASCII");
// now finally build the keyword/value part of the challenge
// response. These can be
@@ -323,17 +323,21 @@
/**
* Parse the challege string, pulling out information required for our
* challenge response.
- *
+ *
* @param challenge
* The challenge data.
- *
+ *
* @return true if there were no errors parsing the string, false otherwise.
* @exception MessagingException
*/
protected boolean parseChallenge(byte[] challenge) throws MessagingException {
realms = new ArrayList();
- DigestParser parser = new DigestParser(new String(challenge));
+ DigestParser parser = null;
+ try {
+ parser = new DigestParser(new String(challenge, "US-ASCII"));
+ } catch (UnsupportedEncodingException ex) {
+ }
// parse the entire string...but we ignore everything but the options we
// support.
@@ -376,7 +380,7 @@
/**
* Normal constructor.
- *
+ *
* @param challenge
* The challenge string to be parsed.
*/
@@ -388,7 +392,7 @@
/**
* Test if there are more values to parse.
- *
+ *
* @return true if we've not reached the end of the challenge string,
* false if the challenge has been completely consumed.
*/
@@ -398,7 +402,7 @@
/**
* Return the character at the current parsing position.
- *
+ *
* @return The string character for the current parse position.
*/
private char currentChar() {
@@ -424,7 +428,7 @@
/**
* Parse a quoted string used with a name/value pair, accounting for
* escape characters embedded within the string.
- *
+ *
* @return The string value of the character string.
*/
private String parseQuotedValue() {
@@ -467,7 +471,7 @@
/**
* Parse a token value used with a name/value pair.
- *
+ *
* @return The string value of the token. Returns null if nothing is
* found up to the separater.
*/
@@ -533,7 +537,7 @@
/**
* Parse out a name token of a name/value pair.
- *
+ *
* @return The string value of the name.
*/
private String parseName() {
@@ -546,7 +550,7 @@
/**
* Parse out a a value of a name/value pair.
- *
+ *
* @return The string value associated with the name.
*/
private String parseValue() {
@@ -564,7 +568,7 @@
/**
* Parse a name/value pair in an DIGEST-MD5 string.
- *
+ *
* @return A NameValuePair object containing the two parts of the value.
* @exception MessagingException
*/
diff --git a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/IMAPMessage.java b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/IMAPMessage.java
index 3726cd9..23f38b4 100644
--- a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/IMAPMessage.java
+++ b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/IMAPMessage.java
@@ -31,7 +31,7 @@
import javax.activation.DataHandler;
-import javax.mail.Address;
+import javax.mail.Address;
import javax.mail.FetchProfile;
import javax.mail.Flags;
import javax.mail.Folder;
@@ -47,13 +47,13 @@
import javax.mail.internet.InternetAddress;
import javax.mail.internet.InternetHeaders;
-import javax.mail.internet.MailDateFormat;
+import javax.mail.internet.MailDateFormat;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;
-import org.apache.geronimo.javamail.store.imap.connection.IMAPBody;
-import org.apache.geronimo.javamail.store.imap.connection.IMAPBodyStructure;
-import org.apache.geronimo.javamail.store.imap.connection.IMAPConnection;
+import org.apache.geronimo.javamail.store.imap.connection.IMAPBody;
+import org.apache.geronimo.javamail.store.imap.connection.IMAPBodyStructure;
+import org.apache.geronimo.javamail.store.imap.connection.IMAPConnection;
import org.apache.geronimo.javamail.store.imap.connection.IMAPEnvelope;
import org.apache.geronimo.javamail.store.imap.connection.IMAPFetchDataItem;
import org.apache.geronimo.javamail.store.imap.connection.IMAPFetchResponse;
@@ -77,9 +77,9 @@
* @version $Rev$ $Date$
*/
public class IMAPMessage extends MimeMessage {
-
- private static final byte[] CRLF = "\r\n".getBytes();
-
+
+ private static final byte[] CRLF = new byte[]{'\r', '\n'};
+
// the Store we're stored in (which manages the connection and other stuff).
protected IMAPStore store;
@@ -87,27 +87,27 @@
protected int sequenceNumber;
// the IMAP uid value;
protected long uid = -1;
- // the section identifier. This is only really used for nested messages. The toplevel version
- // will be null, and each nested message will set the appropriate part identifier
- protected String section;
+ // the section identifier. This is only really used for nested messages. The toplevel version
+ // will be null, and each nested message will set the appropriate part identifier
+ protected String section;
// the loaded message envelope (delayed until needed)
protected IMAPEnvelope envelope;
// the body structure information (also lazy loaded).
protected IMAPBodyStructure bodyStructure;
// the IMAP INTERNALDATE value.
protected Date receivedDate;
- // the size item, which is maintained separately from the body structure
+ // the size item, which is maintained separately from the body structure
// as it can be retrieved without getting the body structure
- protected int size;
- // turned on once we've requested the entire header set.
- protected boolean allHeadersRetrieved = false;
+ protected int size;
+ // turned on once we've requested the entire header set.
+ protected boolean allHeadersRetrieved = false;
// singleton date formatter for this class.
static protected MailDateFormat dateFormat = new MailDateFormat();
/**
* Contruct an IMAPMessage instance.
- *
+ *
* @param folder The hosting folder for the message.
* @param store The Store owning the article (and folder).
* @param msgnum The article message number. This is assigned by the Folder, and is unique
@@ -117,15 +117,15 @@
* change whenever messages are expunged. This is the server retrieval number
* of the message, which needs to be synchronized with status updates
* sent from the server.
- *
+ *
* @exception MessagingException
*/
IMAPMessage(IMAPFolder folder, IMAPStore store, int msgnum, int sequenceNumber) {
super(folder, msgnum);
this.sequenceNumber = sequenceNumber;
this.store = store;
- // The default constructor creates an empty Flags item. We need to clear this out so we
- // know if the flags need to be fetched from the server when requested.
+ // The default constructor creates an empty Flags item. We need to clear this out so we
+ // know if the flags need to be fetched from the server when requested.
flags = null;
// make sure this is a totally fresh set of headers. We'll fill things in as we retrieve them.
headers = new InternetHeaders();
@@ -147,7 +147,7 @@
sequenceNumber = -1;
}
}
-
+
/**
* Return a copy the flags associated with this message.
@@ -156,9 +156,9 @@
* @throws MessagingException if there was a problem accessing the Store
*/
public synchronized Flags getFlags() throws MessagingException {
- // load the flags, if needed
- loadFlags();
- return super.getFlags();
+ // load the flags, if needed
+ loadFlags();
+ return super.getFlags();
}
@@ -171,9 +171,9 @@
* @throws MessagingException if there was a problem accessing the Store
*/
public synchronized boolean isSet(Flags.Flag flag) throws MessagingException {
- // load the flags, if needed
- loadFlags();
- return super.isSet(flag);
+ // load the flags, if needed
+ loadFlags();
+ return super.isSet(flag);
}
/**
@@ -187,31 +187,31 @@
public synchronized void setFlags(Flags flag, boolean set) throws MessagingException {
// make sure this is in a valid state.
checkValidity();
-
- // we need to ensure that we're the only ones with access to the folder's
- // message cache any time we need to talk to the server. This needs to be
- // held until after we release the connection so that any pending EXPUNGE
- // untagged responses are processed before the next time the folder connection is
- // used.
+
+ // we need to ensure that we're the only ones with access to the folder's
+ // message cache any time we need to talk to the server. This needs to be
+ // held until after we release the connection so that any pending EXPUNGE
+ // untagged responses are processed before the next time the folder connection is
+ // used.
synchronized (folder) {
IMAPConnection connection = getConnection();
try {
- // set the flags for this item and update the
- // internal state with the new values returned from the
- // server.
- flags = connection.setFlags(sequenceNumber, flag, set);
+ // set the flags for this item and update the
+ // internal state with the new values returned from the
+ // server.
+ flags = connection.setFlags(sequenceNumber, flag, set);
} finally {
- releaseConnection(connection);
+ releaseConnection(connection);
}
}
}
/**
- * Return an InputStream instance for accessing the
+ * Return an InputStream instance for accessing the
* message content.
- *
+ *
* @return An InputStream instance for accessing the content
* (body) of the message.
* @exception MessagingException
@@ -240,7 +240,7 @@
* @exception IOException
* @exception MessagingException
*/
- public void writeTo(OutputStream out) throws IOException, MessagingException {
+ public void writeTo(OutputStream out) throws IOException, MessagingException {
// no content loaded yet?
if (content == null) {
// make sure we're still valid
@@ -248,26 +248,26 @@
// make sure the content is fully loaded
loadContent();
}
-
+
loadHeaders();
-
+
Enumeration e = headers.getAllHeaderLines();
while(e.hasMoreElements()) {
String line = (String)e.nextElement();
- out.write(line.getBytes());
+ out.write(line.getBytes("ISO8859-1"));
out.write(CRLF);
}
out.write(CRLF);
out.write(CRLF);
out.write(content);
}
-
+
/******************************************************************
- * Following is a set of methods that deal with information in the
- * envelope. These methods ensure the enveloper is loaded and
- * retrieve the information.
+ * Following is a set of methods that deal with information in the
+ * envelope. These methods ensure the enveloper is loaded and
+ * retrieve the information.
********************************************************************/
-
+
/**
* Get the message "From" addresses. This looks first at the
@@ -281,14 +281,14 @@
public Address[] getFrom() throws MessagingException {
// make sure we've retrieved the envelope information.
loadEnvelope();
- // make sure we return a copy of the array so this can't be changed.
- Address[] addresses = envelope.from;
+ // make sure we return a copy of the array so this can't be changed.
+ Address[] addresses = envelope.from;
if (addresses == null) {
return null;
}
- return (Address[])addresses.clone();
+ return (Address[])addresses.clone();
}
-
+
/**
* Return the "Sender" header as an address.
@@ -299,13 +299,13 @@
public Address getSender() throws MessagingException {
// make sure we've retrieved the envelope information.
loadEnvelope();
- // make sure we return a copy of the array so this can't be changed.
- Address[] addresses = envelope.sender;
+ // make sure we return a copy of the array so this can't be changed.
+ Address[] addresses = envelope.sender;
if (addresses == null) {
return null;
}
// There's only a single sender, despite IMAP potentially returning a list
- return addresses[0];
+ return addresses[0];
}
/**
@@ -325,26 +325,26 @@
public Address[] getRecipients(Message.RecipientType type) throws MessagingException {
// make sure we've retrieved the envelope information.
loadEnvelope();
- Address[] addresses = null;
-
+ Address[] addresses = null;
+
if (type == Message.RecipientType.TO) {
- addresses = envelope.to;
+ addresses = envelope.to;
}
else if (type == Message.RecipientType.CC) {
- addresses = envelope.cc;
+ addresses = envelope.cc;
}
else if (type == Message.RecipientType.BCC) {
- addresses = envelope.bcc;
+ addresses = envelope.bcc;
}
else {
- // this could be a newsgroup type, which will tickle the message headers.
+ // this could be a newsgroup type, which will tickle the message headers.
return super.getRecipients(type);
}
- // make sure we return a copy of the array so this can't be changed.
+ // make sure we return a copy of the array so this can't be changed.
if (addresses == null) {
return null;
}
- return (Address[])addresses.clone();
+ return (Address[])addresses.clone();
}
/**
@@ -358,12 +358,12 @@
public Address[] getReplyTo() throws MessagingException {
// make sure we've retrieved the envelope information.
loadEnvelope();
- // make sure we return a copy of the array so this can't be changed.
- Address[] addresses = envelope.replyTo;
+ // make sure we return a copy of the array so this can't be changed.
+ Address[] addresses = envelope.replyTo;
if (addresses == null) {
return null;
}
- return (Address[])addresses.clone();
+ return (Address[])addresses.clone();
}
/**
@@ -378,16 +378,16 @@
public String getSubject() throws MessagingException {
// make sure we've retrieved the envelope information.
loadEnvelope();
-
+
if (envelope.subject == null) {
- return null;
+ return null;
}
- // the subject could be encoded. If there is a decoding error,
- // return the raw subject string.
+ // the subject could be encoded. If there is a decoding error,
+ // return the raw subject string.
try {
- return MimeUtility.decodeText(envelope.subject);
+ return MimeUtility.decodeText(envelope.subject);
} catch (UnsupportedEncodingException e) {
- return envelope.subject;
+ return envelope.subject;
}
}
@@ -401,8 +401,8 @@
public Date getSentDate() throws MessagingException {
// make sure we've retrieved the envelope information.
loadEnvelope();
- // just return that directly
- return envelope.date;
+ // just return that directly
+ return envelope.date;
}
@@ -414,7 +414,7 @@
*/
public Date getReceivedDate() throws MessagingException {
loadEnvelope();
- return receivedDate;
+ return receivedDate;
}
@@ -426,12 +426,12 @@
* @exception MessagingException
*/
public int getSize() throws MessagingException {
- // make sure we've retrieved the envelope information. We load the
- // size when we retrieve that.
+ // make sure we've retrieved the envelope information. We load the
+ // size when we retrieve that.
loadEnvelope();
- return size;
+ return size;
}
-
+
/**
* Get a line count for the IMAP message. This is potentially
@@ -443,7 +443,7 @@
*/
public int getLineCount() throws MessagingException {
loadBodyStructure();
- return bodyStructure.lines;
+ return bodyStructure.lines;
}
/**
@@ -467,7 +467,7 @@
*/
public String getContentType() throws MessagingException {
loadBodyStructure();
- return bodyStructure.mimeType.toString();
+ return bodyStructure.mimeType.toString();
}
@@ -482,7 +482,7 @@
*/
public boolean isMimeType(String type) throws MessagingException {
loadBodyStructure();
- return bodyStructure.mimeType.match(type);
+ return bodyStructure.mimeType.match(type);
}
/**
@@ -496,9 +496,9 @@
public String getDisposition() throws MessagingException {
loadBodyStructure();
if (bodyStructure.disposition != null) {
- return bodyStructure.disposition.getDisposition();
+ return bodyStructure.disposition.getDisposition();
}
- return null;
+ return null;
}
/**
@@ -510,7 +510,7 @@
*/
public String getEncoding() throws MessagingException {
loadBodyStructure();
- return bodyStructure.transferEncoding;
+ return bodyStructure.transferEncoding;
}
/**
@@ -522,95 +522,95 @@
*/
public String getContentID() throws MessagingException {
loadBodyStructure();
- return bodyStructure.contentID;
+ return bodyStructure.contentID;
}
public String getContentMD5() throws MessagingException {
loadBodyStructure();
- return bodyStructure.md5Hash;
+ return bodyStructure.md5Hash;
}
-
-
+
+
public String getDescription() throws MessagingException {
loadBodyStructure();
-
+
if (bodyStructure.contentDescription == null) {
- return null;
+ return null;
}
- // the subject could be encoded. If there is a decoding error,
- // return the raw subject string.
+ // the subject could be encoded. If there is a decoding error,
+ // return the raw subject string.
try {
- return MimeUtility.decodeText(bodyStructure.contentDescription);
+ return MimeUtility.decodeText(bodyStructure.contentDescription);
} catch (UnsupportedEncodingException e) {
return bodyStructure.contentDescription;
}
}
/**
- * Return the content languages associated with this
+ * Return the content languages associated with this
* message.
- *
- * @return
+ *
+ * @return
* @exception MessagingException
*/
public String[] getContentLanguage() throws MessagingException {
loadBodyStructure();
-
+
if (!bodyStructure.languages.isEmpty()) {
- return (String[])bodyStructure.languages.toArray(new String[bodyStructure.languages.size()]);
+ return (String[])bodyStructure.languages.toArray(new String[bodyStructure.languages.size()]);
}
- return null;
+ return null;
}
public String getMessageID() throws MessagingException {
loadEnvelope();
- return envelope.messageID;
+ return envelope.messageID;
}
-
+
public void setFrom(Address address) throws MessagingException {
throw new IllegalWriteException("IMAP messages are read-only");
}
-
+
public void addFrom(Address[] address) throws MessagingException {
throw new IllegalWriteException("IMAP messages are read-only");
}
-
+
public void setSender(Address address) throws MessagingException {
throw new IllegalWriteException("IMAP messages are read-only");
}
-
+
public void setRecipients(Message.RecipientType type, Address[] addresses) throws MessagingException {
throw new IllegalWriteException("IMAP messages are read-only");
}
-
+
public void setRecipients(Message.RecipientType type, String address) throws MessagingException {
throw new IllegalWriteException("IMAP messages are read-only");
}
-
+
public void addRecipients(Message.RecipientType type, Address[] address) throws MessagingException {
throw new IllegalWriteException("IMAP messages are read-only");
}
-
+
public void setReplyTo(Address[] address) throws MessagingException {
throw new IllegalWriteException("IMAP messages are read-only");
}
-
+
public void setSubject(String subject) throws MessagingException {
throw new IllegalWriteException("IMAP messages are read-only");
}
-
+
public void setSubject(String subject, String charset) throws MessagingException {
throw new IllegalWriteException("IMAP messages are read-only");
}
-
+
public void setSentDate(Date sent) throws MessagingException {
throw new IllegalWriteException("IMAP messages are read-only");
}
-
+
public void setDisposition(String disposition) throws MessagingException {
throw new IllegalWriteException("IMAP messages are read-only");
}
-
+
public void setContentID(String cid) throws MessagingException {
throw new IllegalWriteException("IMAP messages are read-only");
}
@@ -622,7 +622,7 @@
public void setDescription(String description) throws MessagingException {
throw new IllegalWriteException("IMAP messages are read-only");
}
-
+
public void setDescription(String description, String charset) throws MessagingException {
throw new IllegalWriteException("IMAP messages are read-only");
}
@@ -630,7 +630,7 @@
public void setContentLanguage(String[] languages) throws MessagingException {
throw new IllegalWriteException("IMAP messages are read-only");
}
-
+
/******************************************************************
* Following is a set of methods that deal with headers
@@ -753,7 +753,7 @@
* @exception MessagingException
*/
public synchronized DataHandler getDataHandler() throws MessagingException {
- // check the validity and make sure we have the body structure information.
+ // check the validity and make sure we have the body structure information.
checkValidity();
loadBodyStructure();
if (dh == null) {
@@ -763,8 +763,8 @@
return dh;
}
else if (bodyStructure.isAttachedMessage()) {
- dh = new DataHandler(new IMAPAttachedMessage(this, section, bodyStructure.nestedEnvelope, bodyStructure.nestedBody),
- bodyStructure.mimeType.toString());
+ dh = new DataHandler(new IMAPAttachedMessage(this, section, bodyStructure.nestedEnvelope, bodyStructure.nestedBody),
+ bodyStructure.mimeType.toString());
return dh;
}
}
@@ -789,32 +789,32 @@
headers = new InternetHeaders(in);
allHeadersRetrieved = true;
}
-
+
/**
- * Load the flag set for this message from the server.
- *
+ * Load the flag set for this message from the server.
+ *
* @exception MessagingeException
*/
public void loadFlags() throws MessagingException {
// make sure this is in a valid state.
checkValidity();
- // if the flags are already loaded, nothing to do
+ // if the flags are already loaded, nothing to do
if (flags != null) {
- return;
+ return;
}
- // we need to ensure that we're the only ones with access to the folder's
- // message cache any time we need to talk to the server. This needs to be
- // held until after we release the connection so that any pending EXPUNGE
- // untagged responses are processed before the next time the folder connection is
- // used.
+ // we need to ensure that we're the only ones with access to the folder's
+ // message cache any time we need to talk to the server. This needs to be
+ // held until after we release the connection so that any pending EXPUNGE
+ // untagged responses are processed before the next time the folder connection is
+ // used.
synchronized (folder) {
IMAPConnection connection = getConnection();
try {
- // fetch the flags for this item.
- flags = connection.fetchFlags(sequenceNumber);
+ // fetch the flags for this item.
+ flags = connection.fetchFlags(sequenceNumber);
} finally {
- releaseConnection(connection);
+ releaseConnection(connection);
}
}
}
@@ -833,21 +833,21 @@
// make sure this is in a valid state.
checkValidity();
- // we need to ensure that we're the only ones with access to the folder's
- // message cache any time we need to talk to the server. This needs to be
- // held until after we release the connection so that any pending EXPUNGE
- // untagged responses are processed before the next time the folder connection is
- // used.
+ // we need to ensure that we're the only ones with access to the folder's
+ // message cache any time we need to talk to the server. This needs to be
+ // held until after we release the connection so that any pending EXPUNGE
+ // untagged responses are processed before the next time the folder connection is
+ // used.
synchronized (folder) {
IMAPConnection connection = getConnection();
try {
- // get the headers and set
+ // get the headers and set
headers = connection.fetchHeaders(sequenceNumber, section);
- // we have the entire header set, not just a subset.
- allHeadersRetrieved = true;
+ // we have the entire header set, not just a subset.
+ allHeadersRetrieved = true;
} finally {
- releaseConnection(connection);
+ releaseConnection(connection);
}
}
}
@@ -858,7 +858,7 @@
* information.
*
* @exception MessagingException
- */
+ */
protected synchronized void loadEnvelope() throws MessagingException {
// don't retrieve if already loaded.
if (envelope != null) {
@@ -867,28 +867,28 @@
// make sure this is in a valid state.
checkValidity();
- // we need to ensure that we're the only ones with access to the folder's
- // message cache any time we need to talk to the server. This needs to be
- // held until after we release the connection so that any pending EXPUNGE
- // untagged responses are processed before the next time the folder connection is
- // used.
+ // we need to ensure that we're the only ones with access to the folder's
+ // message cache any time we need to talk to the server. This needs to be
+ // held until after we release the connection so that any pending EXPUNGE
+ // untagged responses are processed before the next time the folder connection is
+ // used.
synchronized (folder) {
IMAPConnection connection = getConnection();
try {
// fetch the envelope information for this
List fetches = connection.fetchEnvelope(sequenceNumber);
- // now process all of the fetch responses before releasing the folder lock.
- // it's possible that an unsolicited update on another thread might try to
- // make an update, causing a potential deadlock.
+ // now process all of the fetch responses before releasing the folder lock.
+ // it's possible that an unsolicited update on another thread might try to
+ // make an update, causing a potential deadlock.
for (int i = 0; i < fetches.size(); i++) {
// get the returned data items from each of the fetch responses
- // and process.
+ // and process.
IMAPFetchResponse fetch = (IMAPFetchResponse)fetches.get(i);
- // update the internal info
- updateMessageInformation(fetch);
+ // update the internal info
+ updateMessageInformation(fetch);
}
} finally {
- releaseConnection(connection);
+ releaseConnection(connection);
}
}
}
@@ -901,8 +901,8 @@
* @exception MessagingException
*/
protected synchronized void updateEnvelope(IMAPEnvelope envelope) throws MessagingException {
- // set the envelope item
- this.envelope = envelope;
+ // set the envelope item
+ this.envelope = envelope;
// copy header type information from the envelope into the headers.
updateHeader("From", envelope.from);
@@ -933,24 +933,24 @@
// make sure this is in a valid state.
checkValidity();
- // we need to ensure that we're the only ones with access to the folder's
- // message cache any time we need to talk to the server. This needs to be
- // held until after we release the connection so that any pending EXPUNGE
- // untagged responses are processed before the next time the folder connection is
- // used.
+ // we need to ensure that we're the only ones with access to the folder's
+ // message cache any time we need to talk to the server. This needs to be
+ // held until after we release the connection so that any pending EXPUNGE
+ // untagged responses are processed before the next time the folder connection is
+ // used.
synchronized (folder) {
IMAPConnection connection = getConnection();
try {
// fetch the envelope information for this
bodyStructure = connection.fetchBodyStructure(sequenceNumber);
- // go update all of the information
+ // go update all of the information
} finally {
- releaseConnection(connection);
+ releaseConnection(connection);
}
-
- // update this before we release the folder lock so we can avoid
- // deadlock.
- updateBodyStructure(bodyStructure);
+
+ // update this before we release the folder lock so we can avoid
+ // deadlock.
+ updateBodyStructure(bodyStructure);
}
}
@@ -961,9 +961,9 @@
* @exception MessagingException
*/
protected synchronized void updateBodyStructure(IMAPBodyStructure structure) throws MessagingException {
- // save the reference.
- bodyStructure = structure;
- // now update various headers with the information from the body structure
+ // save the reference.
+ bodyStructure = structure;
+ // now update various headers with the information from the body structure
// now update header information with the body structure data.
if (bodyStructure.lines != -1) {
@@ -972,9 +972,9 @@
// languages are a little more complicated
if (bodyStructure.languages != null) {
- // this is a duplicate of what happens in the super class, but
- // the superclass methods call setHeader(), which we override and
- // throw an exception for. We need to set the headers ourselves.
+ // this is a duplicate of what happens in the super class, but
+ // the superclass methods call setHeader(), which we override and
+ // throw an exception for. We need to set the headers ourselves.
if (bodyStructure.languages.size() == 1) {
updateHeader("Content-Language", (String)bodyStructure.languages.get(0));
}
@@ -1010,24 +1010,24 @@
if (content != null) {
return;
}
-
- // we need to ensure that we're the only ones with access to the folder's
- // message cache any time we need to talk to the server. This needs to be
- // held until after we release the connection so that any pending EXPUNGE
- // untagged responses are processed before the next time the folder connection is
- // used.
+
+ // we need to ensure that we're the only ones with access to the folder's
+ // message cache any time we need to talk to the server. This needs to be
+ // held until after we release the connection so that any pending EXPUNGE
+ // untagged responses are processed before the next time the folder connection is
+ // used.
synchronized (folder) {
IMAPConnection connection = getConnection();
try {
- // load the content from the server.
- content = connection.fetchContent(getSequenceNumber(), section);
+ // load the content from the server.
+ content = connection.fetchContent(getSequenceNumber(), section);
} finally {
- releaseConnection(connection);
+ releaseConnection(connection);
}
}
}
-
+
/**
* Retrieve the sequence number assigned to this message.
*
@@ -1037,16 +1037,16 @@
int getSequenceNumber() {
return sequenceNumber;
}
-
+
/**
- * Set the sequence number for the message. This
- * is updated whenever messages get expunged from
- * the folder.
- *
+ * Set the sequence number for the message. This
+ * is updated whenever messages get expunged from
+ * the folder.
+ *
* @param s The new sequence number.
*/
void setSequenceNumber(int s) {
- sequenceNumber = s;
+ sequenceNumber = s;
}
@@ -1068,7 +1068,7 @@
this.uid = uid;
}
-
+
/**
* get the current connection pool attached to the folder. We need
* to do this dynamically, to A) ensure we're only accessing an
@@ -1081,11 +1081,11 @@
// the folder owns everything.
return ((IMAPFolder)folder).getMessageConnection();
}
-
+
/**
- * Release the connection back to the Folder after performing an operation
+ * Release the connection back to the Folder after performing an operation
* that requires a connection.
- *
+ *
* @param connection The previously acquired connection.
*/
protected void releaseConnection(IMAPConnection connection) throws MessagingException {
@@ -1102,7 +1102,7 @@
* @exception MessagingException
*/
protected void checkValidity() throws MessagingException {
- checkValidity(false);
+ checkValidity(false);
}
@@ -1114,24 +1114,24 @@
* @exception MessagingException
*/
protected void checkValidity(boolean update) throws MessagingException {
- // we need to ensure that we're the only ones with access to the folder's
- // message cache any time we need to talk to the server. This needs to be
- // held until after we release the connection so that any pending EXPUNGE
- // untagged responses are processed before the next time the folder connection is
- // used.
+ // we need to ensure that we're the only ones with access to the folder's
+ // message cache any time we need to talk to the server. This needs to be
+ // held until after we release the connection so that any pending EXPUNGE
+ // untagged responses are processed before the next time the folder connection is
+ // used.
if (update) {
synchronized (folder) {
// have the connection update the folder status. This might result in this message
// changing its state to expunged. It might also result in an exception if the
// folder has been closed.
- IMAPConnection connection = getConnection();
+ IMAPConnection connection = getConnection();
try {
connection.updateMailboxStatus();
} finally {
- // this will force any expunged messages to be processed before we release
- // the lock.
- releaseConnection(connection);
+ // this will force any expunged messages to be processed before we release
+ // the lock.
+ releaseConnection(connection);
}
}
}
@@ -1141,160 +1141,160 @@
throw new MessageRemovedException("Illegal opertion on a deleted message");
}
}
-
-
+
+
/**
- * Evaluate whether this message requires any of the information
- * in a FetchProfile to be fetched from the server. If the messages
+ * Evaluate whether this message requires any of the information
+ * in a FetchProfile to be fetched from the server. If the messages
* already contains the information in the profile, it returns false.
- * This allows IMAPFolder to optimize fetch() requests to just the
+ * This allows IMAPFolder to optimize fetch() requests to just the
* messages that are missing any of the requested information.
- *
- * NOTE: If any of the items in the profile are missing, then this
- * message will be updated with ALL of the items.
- *
+ *
+ * NOTE: If any of the items in the profile are missing, then this
+ * message will be updated with ALL of the items.
+ *
* @param profile The FetchProfile indicating the information that should be prefetched.
- *
- * @return true if any of the profile information requires fetching. false if this
+ *
+ * @return true if any of the profile information requires fetching. false if this
* message already contains the given information.
*/
protected boolean evaluateFetch(FetchProfile profile) {
// the fetch profile can contain a number of different item types. Validate
- // whether we need any of these and return true on the first mismatch.
-
- // the UID is a common fetch request, put it first.
+ // whether we need any of these and return true on the first mismatch.
+
+ // the UID is a common fetch request, put it first.
if (profile.contains(UIDFolder.FetchProfileItem.UID) && uid == -1) {
- return true;
+ return true;
}
if (profile.contains(FetchProfile.Item.ENVELOPE) && envelope == null) {
- return true;
+ return true;
}
if (profile.contains(FetchProfile.Item.FLAGS) && flags == null) {
- return true;
+ return true;
}
if (profile.contains(FetchProfile.Item.CONTENT_INFO) && bodyStructure == null) {
- return true;
+ return true;
}
- // The following profile items are our implementation of items that the
- // Sun IMAPFolder implementation supports.
+ // The following profile items are our implementation of items that the
+ // Sun IMAPFolder implementation supports.
if (profile.contains(IMAPFolder.FetchProfileItem.HEADERS) && !allHeadersRetrieved) {
- return true;
+ return true;
}
if (profile.contains(IMAPFolder.FetchProfileItem.SIZE) && bodyStructure.bodySize < 0) {
- return true;
+ return true;
}
- // last bit after checking each of the information types is to see if
- // particular headers have been requested and whether those are on the
- // set we do have loaded.
- String [] requestedHeaders = profile.getHeaderNames();
-
- // ok, any missing header in the list is enough to force us to request the
- // information.
+ // last bit after checking each of the information types is to see if
+ // particular headers have been requested and whether those are on the
+ // set we do have loaded.
+ String [] requestedHeaders = profile.getHeaderNames();
+
+ // ok, any missing header in the list is enough to force us to request the
+ // information.
for (int i = 0; i < requestedHeaders.length; i++) {
if (headers.getHeader(requestedHeaders[i]) == null) {
- return true;
+ return true;
}
}
- // this message, at least, does not need anything fetched.
- return false;
+ // this message, at least, does not need anything fetched.
+ return false;
}
-
+
/**
- * Update a message instance with information retrieved via an IMAP FETCH
+ * Update a message instance with information retrieved via an IMAP FETCH
* command. The command response for this message may contain multiple pieces
* that we need to process.
- *
+ *
* @param response The response line, which may contain multiple data items.
- *
+ *
* @exception MessagingException
*/
void updateMessageInformation(IMAPFetchResponse response) throws MessagingException {
- // get the list of data items associated with this response. We can have
- // a large number of items returned in a single update.
- List items = response.getDataItems();
-
+ // get the list of data items associated with this response. We can have
+ // a large number of items returned in a single update.
+ List items = response.getDataItems();
+
for (int i = 0; i < items.size(); i++) {
- IMAPFetchDataItem item = (IMAPFetchDataItem)items.get(i);
-
+ IMAPFetchDataItem item = (IMAPFetchDataItem)items.get(i);
+
switch (item.getType()) {
- // if the envelope has been requested, we'll end up with all of these items.
+ // if the envelope has been requested, we'll end up with all of these items.
case IMAPFetchDataItem.ENVELOPE:
- // update the envelope and map the envelope items into the headers.
+ // update the envelope and map the envelope items into the headers.
updateEnvelope((IMAPEnvelope)item);
break;
case IMAPFetchDataItem.INTERNALDATE:
receivedDate = ((IMAPInternalDate)item).getDate();;
break;
case IMAPFetchDataItem.SIZE:
- size = ((IMAPMessageSize)item).size;
+ size = ((IMAPMessageSize)item).size;
break;
case IMAPFetchDataItem.UID:
- uid = ((IMAPUid)item).uid;
- // make sure the folder knows about the UID update.
- ((IMAPFolder)folder).addToUidCache(new Long(uid), this);
- break;
- case IMAPFetchDataItem.BODYSTRUCTURE:
- updateBodyStructure((IMAPBodyStructure)item);
- break;
- // a partial or full header update
+ uid = ((IMAPUid)item).uid;
+ // make sure the folder knows about the UID update.
+ ((IMAPFolder)folder).addToUidCache(new Long(uid), this);
+ break;
+ case IMAPFetchDataItem.BODYSTRUCTURE:
+ updateBodyStructure((IMAPBodyStructure)item);
+ break;
+ // a partial or full header update
case IMAPFetchDataItem.HEADER:
{
- // if we've fetched the complete set, then replace what we have
- IMAPInternetHeader h = (IMAPInternetHeader)item;
+ // if we've fetched the complete set, then replace what we have
+ IMAPInternetHeader h = (IMAPInternetHeader)item;
if (h.isComplete()) {
- // we've got a complete header set now.
- this.headers = h.headers;
- allHeadersRetrieved = true;
+ // we've got a complete header set now.
+ this.headers = h.headers;
+ allHeadersRetrieved = true;
}
else {
- // need to merge the requested headers in with
- // our existing set. We need to be careful, since we
- // don't want to add duplicates.
- mergeHeaders(h.headers);
+ // need to merge the requested headers in with
+ // our existing set. We need to be careful, since we
+ // don't want to add duplicates.
+ mergeHeaders(h.headers);
}
}
default:
}
}
}
-
-
+
+
/**
- * Merge a subset of the requested headers with our existing partial set.
- * The new set will contain all headers requested from the server, plus
+ * Merge a subset of the requested headers with our existing partial set.
+ * The new set will contain all headers requested from the server, plus
* any of our existing headers that were not included in the retrieved set.
- *
+ *
* @param newHeaders The retrieved set of headers.
*/
protected synchronized void mergeHeaders(InternetHeaders newHeaders) {
- // This is sort of tricky to manage. The input headers object is a fresh set
+ // This is sort of tricky to manage. The input headers object is a fresh set
// retrieved from the server, but it's a subset of the headers. Our existing set
- // might not be complete, but it may contain duplicates of information in the
- // retrieved set, plus headers that are not in the retrieved set. To keep from
- // adding duplicates, we'll only add headers that are not in the retrieved set to
- // that set.
-
- // start by running through the list of headers
- Enumeration e = headers.getAllHeaders();
-
+ // might not be complete, but it may contain duplicates of information in the
+ // retrieved set, plus headers that are not in the retrieved set. To keep from
+ // adding duplicates, we'll only add headers that are not in the retrieved set to
+ // that set.
+
+ // start by running through the list of headers
+ Enumeration e = headers.getAllHeaders();
+
while (e.hasMoreElements()) {
- Header header = (Header)e.nextElement();
- // if there are no headers with this name in the new set, then
- // we can add this. Note that to add the header, we need to
- // retrieve all instances by this name and add them as a unit.
- // When we hit one of the duplicates again with the enumeration,
- // we'll skip it then because the merge target will have everything.
+ Header header = (Header)e.nextElement();
+ // if there are no headers with this name in the new set, then
+ // we can add this. Note that to add the header, we need to
+ // retrieve all instances by this name and add them as a unit.
+ // When we hit one of the duplicates again with the enumeration,
+ // we'll skip it then because the merge target will have everything.
if (newHeaders.getHeader(header.getName()) == null) {
- // get all occurrences of this name and stuff them into the
- // new list
- String name = header.getName();
- String[] a = headers.getHeader(name);
+ // get all occurrences of this name and stuff them into the
+ // new list
+ String name = header.getName();
+ String[] a = headers.getHeader(name);
for (int i = 0; i < a.length; i++) {
- newHeaders.addHeader(name, a[i]);
+ newHeaders.addHeader(name, a[i]);
}
}
}
// and replace the current header set
- headers = newHeaders;
+ headers = newHeaders;
}
}
diff --git a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/connection/IMAPCommand.java b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/connection/IMAPCommand.java
index 705dedf..d49b513 100644
--- a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/connection/IMAPCommand.java
+++ b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/connection/IMAPCommand.java
@@ -28,7 +28,7 @@
import java.util.List;
import java.util.Vector;
-import javax.mail.FetchProfile;
+import javax.mail.FetchProfile;
import javax.mail.Flags;
import javax.mail.Message;
import javax.mail.MessagingException;
@@ -58,10 +58,10 @@
import javax.mail.search.StringTerm;
import javax.mail.search.SubjectTerm;
-import org.apache.geronimo.javamail.store.imap.ACL;
+import org.apache.geronimo.javamail.store.imap.ACL;
import org.apache.geronimo.javamail.store.imap.IMAPFolder;
-import org.apache.geronimo.javamail.store.imap.Rights;
-import org.apache.geronimo.javamail.store.imap.connection.IMAPResponseTokenizer.Token;
+import org.apache.geronimo.javamail.store.imap.Rights;
+import org.apache.geronimo.javamail.store.imap.connection.IMAPResponseTokenizer.Token;
import org.apache.geronimo.javamail.util.CommandFailedException;
@@ -89,127 +89,127 @@
'7', '8', '9',
'+', ','
};
-
+
protected boolean needWhiteSpace = false;
// our utility writer stream
protected DataOutputStream out;
// the real output target
protected ByteArrayOutputStream sink;
- // our command segment set. If the command contains literals, then the literal
- // data must be sent after receiving an continue response back from the server.
- protected List segments = null;
- // the append tag for the response
- protected String tag;
-
+ // our command segment set. If the command contains literals, then the literal
+ // data must be sent after receiving an continue response back from the server.
+ protected List segments = null;
+ // the append tag for the response
+ protected String tag;
+
// our counter used to generate command tags.
static protected int tagCounter = 0;
/**
- * Create an empty command.
+ * Create an empty command.
*/
public IMAPCommand() {
try {
sink = new ByteArrayOutputStream();
out = new DataOutputStream(sink);
- // write the tag data at the beginning of the command.
- out.writeBytes(getTag());
- // need a blank separator
- out.write(' ');
+ // write the tag data at the beginning of the command.
+ out.writeBytes(getTag());
+ // need a blank separator
+ out.write(' ');
} catch (IOException e ) {
}
}
/**
* Create a command with an initial command string.
- *
+ *
* @param command The command string used to start this command.
*/
public IMAPCommand(String command) {
- this();
- append(command);
+ this();
+ append(command);
}
-
+
public String getTag() {
if (tag == null) {
// the tag needs to be non-numeric, so tack a convenient alpha character on the front.
tag = "a" + tagCounter++;
}
- return tag;
+ return tag;
}
-
-
+
+
/**
- * Save the current segment of the command we've accumulated. This
- * generally occurs because we have a literal element in the command
- * that's going to require a continuation response from the server before
- * we can send it.
+ * Save the current segment of the command we've accumulated. This
+ * generally occurs because we have a literal element in the command
+ * that's going to require a continuation response from the server before
+ * we can send it.
*/
- private void saveCurrentSegment()
+ private void saveCurrentSegment()
{
try {
- out.flush(); // make sure everything is written
- // get the data so far and reset the sink
- byte[] segment = sink.toByteArray();
- sink.reset();
- // most commands don't have segments, so don't create the list until we do.
+ out.flush(); // make sure everything is written
+ // get the data so far and reset the sink
+ byte[] segment = sink.toByteArray();
+ sink.reset();
+ // most commands don't have segments, so don't create the list until we do.
if (segments == null) {
- segments = new ArrayList();
+ segments = new ArrayList();
}
- // ok, we need to issue this command as a conversation.
+ // ok, we need to issue this command as a conversation.
segments.add(segment);
} catch (IOException e) {
}
}
-
-
+
+
/**
- * Write all of the command data to the stream. This includes the
- * leading tag data.
- *
+ * Write all of the command data to the stream. This includes the
+ * leading tag data.
+ *
* @param outStream
* @param connection
- *
+ *
* @exception IOException
* @exception MessagingException
*/
public void writeTo(OutputStream outStream, IMAPConnection connection) throws IOException, MessagingException
{
-
+
// just a simple, single string-encoded command?
if (segments == null) {
// make sure the output stream is flushed
- out.flush();
- // just copy the command data to the output stream
- sink.writeTo(outStream);
- // we need to end the command with a CRLF sequence.
+ out.flush();
+ // just copy the command data to the output stream
+ sink.writeTo(outStream);
+ // we need to end the command with a CRLF sequence.
outStream.write('\r');
outStream.write('\n');
}
- // multiple-segment mode, which means we need to deal with continuation responses at
- // each of the literal boundaries.
- else {
- // at this point, we have a list of command pieces that must be written out, then a
- // continuation response checked for after each write. Once each of these pieces is
- // written out, we still have command stuff pending in the out stream, which we'll tack
- // on to the end.
+ // multiple-segment mode, which means we need to deal with continuation responses at
+ // each of the literal boundaries.
+ else {
+ // at this point, we have a list of command pieces that must be written out, then a
+ // continuation response checked for after each write. Once each of these pieces is
+ // written out, we still have command stuff pending in the out stream, which we'll tack
+ // on to the end.
for (int i = 0; i < segments.size(); i++) {
- outStream.write((byte [])segments.get(i));
- // now wait for a response from the connection. We should be getting a
- // continuation response back (and might have also received some asynchronous
- // replies, which we'll leave in the queue for now. If we get some status back
- // other than than a continue, we've got an error in our command somewhere.
- IMAPTaggedResponse response = connection.receiveResponse();
+ outStream.write((byte [])segments.get(i));
+ // now wait for a response from the connection. We should be getting a
+ // continuation response back (and might have also received some asynchronous
+ // replies, which we'll leave in the queue for now. If we get some status back
+ // other than than a continue, we've got an error in our command somewhere.
+ IMAPTaggedResponse response = connection.receiveResponse();
if (!response.isContinuation()) {
- throw new CommandFailedException("Error response received on a IMAP continued command: " + response);
+ throw new CommandFailedException("Error response received on a IMAP continued command: " + response);
}
}
out.flush();
- // all leading segments written with the appropriate continuation received in reply.
- // just copy the command data to the output stream
- sink.writeTo(outStream);
- // we need to end the command with a CRLF sequence.
+ // all leading segments written with the appropriate continuation received in reply.
+ // just copy the command data to the output stream
+ sink.writeTo(outStream);
+ // we need to end the command with a CRLF sequence.
outStream.write('\r');
outStream.write('\n');
}
@@ -224,7 +224,7 @@
*/
public void append(String value) {
try {
- // add the bytes direcly
+ // add the bytes direcly
out.writeBytes(value);
// assume we're needing whitespace after this (pretty much unknown).
needWhiteSpace = true;
@@ -242,20 +242,26 @@
* @param value The value to append.
*/
public void appendString(String value) {
- // work off the byte values
- appendString(value.getBytes());
+ try {
+ // work off the byte values
+ appendString(value.getBytes("ISO8859-1"));
+ } catch (UnsupportedEncodingException e) {
+ }
}
/**
* Append a string value to a command buffer. This always appends as
* a QUOTEDSTRING
- *
+ *
* @param value The value to append.
*/
public void appendQuotedString(String value) {
- // work off the byte values
- appendQuotedString(value.getBytes());
+ try {
+ // work off the byte values
+ appendQuotedString(value.getBytes("ISO8859-1"));
+ } catch (UnsupportedEncodingException e) {
+ }
}
@@ -270,11 +276,14 @@
public void appendEncodedString(String value) {
// encode first.
value = encode(value);
- // work off the byte values
- appendString(value.getBytes());
+ try {
+ // work off the byte values
+ appendString(value.getBytes("ISO8859-1"));
+ } catch (UnsupportedEncodingException e) {
+ }
}
-
+
/**
* Encode a string using the modified UTF-7 encoding.
*
@@ -354,7 +363,7 @@
// convert the encoded string.
return result.toString();
}
-
+
/**
* Encode a single buffer of characters. This buffer will have
@@ -428,15 +437,18 @@
*/
public void appendString(String value, String charset) throws MessagingException {
if (charset == null) {
- // work off the byte values
- appendString(value.getBytes());
+ try {
+ // work off the byte values
+ appendString(value.getBytes("ISO8859-1"));
+ } catch (UnsupportedEncodingException e) {
+ }
}
else {
try {
// use the charset to extract the bytes
appendString(value.getBytes(charset));
- } catch (UnsupportedEncodingException e) {
throw new MessagingException("Invalid text encoding");
+ } catch (UnsupportedEncodingException e) {
}
}
}
@@ -467,20 +479,20 @@
/**
- * Append an integer value to the command, converting
+ * Append an integer value to the command, converting
* the integer into string form.
- *
+ *
* @param value The value to append.
*/
public void appendInteger(int value) {
appendAtom(Integer.toString(value));
}
-
+
/**
- * Append a long value to the command, converting
+ * Append a long value to the command, converting
* the integer into string form.
- *
+ *
* @param value The value to append.
*/
public void appendLong(long value) {
@@ -489,22 +501,25 @@
/**
- * Append an atom value to the command. Atoms are directly
- * appended without using literal encodings.
- *
+ * Append an atom value to the command. Atoms are directly
+ * appended without using literal encodings.
+ *
* @param value The value to append.
*/
public void appendAtom(String value) {
- appendAtom(value.getBytes());
+ try {
+ appendAtom(value.getBytes("ISO8859-1"));
+ } catch (UnsupportedEncodingException e) {
+ }
}
/**
- * Append an atom to the command buffer. Atoms are directly
- * appended without using literal encodings. White space is
- * accounted for with the append operation.
- *
+ * Append an atom to the command buffer. Atoms are directly
+ * appended without using literal encodings. White space is
+ * accounted for with the append operation.
+ *
* @param value The value to append.
*/
public void appendAtom(byte[] value) {
@@ -519,11 +534,11 @@
/**
- * Append an IMAP literal values to the command.
- * literals are written using a header with the length
- * specified, followed by a CRLF sequence, followed
- * by the literal data.
- *
+ * Append an IMAP literal values to the command.
+ * literals are written using a header with the length
+ * specified, followed by a CRLF sequence, followed
+ * by the literal data.
+ *
* @param value The literal data to write.
*/
public void appendLiteral(byte[] value) {
@@ -535,10 +550,10 @@
}
/**
- * Add a literal header to the buffer. The literal
- * header is the literal length enclosed in a
+ * Add a literal header to the buffer. The literal
+ * header is the literal length enclosed in a
* "{n}" pair, followed by a CRLF sequence.
- *
+ *
* @param size The size of the literal value.
*/
protected void appendLiteralHeader(int size) {
@@ -547,19 +562,19 @@
out.writeByte('{');
out.writeBytes(Integer.toString(size));
out.writeBytes("}\r\n");
- // the IMAP client is required to send literal data to the server by
- // writing the command up to the header, then waiting for a continuation
- // response to send the rest.
- saveCurrentSegment();
+ // the IMAP client is required to send literal data to the server by
+ // writing the command up to the header, then waiting for a continuation
+ // response to send the rest.
+ saveCurrentSegment();
} catch (IOException e) {
}
}
/**
- * Append literal data to the command where the
+ * Append literal data to the command where the
* literal sourcd is a ByteArrayOutputStream.
- *
+ *
* @param value The source of the literal data.
*/
public void appendLiteral(ByteArrayOutputStream value) {
@@ -572,10 +587,10 @@
}
/**
- * Write out a string of literal data, taking into
- * account the need to escape both '"' and '\'
+ * Write out a string of literal data, taking into
+ * account the need to escape both '"' and '\'
* characters.
- *
+ *
* @param value The bytes of the string to write.
*/
public void appendQuotedString(byte[] value) {
@@ -599,10 +614,10 @@
}
/**
- * Mark the start of a list value being written to
- * the command. A list is a sequences of different
- * tokens enclosed in "(" ")" pairs. Lists can
- * be nested.
+ * Mark the start of a list value being written to
+ * the command. A list is a sequences of different
+ * tokens enclosed in "(" ")" pairs. Lists can
+ * be nested.
*/
public void startList() {
try {
@@ -614,7 +629,7 @@
}
/**
- * Write out the end of the list.
+ * Write out the end of the list.
*/
public void endList() {
try {
@@ -626,9 +641,9 @@
/**
- * Add a whitespace character to the command if the
- * previous token was a type that required a
- * white space character to mark the boundary.
+ * Add a whitespace character to the command if the
+ * previous token was a type that required a
+ * white space character to mark the boundary.
*/
protected void conditionalWhitespace() {
try {
@@ -646,15 +661,15 @@
/**
* Append a body section specification to a command string. Body
* section specifications are of the form "[section]<start.count>".
- *
+ *
* @param section The section numeric identifier.
* @param partName The name of the body section we want (e.g. "TEST", "HEADERS").
*/
public void appendBodySection(String section, String partName) {
try {
- // we sometimes get called from the top level
+ // we sometimes get called from the top level
if (section == null) {
- appendBodySection(partName);
+ appendBodySection(partName);
return;
}
@@ -674,7 +689,7 @@
/**
* Append a body section specification to a command string. Body
* section specifications are of the form "[section]".
- *
+ *
* @param partName The partname we require.
*/
public void appendBodySection(String partName) {
@@ -758,8 +773,8 @@
// date_time strings need to be done as quoted strings because they contain blanks.
appendString(formatter.format(d));
}
-
-
+
+
/**
* append an IMAP search sequence from a SearchTerm. SearchTerms
* terms can be complex sets of terms in a tree form, so this
@@ -966,15 +981,15 @@
// we're going to generate this with parenthetical search keys, even if it is just a simple term.
appendAtom("OR");
- startList();
+ startList();
// generated OR argument 1
appendSearchTerm(terms[0], charset);
- endList();
- startList();
+ endList();
+ startList();
// generated OR argument 2
appendSearchTerm(terms[0], charset);
// and the closing parens
- endList();
+ endList();
}
@@ -987,11 +1002,11 @@
protected void appendNot(NotTerm term, String charset) throws MessagingException {
// we're goint to generate this with parenthetical search keys, even if it is just a simple term.
appendAtom("NOT");
- startList();
+ startList();
// generated the NOT expression
appendSearchTerm(term.getTerm(), charset);
// and the closing parens
- endList();
+ endList();
}
@@ -1348,114 +1363,114 @@
return false;
}
-
-
+
+
/**
* Append a FetchProfile information to an IMAPCommand
* that's to be issued.
- *
+ *
* @param profile The fetch profile we're using.
- *
+ *
* @exception MessagingException
*/
public void appendFetchProfile(FetchProfile profile) throws MessagingException {
- // the fetch profile items are a parenthtical list passed on a
- // FETCH command.
- startList();
+ // the fetch profile items are a parenthtical list passed on a
+ // FETCH command.
+ startList();
if (profile.contains(UIDFolder.FetchProfileItem.UID)) {
- appendAtom("UID");
+ appendAtom("UID");
}
if (profile.contains(FetchProfile.Item.ENVELOPE)) {
- // fetching the envelope involves several items
- appendAtom("ENVELOPE");
- appendAtom("INTERNALDATE");
- appendAtom("RFC822.SIZE");
+ // fetching the envelope involves several items
+ appendAtom("ENVELOPE");
+ appendAtom("INTERNALDATE");
+ appendAtom("RFC822.SIZE");
}
if (profile.contains(FetchProfile.Item.FLAGS)) {
- appendAtom("FLAGS");
+ appendAtom("FLAGS");
}
if (profile.contains(FetchProfile.Item.CONTENT_INFO)) {
- appendAtom("BODYSTRUCTURE");
+ appendAtom("BODYSTRUCTURE");
}
if (profile.contains(IMAPFolder.FetchProfileItem.SIZE)) {
- appendAtom("RFC822.SIZE");
+ appendAtom("RFC822.SIZE");
}
- // There are two choices here, that are sort of redundant.
- // if all headers have been requested, there's no point in
- // adding any specifically requested one.
+ // There are two choices here, that are sort of redundant.
+ // if all headers have been requested, there's no point in
+ // adding any specifically requested one.
if (profile.contains(IMAPFolder.FetchProfileItem.HEADERS)) {
- appendAtom("BODY.PEEK[HEADER]");
+ appendAtom("BODY.PEEK[HEADER]");
}
else {
- String[] headers = profile.getHeaderNames();
+ String[] headers = profile.getHeaderNames();
// have an actual list to retrieve? need to craft this as a sublist
- // of identified fields.
+ // of identified fields.
if (headers.length > 0) {
- appendAtom("BODY.PEEK[HEADER.FIELDS]");
- startList();
+ appendAtom("BODY.PEEK[HEADER.FIELDS]");
+ startList();
for (int i = 0; i < headers.length; i++) {
- appendAtom(headers[i]);
+ appendAtom(headers[i]);
}
- endList();
+ endList();
}
}
- // end the list.
- endList();
+ // end the list.
+ endList();
}
-
-
+
+
/**
- * Append an ACL value to a command. The ACL is the writes string name,
+ * Append an ACL value to a command. The ACL is the writes string name,
* followed by the rights value. This version uses no +/- modifier.
- *
+ *
* @param acl The ACL to append.
*/
public void appendACL(ACL acl) {
- appendACL(acl, null);
+ appendACL(acl, null);
}
-
+
/**
* Append an ACL value to a command. The ACL is the writes string name,
- * followed by the rights value. A +/- modifier can be added to the
- * // result.
- *
+ * followed by the rights value. A +/- modifier can be added to the
+ * // result.
+ *
* @param acl The ACL to append.
* @param modifier The modifer string (can be null).
*/
public void appendACL(ACL acl, String modifier) {
- appendString(acl.getName());
- String rights = acl.getRights().toString();
-
+ appendString(acl.getName());
+ String rights = acl.getRights().toString();
+
if (modifier != null) {
- rights = modifier + rights;
+ rights = modifier + rights;
}
- appendString(rights);
+ appendString(rights);
}
-
-
+
+
/**
- * Append a quota specification to an IMAP command.
- *
+ * Append a quota specification to an IMAP command.
+ *
* @param quota The quota value to append.
*/
public void appendQuota(Quota quota) {
- appendString(quota.quotaRoot);
- startList();
+ appendString(quota.quotaRoot);
+ startList();
for (int i = 0; i < quota.resources.length; i++) {
- appendQuotaResource(quota.resources[i]);
+ appendQuotaResource(quota.resources[i]);
}
- endList();
+ endList();
}
-
+
/**
- * Append a Quota.Resource element to an IMAP command. This converts as
- * the resoure name, the usage value and limit value).
- *
+ * Append a Quota.Resource element to an IMAP command. This converts as
+ * the resoure name, the usage value and limit value).
+ *
* @param resource The resource element we're appending.
*/
public void appendQuotaResource(Quota.Resource resource) {
- appendAtom(resource.name);
- // NB: For command purposes, only the limit is used.
+ appendAtom(resource.name);
+ // NB: For command purposes, only the limit is used.
appendLong(resource.limit);
}
}
diff --git a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/connection/IMAPConnection.java b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/connection/IMAPConnection.java
index d84ec69..b8f9186 100644
--- a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/connection/IMAPConnection.java
+++ b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/connection/IMAPConnection.java
@@ -37,7 +37,7 @@
import javax.mail.Address;
import javax.mail.AuthenticationFailedException;
-import javax.mail.FetchProfile;
+import javax.mail.FetchProfile;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Message;
@@ -52,17 +52,17 @@
import javax.mail.search.SearchTerm;
-import org.apache.geronimo.javamail.authentication.AuthenticatorFactory;
+import org.apache.geronimo.javamail.authentication.AuthenticatorFactory;
import org.apache.geronimo.javamail.authentication.ClientAuthenticator;
-import org.apache.geronimo.javamail.authentication.LoginAuthenticator;
-import org.apache.geronimo.javamail.authentication.PlainAuthenticator;
+import org.apache.geronimo.javamail.authentication.LoginAuthenticator;
+import org.apache.geronimo.javamail.authentication.PlainAuthenticator;
import org.apache.geronimo.javamail.store.imap.ACL;
-import org.apache.geronimo.javamail.store.imap.Rights;
+import org.apache.geronimo.javamail.store.imap.Rights;
-import org.apache.geronimo.javamail.util.CommandFailedException;
-import org.apache.geronimo.javamail.util.InvalidCommandException;
-import org.apache.geronimo.javamail.util.MailConnection;
-import org.apache.geronimo.javamail.util.ProtocolProperties;
+import org.apache.geronimo.javamail.util.CommandFailedException;
+import org.apache.geronimo.javamail.util.InvalidCommandException;
+import org.apache.geronimo.javamail.util.MailConnection;
+import org.apache.geronimo.javamail.util.ProtocolProperties;
import org.apache.geronimo.javamail.util.TraceInputStream;
import org.apache.geronimo.javamail.util.TraceOutputStream;
import org.apache.geronimo.mail.util.Base64;
@@ -79,13 +79,13 @@
* @version $Rev$ $Date$
*/
public class IMAPConnection extends MailConnection {
-
+
protected static final String CAPABILITY_LOGIN_DISABLED = "LOGINDISABLED";
- // The connection pool we're a member of. This keeps holds most of the
- // connnection parameter information for us.
- protected IMAPConnectionPool pool;
-
+ // The connection pool we're a member of. This keeps holds most of the
+ // connnection parameter information for us.
+ protected IMAPConnectionPool pool;
+
// special input stream for reading individual response lines.
protected IMAPResponseStream reader;
@@ -95,85 +95,85 @@
protected LinkedList responseHandlers = new LinkedList();
// the list of queued untagged responses.
protected List queuedResponses = new LinkedList();
- // this is set on if we had a forced disconnect situation from
- // the server.
+ // this is set on if we had a forced disconnect situation from
+ // the server.
protected boolean closed = false;
/**
* Normal constructor for an IMAPConnection() object.
- *
+ *
* @param props The protocol properties abstraction containing our
* property modifiers.
* @param pool
*/
public IMAPConnection(ProtocolProperties props, IMAPConnectionPool pool) {
super(props);
- this.pool = pool;
+ this.pool = pool;
}
-
+
/**
* Connect to the server and do the initial handshaking.
*
* @exception MessagingException
*/
public boolean protocolConnect(String host, int port, String authid, String realm, String username, String password) throws MessagingException {
- this.serverHost = host;
- this.serverPort = port;
- this.realm = realm;
- this.authid = authid;
- this.username = username;
- this.password = password;
-
- boolean preAuthorized = false;
-
+ this.serverHost = host;
+ this.serverPort = port;
+ this.realm = realm;
+ this.authid = authid;
+ this.username = username;
+ this.password = password;
+
+ boolean preAuthorized = false;
+
try {
// create socket and connect to server.
getConnection();
- // we need to ask the server what its capabilities are. This can be done
- // before we login.
+ // we need to ask the server what its capabilities are. This can be done
+ // before we login.
getCapability();
- // do a preauthoriziation check.
+ // do a preauthoriziation check.
if (extractResponse("PREAUTH") != null) {
- preAuthorized = true;
+ preAuthorized = true;
}
-
+
// make sure we process these now
- processPendingResponses();
+ processPendingResponses();
// if we're not already using an SSL connection, and we have permission to issue STARTTLS, AND
// the server supports this, then switch to TLS mode before continuing.
if (!sslConnection && props.getBooleanProperty(MAIL_STARTTLS_ENABLE, false) && hasCapability(CAPABILITY_STARTTLS)) {
// if the server supports TLS, then use it for the connection.
// on our connection.
-
+
// tell the server of our intention to start a TLS session
sendSimpleCommand("STARTTLS");
-
- // The connection is then handled by the superclass level.
+
+ // The connection is then handled by the superclass level.
getConnectedTLSSocket();
-
+
// create the special reader for pulling the responses.
reader = new IMAPResponseStream(inputStream);
- // the IMAP spec states that the capability response is independent of login state or
- // user, but I'm not sure I believe that to be the case. It doesn't hurt to refresh
- // the information again after establishing a secure connection.
+ // the IMAP spec states that the capability response is independent of login state or
+ // user, but I'm not sure I believe that to be the case. It doesn't hurt to refresh
+ // the information again after establishing a secure connection.
getCapability();
- // and we need to repeat this check.
+ // and we need to repeat this check.
if (extractResponse("PREAUTH") != null) {
- preAuthorized = true;
+ preAuthorized = true;
}
}
-
- // damn, no login required.
+
+ // damn, no login required.
if (preAuthorized) {
- return true;
+ return true;
}
-
- // go login with the server
- return login();
+
+ // go login with the server
+ return login();
} catch (IOException e) {
if (debug) {
debugOut("I/O exception establishing connection", e);
@@ -181,8 +181,8 @@
throw new MessagingException("Connection error", e);
}
finally {
- // make sure the queue is cleared
- processPendingResponses();
+ // make sure the queue is cleared
+ processPendingResponses();
}
}
@@ -220,13 +220,13 @@
}
try {
// say goodbye
- logout();
+ logout();
} finally {
// and close up the connection. We do this in a finally block to make sure the connection
// is shut down even if quit gets an error.
closeServerConnection();
- // get rid of our response processor too.
- reader = null;
+ // get rid of our response processor too.
+ reader = null;
}
}
@@ -239,9 +239,9 @@
*/
protected void getConnection() throws IOException, MessagingException
{
- // do all of the non-protocol specific set up. This will get our socket established
- // and ready use.
- super.getConnection();
+ // do all of the non-protocol specific set up. This will get our socket established
+ // and ready use.
+ super.getConnection();
// create the special reader for pulling the responses.
reader = new IMAPResponseStream(inputStream);
@@ -263,9 +263,9 @@
* @exception MessagingException
*/
public void sendSimpleCommand(String data) throws MessagingException {
- // create a command object and issue the command with that.
- IMAPCommand command = new IMAPCommand(data);
- sendSimpleCommand(command);
+ // create a command object and issue the command with that.
+ IMAPCommand command = new IMAPCommand(data);
+ sendSimpleCommand(command);
}
@@ -283,94 +283,99 @@
*/
public void sendSimpleCommand(IMAPCommand data) throws MessagingException {
// the command sending process will raise exceptions for bad responses....
- // we just need to send the command and forget about it.
+ // we just need to send the command and forget about it.
sendCommand(data);
}
/**
* Sends a command down the socket, returning the server response.
- *
+ *
* @param data The String form of the command.
- *
+ *
* @return The tagged response information that terminates the command interaction.
* @exception MessagingException
*/
public IMAPTaggedResponse sendCommand(String data) throws MessagingException {
- IMAPCommand command = new IMAPCommand(data);
- return sendCommand(command);
+ IMAPCommand command = new IMAPCommand(data);
+ return sendCommand(command);
}
/**
* Sends a command down the socket, returning the server response.
- *
+ *
* @param data An IMAPCommand object with the prepared command information.
- *
- * @return The tagged (or continuation) response information that terminates the
+ *
+ * @return The tagged (or continuation) response information that terminates the
* command response sequence.
* @exception MessagingException
*/
public synchronized IMAPTaggedResponse sendCommand(IMAPCommand data) throws MessagingException {
- // check first
- checkConnected();
+ // check first
+ checkConnected();
try {
- // have the command write the command data. This also prepends a tag.
+ // have the command write the command data. This also prepends a tag.
data.writeTo(outputStream, this);
outputStream.flush();
// update the activity timestamp
updateLastAccess();
- // get the received response
- return receiveResponse();
+ // get the received response
+ return receiveResponse();
} catch (IOException e) {
throw new MessagingException(e.toString(), e);
}
}
-
+
/**
* Sends a message down the socket and terminates with the
* appropriate CRLF
- *
+ *
* @param data The string data to send.
- *
+ *
* @return An IMAPTaggedResponse item returned from the server.
* @exception MessagingException
*/
public IMAPTaggedResponse sendLine(String data) throws MessagingException {
- return sendLine(data.getBytes());
+ try {
+ return sendLine(data.getBytes("ISO8859-1"));
+ } catch (UnsupportedEncodingException e) {
+ // should never happen
+ return null;
+ }
}
-
+
/**
* Sends a message down the socket and terminates with the
* appropriate CRLF
- *
+ *
* @param data The array of data to send to the server.
- *
+ *
* @return The response item returned from the IMAP server.
* @exception MessagingException
*/
public IMAPTaggedResponse sendLine(byte[] data) throws MessagingException {
- return sendLine(data, 0, data.length);
+ return sendLine(data, 0, data.length);
}
-
+
/**
* Sends a message down the socket and terminates with the
* appropriate CRLF
- *
+ *
* @param data The source data array.
* @param offset The offset within the data array.
* @param length The length of data to send.
- *
- * @return The response line returned from the IMAP server.
+ *
+ * @return The response line returned from the IMAP server.
* @exception MessagingException
*/
public synchronized IMAPTaggedResponse sendLine(byte[] data, int offset, int length) throws MessagingException {
- // check first
- checkConnected();
-
+ // check first
+ checkConnected();
+
try {
outputStream.write(data, offset, length);
outputStream.write(CR);
@@ -378,13 +383,13 @@
outputStream.flush();
// update the activity timestamp
updateLastAccess();
- return receiveResponse();
+ return receiveResponse();
} catch (IOException e) {
throw new MessagingException(e.toString(), e);
}
}
-
+
/**
* Get a reply line for an IMAP command.
*
@@ -394,80 +399,80 @@
while (true) {
// read and parse a response from the server.
IMAPResponse response = reader.readResponse();
- // The response set is terminated by either a continuation response or a
- // tagged response (we only have a single command active at one time).
+ // The response set is terminated by either a continuation response or a
+ // tagged response (we only have a single command active at one time).
if (response instanceof IMAPTaggedResponse) {
// update the access time stamp for later timeout processing.
- updateLastAccess();
- IMAPTaggedResponse tagged = (IMAPTaggedResponse)response;
- // we turn these into exceptions here, which means the issuer doesn't have to
- // worry about checking status.
+ updateLastAccess();
+ IMAPTaggedResponse tagged = (IMAPTaggedResponse)response;
+ // we turn these into exceptions here, which means the issuer doesn't have to
+ // worry about checking status.
if (tagged.isBAD()) {
- throw new InvalidCommandException("Unexpected command IMAP command error");
+ throw new InvalidCommandException("Unexpected command IMAP command error");
}
else if (tagged.isNO()) {
- throw new CommandFailedException("Unexpected error executing IMAP command");
+ throw new CommandFailedException("Unexpected error executing IMAP command");
}
- return tagged;
+ return tagged;
}
else {
- // all other unsolicited responses are either async status updates or
- // additional elements of a command we just sent. These will be processed
- // either during processing of the command response, or at the end of the
- // current command processing.
- queuePendingResponse((IMAPUntaggedResponse)response);
+ // all other unsolicited responses are either async status updates or
+ // additional elements of a command we just sent. These will be processed
+ // either during processing of the command response, or at the end of the
+ // current command processing.
+ queuePendingResponse((IMAPUntaggedResponse)response);
}
}
}
-
+
/**
* Get the servers capabilities from the wire....
*/
public void getCapability() throws MessagingException {
sendCommand("CAPABILITY");
// get the capabilities from the response.
- IMAPCapabilityResponse response = (IMAPCapabilityResponse)extractResponse("CAPABILITY");
- capabilities = response.getCapabilities();
- authentications = response.getAuthentications();
+ IMAPCapabilityResponse response = (IMAPCapabilityResponse)extractResponse("CAPABILITY");
+ capabilities = response.getCapabilities();
+ authentications = response.getAuthentications();
}
/**
- * Logs out from the server.
+ * Logs out from the server.
*/
public void logout() throws MessagingException {
- // We can just send the command and generally ignore the
- // status response.
+ // We can just send the command and generally ignore the
+ // status response.
sendCommand("LOGOUT");
}
/**
* Deselect a mailbox when a folder returns a connection.
- *
+ *
* @exception MessagingException
*/
public void closeMailbox() throws MessagingException {
- // We can just send the command and generally ignore the
- // status response.
+ // We can just send the command and generally ignore the
+ // status response.
sendCommand("CLOSE");
}
-
+
/**
* Authenticate with the server, if necessary (or possible).
- *
+ *
* @return true if we were able to authenticate correctly, false for authentication failures.
* @exception MessagingException
*/
protected boolean login() throws MessagingException
{
- // if no username or password, fail this immediately.
- // the base connect property should resolve a username/password combo for us and
- // try again.
+ // if no username or password, fail this immediately.
+ // the base connect property should resolve a username/password combo for us and
+ // try again.
if (username == null || password == null) {
- return false;
+ return false;
}
-
+
// are we permitted to use SASL mechanisms?
if (props.getBooleanProperty(MAIL_SASL_ENABLE, false)) {
// we might be enable for SASL, but the client and the server might
@@ -488,17 +493,17 @@
// no authzid capability with this authentication method.
return processLoginAuthentication();
}
-
- // the server can choose to disable the LOGIN command. If not disabled, try
- // using LOGIN rather than AUTHENTICATE.
+
+ // the server can choose to disable the LOGIN command. If not disabled, try
+ // using LOGIN rather than AUTHENTICATE.
if (!hasCapability(CAPABILITY_LOGIN_DISABLED)) {
- return processLogin();
+ return processLogin();
}
-
- throw new MessagingException("No supported LOGIN methods enabled");
+
+ throw new MessagingException("No supported LOGIN methods enabled");
}
-
+
/**
* Process SASL-type authentication.
*
@@ -507,24 +512,24 @@
* @exception MessagingException
*/
protected boolean processSaslAuthentication() throws MessagingException {
- // if unable to get an appropriate authenticator, just fail it.
- ClientAuthenticator authenticator = getSaslAuthenticator();
+ // if unable to get an appropriate authenticator, just fail it.
+ ClientAuthenticator authenticator = getSaslAuthenticator();
if (authenticator == null) {
- return false;
+ return false;
}
-
+
// go process the login.
return processLogin(authenticator);
}
-
+
protected ClientAuthenticator getSaslAuthenticator() {
- return AuthenticatorFactory.getAuthenticator(props, selectSaslMechanisms(), serverHost, username, password, authid, realm);
+ return AuthenticatorFactory.getAuthenticator(props, selectSaslMechanisms(), serverHost, username, password, authid, realm);
}
/**
* Process SASL-type PLAIN authentication.
*
- * @return Returns true if the login is accepted.
+ * @return Returns true if the login is accepted.
* @exception MessagingException
*/
protected boolean processPlainAuthentication() throws MessagingException {
@@ -536,44 +541,44 @@
/**
* Process SASL-type LOGIN authentication.
*
- * @return Returns true if the login is accepted.
+ * @return Returns true if the login is accepted.
* @exception MessagingException
*/
protected boolean processLoginAuthentication() throws MessagingException {
// go process the login.
return processLogin(new LoginAuthenticator(username, password));
}
-
-
+
+
/**
- * Process a LOGIN using the LOGIN command instead of AUTHENTICATE.
- *
- * @return true if the command succeeded, false for any authentication failures.
+ * Process a LOGIN using the LOGIN command instead of AUTHENTICATE.
+ *
+ * @return true if the command succeeded, false for any authentication failures.
* @exception MessagingException
*/
protected boolean processLogin() throws MessagingException {
// arguments are "LOGIN userid password"
IMAPCommand command = new IMAPCommand("LOGIN");
- command.appendAtom(username);
- command.appendAtom(password);
-
- // go issue the command
+ command.appendAtom(username);
+ command.appendAtom(password);
+
+ // go issue the command
try {
- sendCommand(command);
+ sendCommand(command);
} catch (CommandFailedException e) {
// we'll get a NO response for a rejected login
- return false;
+ return false;
}
// seemed to work ok....
- return true;
+ return true;
}
/**
* Process a login using the provided authenticator object.
- *
- * NB: This method is synchronized because we have a multi-step process going on
- * here. No other commands should be sent to the server until we complete.
+ *
+ * NB: This method is synchronized because we have a multi-step process going on
+ * here. No other commands should be sent to the server until we complete.
*
* @return Returns true if the server support a SASL authentication mechanism and
* accepted reponse challenges.
@@ -588,7 +593,7 @@
// and tell the server which mechanism we're using.
command.appendAtom(authenticator.getMechanismName());
// send the command now
-
+
try {
IMAPTaggedResponse response = sendCommand(command);
@@ -604,19 +609,19 @@
response = sendLine(Base64.encode(authenticator.evaluateChallenge(challenge)));
}
else {
- // there are only two choices here, OK or a continuation. OK means
- // we've passed muster and are in.
- return true;
+ // there are only two choices here, OK or a continuation. OK means
+ // we've passed muster and are in.
+ return true;
}
}
} catch (CommandFailedException e ) {
- // a failure at any point in this process will result in a "NO" response.
- // That causes an exception to get thrown, so just fail the login
- // if we get one.
- return false;
+ // a failure at any point in this process will result in a "NO" response.
+ // That causes an exception to get thrown, so just fail the login
+ // if we get one.
+ return false;
}
}
-
+
/**
* Return the server host for this connection.
@@ -627,7 +632,7 @@
return serverHost;
}
-
+
/**
* Attach a handler for untagged responses to this connection.
*
@@ -664,7 +669,7 @@
*/
public void processPendingResponses() throws MessagingException {
List pendingResponses = null;
- List handlerList = null;
+ List handlerList = null;
synchronized(this) {
if (queuedResponses.isEmpty()) {
@@ -672,172 +677,172 @@
}
pendingResponses = queuedResponses;
queuedResponses = new LinkedList();
- // get a copy of the response handlers so we can
- // release the connection lock before broadcasting
- handlerList = (List)responseHandlers.clone();
+ // get a copy of the response handlers so we can
+ // release the connection lock before broadcasting
+ handlerList = (List)responseHandlers.clone();
}
-
+
for (int i = 0; i < pendingResponses.size(); i++) {
- IMAPUntaggedResponse response = (IMAPUntaggedResponse)pendingResponses.get(i);
+ IMAPUntaggedResponse response = (IMAPUntaggedResponse)pendingResponses.get(i);
for (int j = 0; j < handlerList.size(); j++) {
- // broadcast to each handler. If a handler returns true, then it
- // handled whatever this message required and we should skip sending
- // it to other handlers.
- IMAPUntaggedResponseHandler h = (IMAPUntaggedResponseHandler)handlerList.get(j);
- if (h.handleResponse(response)) {
- break;
+ // broadcast to each handler. If a handler returns true, then it
+ // handled whatever this message required and we should skip sending
+ // it to other handlers.
+ IMAPUntaggedResponseHandler h = (IMAPUntaggedResponseHandler)handlerList.get(j);
+ if (h.handleResponse(response)) {
+ break;
}
}
}
}
-
+
/**
- * Extract a single response from the pending queue that
- * match a give keyword type. All matching responses
- * are removed from the pending queue.
- *
+ * Extract a single response from the pending queue that
+ * match a give keyword type. All matching responses
+ * are removed from the pending queue.
+ *
* @param type The string name of the keyword.
- *
- * @return A List of all matching queued responses.
+ *
+ * @return A List of all matching queued responses.
*/
public IMAPUntaggedResponse extractResponse(String type) {
- Iterator i = queuedResponses.iterator();
+ Iterator i = queuedResponses.iterator();
while (i.hasNext()) {
- IMAPUntaggedResponse response = (IMAPUntaggedResponse)i.next();
- // if this is of the target type, move it to the response set.
+ IMAPUntaggedResponse response = (IMAPUntaggedResponse)i.next();
+ // if this is of the target type, move it to the response set.
if (response.isKeyword(type)) {
- i.remove();
+ i.remove();
return response;
}
}
- return null;
+ return null;
}
-
+
/**
- * Extract all responses from the pending queue that
- * match a give keyword type. All matching responses
- * are removed from the pending queue.
- *
+ * Extract all responses from the pending queue that
+ * match a give keyword type. All matching responses
+ * are removed from the pending queue.
+ *
* @param type The string name of the keyword.
- *
- * @return A List of all matching queued responses.
+ *
+ * @return A List of all matching queued responses.
*/
public List extractResponses(String type) {
- List responses = new ArrayList();
-
- Iterator i = queuedResponses.iterator();
+ List responses = new ArrayList();
+
+ Iterator i = queuedResponses.iterator();
while (i.hasNext()) {
- IMAPUntaggedResponse response = (IMAPUntaggedResponse)i.next();
- // if this is of the target type, move it to the response set.
+ IMAPUntaggedResponse response = (IMAPUntaggedResponse)i.next();
+ // if this is of the target type, move it to the response set.
if (response.isKeyword(type)) {
- i.remove();
- responses.add(response);
+ i.remove();
+ responses.add(response);
}
}
- return responses;
+ return responses;
}
-
-
+
+
/**
- * Extract all responses from the pending queue that
- * are "FETCH" responses for a given message number. All matching responses
- * are removed from the pending queue.
- *
+ * Extract all responses from the pending queue that
+ * are "FETCH" responses for a given message number. All matching responses
+ * are removed from the pending queue.
+ *
* @param type The string name of the keyword.
- *
- * @return A List of all matching queued responses.
+ *
+ * @return A List of all matching queued responses.
*/
public List extractFetchResponses(int sequenceNumber) {
- List responses = new ArrayList();
-
- Iterator i = queuedResponses.iterator();
+ List responses = new ArrayList();
+
+ Iterator i = queuedResponses.iterator();
while (i.hasNext()) {
- IMAPUntaggedResponse response = (IMAPUntaggedResponse)i.next();
- // if this is of the target type, move it to the response set.
+ IMAPUntaggedResponse response = (IMAPUntaggedResponse)i.next();
+ // if this is of the target type, move it to the response set.
if (response.isKeyword("FETCH")) {
- IMAPFetchResponse fetch = (IMAPFetchResponse)response;
+ IMAPFetchResponse fetch = (IMAPFetchResponse)response;
// a response for the correct message number?
if (fetch.sequenceNumber == sequenceNumber) {
- // pluck these from the list and add to the response set.
- i.remove();
- responses.add(response);
+ // pluck these from the list and add to the response set.
+ i.remove();
+ responses.add(response);
}
}
}
- return responses;
+ return responses;
}
-
+
/**
- * Extract a fetch response data item from the queued elements.
- *
+ * Extract a fetch response data item from the queued elements.
+ *
* @param sequenceNumber
* The message number we're interested in. Fetch responses for other messages
* will be skipped.
* @param type The type of body element we need. It is assumed that only one item for
* the given message number will exist in the queue. The located item will
* be returned, and that fetch response will be removed from the pending queue.
- *
+ *
* @return The target data item, or null if a match is not found.
*/
- protected IMAPFetchDataItem extractFetchDataItem(long sequenceNumber, int type)
+ protected IMAPFetchDataItem extractFetchDataItem(long sequenceNumber, int type)
{
- Iterator i = queuedResponses.iterator();
+ Iterator i = queuedResponses.iterator();
while (i.hasNext()) {
- IMAPUntaggedResponse response = (IMAPUntaggedResponse)i.next();
- // if this is of the target type, move it to the response set.
+ IMAPUntaggedResponse response = (IMAPUntaggedResponse)i.next();
+ // if this is of the target type, move it to the response set.
if (response.isKeyword("FETCH")) {
- IMAPFetchResponse fetch = (IMAPFetchResponse)response;
+ IMAPFetchResponse fetch = (IMAPFetchResponse)response;
// a response for the correct message number?
if (fetch.sequenceNumber == sequenceNumber) {
// does this response have the item we're looking for?
- IMAPFetchDataItem item = fetch.getDataItem(type);
+ IMAPFetchDataItem item = fetch.getDataItem(type);
if (item != null) {
- // remove this from the pending queue and return the
+ // remove this from the pending queue and return the
// located item
- i.remove();
- return item;
+ i.remove();
+ return item;
}
}
}
}
- // not located, sorry
- return null;
+ // not located, sorry
+ return null;
}
-
+
/**
- * Extract a all fetch responses that contain a given data item.
- *
+ * Extract a all fetch responses that contain a given data item.
+ *
* @param type The type of body element we need. It is assumed that only one item for
* the given message number will exist in the queue. The located item will
* be returned, and that fetch response will be removed from the pending queue.
- *
- * @return A List of all matching Fetch responses.
+ *
+ * @return A List of all matching Fetch responses.
*/
- protected List extractFetchDataItems(int type)
+ protected List extractFetchDataItems(int type)
{
- Iterator i = queuedResponses.iterator();
- List items = new ArrayList();
-
+ Iterator i = queuedResponses.iterator();
+ List items = new ArrayList();
+
while (i.hasNext()) {
- IMAPUntaggedResponse response = (IMAPUntaggedResponse)i.next();
- // if this is of the target type, move it to the response set.
+ IMAPUntaggedResponse response = (IMAPUntaggedResponse)i.next();
+ // if this is of the target type, move it to the response set.
if (response.isKeyword("FETCH")) {
- IMAPFetchResponse fetch = (IMAPFetchResponse)response;
+ IMAPFetchResponse fetch = (IMAPFetchResponse)response;
// does this response have the item we're looking for?
- IMAPFetchDataItem item = fetch.getDataItem(type);
+ IMAPFetchDataItem item = fetch.getDataItem(type);
if (item != null) {
- // remove this from the pending queue and return the
+ // remove this from the pending queue and return the
// located item
- i.remove();
- // we want the fetch response, not the data item, because
- // we're going to require the message sequence number information
- // too.
- items.add(fetch);
+ i.remove();
+ // we want the fetch response, not the data item, because
+ // we're going to require the message sequence number information
+ // too.
+ items.add(fetch);
}
}
}
- // return whatever we have.
- return items;
+ // return whatever we have.
+ return items;
}
/**
@@ -852,26 +857,26 @@
/**
* check to see if this connection is truely alive.
- *
+ *
* @param timeout The timeout value to control how often we ping
* the server to see if we're still good.
- *
+ *
* @return true if the server is responding to requests, false for any
* connection errors. This will also update the folder status
* by processing returned unsolicited messages.
*/
public synchronized boolean isAlive(long timeout) {
- long lastUsed = System.currentTimeMillis() - lastAccess;
+ long lastUsed = System.currentTimeMillis() - lastAccess;
if (lastUsed < timeout) {
- return true;
+ return true;
}
-
+
try {
- sendSimpleCommand("NOOP");
+ sendSimpleCommand("NOOP");
return true;
} catch (MessagingException e) {
- // the NOOP command will throw a MessagingException if we get anything
- // other than an OK response back from the server.
+ // the NOOP command will throw a MessagingException if we get anything
+ // other than an OK response back from the server.
}
return false;
}
@@ -887,17 +892,17 @@
public synchronized List fetchEnvelope(int sequenceNumber) throws MessagingException {
IMAPCommand command = new IMAPCommand("FETCH");
command.appendInteger(sequenceNumber);
- command.startList();
- command.appendAtom("ENVELOPE INTERNALDATE RFC822.SIZE");
- command.endList();
-
+ command.startList();
+ command.appendAtom("ENVELOPE INTERNALDATE RFC822.SIZE");
+ command.endList();
+
// we want all of the envelope information about the message, which involves multiple FETCH chunks.
sendCommand(command);
// these are fairly involved sets, so the caller needs to handle these.
- // we just return all of the FETCH results matching the target message number.
- return extractFetchResponses(sequenceNumber);
+ // we just return all of the FETCH results matching the target message number.
+ return extractFetchResponses(sequenceNumber);
}
-
+
/**
* Issue a FETCH command to retrieve the message BODYSTRUCTURE structure.
*
@@ -909,13 +914,13 @@
public synchronized IMAPBodyStructure fetchBodyStructure(int sequenceNumber) throws MessagingException {
IMAPCommand command = new IMAPCommand("FETCH");
command.appendInteger(sequenceNumber);
- command.startList();
- command.appendAtom("BODYSTRUCTURE");
- command.endList();
-
+ command.startList();
+ command.appendAtom("BODYSTRUCTURE");
+ command.endList();
+
// we want all of the envelope information about the message, which involves multiple FETCH chunks.
sendCommand(command);
- // locate the response from this
+ // locate the response from this
IMAPBodyStructure bodyStructure = (IMAPBodyStructure)extractFetchDataItem(sequenceNumber, IMAPFetchDataItem.BODYSTRUCTURE);
if (bodyStructure == null) {
@@ -937,11 +942,11 @@
public synchronized InternetHeaders fetchHeaders(int sequenceNumber, String part) throws MessagingException {
IMAPCommand command = new IMAPCommand("FETCH");
command.appendInteger(sequenceNumber);
- command.startList();
- command.appendAtom("BODY.PEEK");
- command.appendBodySection(part, "HEADER");
- command.endList();
-
+ command.startList();
+ command.appendAtom("BODY.PEEK");
+ command.appendBodySection(part, "HEADER");
+ command.endList();
+
// we want all of the envelope information about the message, which involves multiple FETCH chunks.
sendCommand(command);
IMAPInternetHeader header = (IMAPInternetHeader)extractFetchDataItem(sequenceNumber, IMAPFetchDataItem.HEADER);
@@ -965,11 +970,11 @@
public synchronized IMAPMessageText fetchText(int sequenceNumber) throws MessagingException {
IMAPCommand command = new IMAPCommand("FETCH");
command.appendInteger(sequenceNumber);
- command.startList();
- command.appendAtom("BODY.PEEK");
- command.appendBodySection("TEXT");
- command.endList();
-
+ command.startList();
+ command.appendAtom("BODY.PEEK");
+ command.appendBodySection("TEXT");
+ command.endList();
+
// we want all of the envelope information about the message, which involves multiple FETCH chunks.
sendCommand(command);
IMAPMessageText text = (IMAPMessageText)extractFetchDataItem(sequenceNumber, IMAPFetchDataItem.TEXT);
@@ -993,11 +998,11 @@
public synchronized IMAPMessageText fetchBodyPartText(int sequenceNumber, String section) throws MessagingException {
IMAPCommand command = new IMAPCommand("FETCH");
command.appendInteger(sequenceNumber);
- command.startList();
- command.appendAtom("BODY.PEEK");
- command.appendBodySection(section, "TEXT");
- command.endList();
-
+ command.startList();
+ command.appendAtom("BODY.PEEK");
+ command.appendBodySection(section, "TEXT");
+ command.endList();
+
// we want all of the envelope information about the message, which involves multiple FETCH chunks.
sendCommand(command);
IMAPMessageText text = (IMAPMessageText)extractFetchDataItem(sequenceNumber, IMAPFetchDataItem.TEXT);
@@ -1013,12 +1018,12 @@
/**
* Issue a FETCH command to retrieve the entire message body in one shot.
* This may also be used to fetch an embedded message part as a unit.
- *
+ *
* @param sequenceNumber
* The sequence number of the message.
* @param section The section number to fetch. If null, the entire body of the message
* is retrieved.
- *
+ *
* @return The IMAPBody item for the message.
* All other untagged responses are queued for processing.
* @exception MessagingException
@@ -1026,13 +1031,13 @@
public synchronized IMAPBody fetchBody(int sequenceNumber, String section) throws MessagingException {
IMAPCommand command = new IMAPCommand("FETCH");
command.appendInteger(sequenceNumber);
- command.startList();
- command.appendAtom("BODY.PEEK");
- // no part name here, only the section identifier. This will fetch
- // the entire body, with all of the bits in place.
- command.appendBodySection(section, null);
- command.endList();
-
+ command.startList();
+ command.appendAtom("BODY.PEEK");
+ // no part name here, only the section identifier. This will fetch
+ // the entire body, with all of the bits in place.
+ command.appendBodySection(section, null);
+ command.endList();
+
// we want all of the envelope information about the message, which involves multiple FETCH chunks.
sendCommand(command);
IMAPBody body = (IMAPBody)extractFetchDataItem(sequenceNumber, IMAPFetchDataItem.BODY);
@@ -1043,32 +1048,32 @@
// and return the body structure directly.
return body;
}
-
-
+
+
/**
- * Fetch the message content. This sorts out which method should be used
+ * Fetch the message content. This sorts out which method should be used
* based on the server capability.
- *
+ *
* @param sequenceNumber
* The sequence number of the target message.
- *
+ *
* @return The byte[] content information.
* @exception MessagingException
*/
public byte[] fetchContent(int sequenceNumber) throws MessagingException {
- // fetch the text item and return the data
+ // fetch the text item and return the data
IMAPMessageText text = fetchText(sequenceNumber);
return text.getContent();
}
-
-
+
+
/**
- * Fetch the message content. This sorts out which method should be used
+ * Fetch the message content. This sorts out which method should be used
* based on the server capability.
- *
+ *
* @param sequenceNumber
* The sequence number of the target message.
- *
+ *
* @return The byte[] content information.
* @exception MessagingException
*/
@@ -1101,8 +1106,8 @@
sendCommand(command);
- // pull out the ones we're interested in
- return extractResponses("LIST");
+ // pull out the ones we're interested in
+ return extractResponses("LIST");
}
@@ -1123,8 +1128,8 @@
command.appendEncodedString(pattern);
sendCommand(command);
- // pull out the ones we're interested in
- return extractResponses("LSUB");
+ // pull out the ones we're interested in
+ return extractResponses("LSUB");
}
@@ -1234,13 +1239,13 @@
// now harvest each of the respon
IMAPMailboxStatus status = new IMAPMailboxStatus();
- status.mergeSizeResponses(extractResponses("EXISTS"));
- status.mergeSizeResponses(extractResponses("RECENT"));
- status.mergeOkResponses(extractResponses("UIDNEXT"));
- status.mergeOkResponses(extractResponses("UIDVALIDITY"));
- status.mergeOkResponses(extractResponses("UNSEEN"));
- status.mergeStatus((IMAPStatusResponse)extractResponse("STATUS"));
- status.mergeStatus((IMAPPermanentFlagsResponse)extractResponse("PERMANENTFLAGS"));
+ status.mergeSizeResponses(extractResponses("EXISTS"));
+ status.mergeSizeResponses(extractResponses("RECENT"));
+ status.mergeOkResponses(extractResponses("UIDNEXT"));
+ status.mergeOkResponses(extractResponses("UIDVALIDITY"));
+ status.mergeOkResponses(extractResponses("UNSEEN"));
+ status.mergeStatus((IMAPStatusResponse)extractResponse("STATUS"));
+ status.mergeStatus((IMAPPermanentFlagsResponse)extractResponse("PERMANENTFLAGS"));
return status;
}
@@ -1275,25 +1280,25 @@
// issue the select
IMAPTaggedResponse response = sendCommand(command);
- IMAPMailboxStatus status = new IMAPMailboxStatus();
- // set the mode to the requested open mode.
- status.mode = readOnly ? Folder.READ_ONLY : Folder.READ_WRITE;
-
- // the server might disagree on the mode, so check to see if
- // it's telling us READ-ONLY.
+ IMAPMailboxStatus status = new IMAPMailboxStatus();
+ // set the mode to the requested open mode.
+ status.mode = readOnly ? Folder.READ_ONLY : Folder.READ_WRITE;
+
+ // the server might disagree on the mode, so check to see if
+ // it's telling us READ-ONLY.
if (response.hasStatus("READ-ONLY")) {
- status.mode = Folder.READ_ONLY;
+ status.mode = Folder.READ_ONLY;
}
-
- // some of these are required, some are optional.
- status.mergeFlags((IMAPFlagsResponse)extractResponse("FLAGS"));
- status.mergeStatus((IMAPSizeResponse)extractResponse("EXISTS"));
- status.mergeStatus((IMAPSizeResponse)extractResponse("RECENT"));
- status.mergeStatus((IMAPOkResponse)extractResponse("UIDVALIDITY"));
- status.mergeStatus((IMAPOkResponse)extractResponse("UNSEEN"));
- status.mergeStatus((IMAPPermanentFlagsResponse)extractResponse("PERMANENTFLAGS"));
+
+ // some of these are required, some are optional.
+ status.mergeFlags((IMAPFlagsResponse)extractResponse("FLAGS"));
+ status.mergeStatus((IMAPSizeResponse)extractResponse("EXISTS"));
+ status.mergeStatus((IMAPSizeResponse)extractResponse("RECENT"));
+ status.mergeStatus((IMAPOkResponse)extractResponse("UIDVALIDITY"));
+ status.mergeStatus((IMAPOkResponse)extractResponse("UNSEEN"));
+ status.mergeStatus((IMAPPermanentFlagsResponse)extractResponse("PERMANENTFLAGS"));
// mine the response for status information about the selected mailbox.
- return status;
+ return status;
}
@@ -1301,17 +1306,17 @@
* Tells the IMAP server to expunge messages marked for deletion.
* The server will send us an untagged EXPUNGE message back for
* each deleted message. For explicit expunges we request, we'll
- * grabbed the untagged responses here, rather than force them to
- * be handled as pending responses. The caller will handle the
- * updates directly.
+ * grabbed the untagged responses here, rather than force them to
+ * be handled as pending responses. The caller will handle the
+ * updates directly.
*
* @exception MessagingException
*/
public synchronized List expungeMailbox() throws MessagingException {
- // send the message, and make sure we got an OK response
+ // send the message, and make sure we got an OK response
sendCommand("EXPUNGE");
- // extract all of the expunged responses and return.
- return extractResponses("EXPUNGED");
+ // extract all of the expunged responses and return.
+ return extractResponses("EXPUNGED");
}
public int[] searchMailbox(SearchTerm term) throws MessagingException {
@@ -1369,16 +1374,16 @@
// the IMAP command sequence. The SearchTerm sequence may be a complex tree of comparison terms,
// so this is not a simple process.
command.appendSearchTerm(term, charset);
- // need to append the message set
- command.appendAtom(messages);
+ // need to append the message set
+ command.appendAtom(messages);
// now issue the composed command.
sendCommand(command);
- // get the list of search responses
- IMAPSearchResponse hits = (IMAPSearchResponse)extractResponse("SEARCH");
- // and return the message hits
- return hits.messageNumbers;
+ // get the list of search responses
+ IMAPSearchResponse hits = (IMAPSearchResponse)extractResponse("SEARCH");
+ // and return the message hits
+ return hits.messageNumbers;
}
@@ -1422,29 +1427,29 @@
/**
* Fetch the flag set for a given message sequence number.
- *
+ *
* @param sequenceNumber
* The message sequence number.
- *
+ *
* @return The Flags defined for this message.
* @exception MessagingException
*/
- public synchronized Flags fetchFlags(int sequenceNumber) throws MessagingException {
- // we want just the flag item here.
+ public synchronized Flags fetchFlags(int sequenceNumber) throws MessagingException {
+ // we want just the flag item here.
sendCommand("FETCH " + String.valueOf(sequenceNumber) + " (FLAGS)");
// get the return data item, and get the flags from within it
IMAPFlags flags = (IMAPFlags)extractFetchDataItem(sequenceNumber, IMAPFetchDataItem.FLAGS);
- return flags.flags;
+ return flags.flags;
}
-
+
/**
* Set the flags for a range of messages.
- *
+ *
* @param messageSet The set of message numbers.
* @param flags The new flag settings.
* @param set true if the flags should be set, false for a clear operation.
- *
+ *
* @return A list containing all of the responses with the new flag values.
* @exception MessagingException
*/
@@ -1461,28 +1466,28 @@
// append the flag set
command.appendFlags(flags);
-
- // we want just the flag item here.
- sendCommand(command);
- // we should have a FETCH response for each of the updated messages. Return this
- // response, and update the message numbers.
+
+ // we want just the flag item here.
+ sendCommand(command);
+ // we should have a FETCH response for each of the updated messages. Return this
+ // response, and update the message numbers.
return extractFetchDataItems(IMAPFetchDataItem.FLAGS);
}
-
+
/**
* Set the flags for a single message.
- *
+ *
* @param sequenceNumber
* The sequence number of target message.
* @param flags The new flag settings.
* @param set true if the flags should be set, false for a clear operation.
- *
+ *
* @exception MessagingException
*/
public synchronized Flags setFlags(int sequenceNumber, Flags flags, boolean set) throws MessagingException {
IMAPCommand command = new IMAPCommand("STORE");
- command.appendInteger(sequenceNumber);
+ command.appendInteger(sequenceNumber);
// the command varies depending on whether this is a set or clear operation
if (set) {
command.appendAtom("+FLAGS");
@@ -1493,21 +1498,21 @@
// append the flag set
command.appendFlags(flags);
-
- // we want just the flag item here.
- sendCommand(command);
+
+ // we want just the flag item here.
+ sendCommand(command);
// get the return data item, and get the flags from within it
IMAPFlags flagResponse = (IMAPFlags)extractFetchDataItem(sequenceNumber, IMAPFetchDataItem.FLAGS);
- return flagResponse.flags;
+ return flagResponse.flags;
}
/**
- * Copy a range of messages to a target mailbox.
- *
+ * Copy a range of messages to a target mailbox.
+ *
* @param messageSet The set of message numbers.
* @param target The target mailbox name.
- *
+ *
* @exception MessagingException
*/
public void copyMessages(String messageSet, String target) throws MessagingException {
@@ -1520,455 +1525,455 @@
// it was ok.
sendSimpleCommand(command);
}
-
-
+
+
/**
* Fetch the message number for a give UID.
- *
+ *
* @param uid The target UID
- *
+ *
* @return An IMAPUid object containing the mapping information.
*/
public synchronized IMAPUid getSequenceNumberForUid(long uid) throws MessagingException {
IMAPCommand command = new IMAPCommand("UID FETCH");
command.appendLong(uid);
- command.appendAtom("(UID)");
+ command.appendAtom("(UID)");
- // this situation is a little strange, so it deserves a little explanation.
- // We need the message sequence number for this message from a UID value.
+ // this situation is a little strange, so it deserves a little explanation.
+ // We need the message sequence number for this message from a UID value.
// we're going to send a UID FETCH command, requesting the UID value back.
- // That seems strange, but the * nnnn FETCH response for the request will
- // be tagged with the message sequence number. THAT'S the information we
- // really want, and it will be included in the IMAPUid object.
+ // That seems strange, but the * nnnn FETCH response for the request will
+ // be tagged with the message sequence number. THAT'S the information we
+ // really want, and it will be included in the IMAPUid object.
sendCommand(command);
// ok, now we need to search through these looking for a FETCH response with a UID element.
- List responses = extractResponses("FETCH");
+ List responses = extractResponses("FETCH");
- // we're looking for a fetch response with a UID data item with the UID information
- // inside of it.
+ // we're looking for a fetch response with a UID data item with the UID information
+ // inside of it.
for (int i = 0; i < responses.size(); i++) {
- IMAPFetchResponse response = (IMAPFetchResponse)responses.get(i);
- IMAPUid item = (IMAPUid)response.getDataItem(IMAPFetchDataItem.UID);
- // is this the response we're looking for? The information we
- // need is the message number returned with the response, which is
- // also contained in the UID item.
+ IMAPFetchResponse response = (IMAPFetchResponse)responses.get(i);
+ IMAPUid item = (IMAPUid)response.getDataItem(IMAPFetchDataItem.UID);
+ // is this the response we're looking for? The information we
+ // need is the message number returned with the response, which is
+ // also contained in the UID item.
if (item != null && item.uid == uid) {
- return item;
+ return item;
}
- // not one meant for us, add it back to the pending queue.
+ // not one meant for us, add it back to the pending queue.
queuePendingResponse(response);
}
- // didn't find this one
- return null;
+ // didn't find this one
+ return null;
}
-
-
+
+
/**
- * Fetch the message numbers for a consequetive range
+ * Fetch the message numbers for a consequetive range
* of UIDs.
- *
+ *
* @param start The start of the range.
* @param end The end of the uid range.
- *
- * @return A list of UID objects containing the mappings.
+ *
+ * @return A list of UID objects containing the mappings.
*/
public synchronized List getSequenceNumbersForUids(long start, long end) throws MessagingException {
IMAPCommand command = new IMAPCommand("UID FETCH");
- // send the request for the range "start:end" so we can fetch all of the info
- // at once.
+ // send the request for the range "start:end" so we can fetch all of the info
+ // at once.
command.appendLong(start);
- command.append(":");
- // not the special range marker? Just append the
- // number. The LASTUID value needs to be "*" on the command.
+ command.append(":");
+ // not the special range marker? Just append the
+ // number. The LASTUID value needs to be "*" on the command.
if (end != UIDFolder.LASTUID) {
command.appendLong(end);
}
else {
command.append("*");
}
- command.appendAtom("(UID)");
+ command.appendAtom("(UID)");
- // this situation is a little strange, so it deserves a little explanation.
- // We need the message sequence number for this message from a UID value.
+ // this situation is a little strange, so it deserves a little explanation.
+ // We need the message sequence number for this message from a UID value.
// we're going to send a UID FETCH command, requesting the UID value back.
- // That seems strange, but the * nnnn FETCH response for the request will
- // be tagged with the message sequence number. THAT'S the information we
- // really want, and it will be included in the IMAPUid object.
+ // That seems strange, but the * nnnn FETCH response for the request will
+ // be tagged with the message sequence number. THAT'S the information we
+ // really want, and it will be included in the IMAPUid object.
sendCommand(command);
// ok, now we need to search through these looking for a FETCH response with a UID element.
- List responses = extractResponses("FETCH");
+ List responses = extractResponses("FETCH");
- List uids = new ArrayList((int)(end - start + 1));
+ List uids = new ArrayList((int)(end - start + 1));
- // we're looking for a fetch response with a UID data item with the UID information
- // inside of it.
+ // we're looking for a fetch response with a UID data item with the UID information
+ // inside of it.
for (int i = 0; i < responses.size(); i++) {
- IMAPFetchResponse response = (IMAPFetchResponse)responses.get(i);
- IMAPUid item = (IMAPUid)response.getDataItem(IMAPFetchDataItem.UID);
- // is this the response we're looking for? The information we
- // need is the message number returned with the response, which is
- // also contained in the UID item.
+ IMAPFetchResponse response = (IMAPFetchResponse)responses.get(i);
+ IMAPUid item = (IMAPUid)response.getDataItem(IMAPFetchDataItem.UID);
+ // is this the response we're looking for? The information we
+ // need is the message number returned with the response, which is
+ // also contained in the UID item.
if (item != null) {
- uids.add(item);
+ uids.add(item);
}
else {
- // not one meant for us, add it back to the pending queue.
+ // not one meant for us, add it back to the pending queue.
queuePendingResponse(response);
}
}
- // return the list of uids we located.
- return uids;
+ // return the list of uids we located.
+ return uids;
}
-
-
+
+
/**
* Fetch the UID value for a target message number
- *
+ *
* @param sequenceNumber
* The target message number.
- *
+ *
* @return An IMAPUid object containing the mapping information.
*/
public synchronized IMAPUid getUidForSequenceNumber(int sequenceNumber) throws MessagingException {
IMAPCommand command = new IMAPCommand("FETCH");
- command.appendInteger(sequenceNumber);
- command.appendAtom("(UID)");
+ command.appendInteger(sequenceNumber);
+ command.appendAtom("(UID)");
- // similar to the other fetches, but without the strange bit. We're starting
- // with the message number in this case.
+ // similar to the other fetches, but without the strange bit. We're starting
+ // with the message number in this case.
sendCommand(command);
-
+
// ok, now we need to search through these looking for a FETCH response with a UID element.
- return (IMAPUid)extractFetchDataItem(sequenceNumber, IMAPFetchDataItem.UID);
+ return (IMAPUid)extractFetchDataItem(sequenceNumber, IMAPFetchDataItem.UID);
}
-
-
+
+
/**
* Retrieve the user name space info from the server.
- *
- * @return An IMAPNamespace response item with the information. If the server
+ *
+ * @return An IMAPNamespace response item with the information. If the server
* doesn't support the namespace extension, an empty one is returned.
*/
public synchronized IMAPNamespaceResponse getNamespaces() throws MessagingException {
- // if no namespace capability, then return an empty
- // response, which will trigger the default behavior.
+ // if no namespace capability, then return an empty
+ // response, which will trigger the default behavior.
if (!hasCapability("NAMESPACE")) {
- return new IMAPNamespaceResponse();
+ return new IMAPNamespaceResponse();
}
- // no arguments on this command, so just send an hope it works.
- sendCommand("NAMESPACE");
-
- // this should be here, since it's a required response when the
- // command worked. Just extract, and return.
- return (IMAPNamespaceResponse)extractResponse("NAMESPACE");
+ // no arguments on this command, so just send an hope it works.
+ sendCommand("NAMESPACE");
+
+ // this should be here, since it's a required response when the
+ // command worked. Just extract, and return.
+ return (IMAPNamespaceResponse)extractResponse("NAMESPACE");
}
-
-
+
+
/**
* Prefetch message information based on the request profile. We'll return
- * all of the fetch information to the requesting Folder, which will sort
- * out what goes where.
- *
+ * all of the fetch information to the requesting Folder, which will sort
+ * out what goes where.
+ *
* @param messageSet The set of message numbers we need to fetch.
* @param profile The profile of the required information.
- *
- * @return All FETCH responses resulting from the command.
+ *
+ * @return All FETCH responses resulting from the command.
* @exception MessagingException
*/
public synchronized List fetch(String messageSet, FetchProfile profile) throws MessagingException {
IMAPCommand command = new IMAPCommand("FETCH");
- command.appendAtom(messageSet);
- // this is the set of items to append
- command.appendFetchProfile(profile);
-
- // now send the fetch command, which will likely send back a lot of "FETCH" responses.
- // Suck all of those reponses out of the queue and send them back for processing.
- sendCommand(command);
- // we can have a large number of messages here, so just grab all of the fetches
- // we get back, and let the Folder sort out who gets what.
- return extractResponses("FETCH");
+ command.appendAtom(messageSet);
+ // this is the set of items to append
+ command.appendFetchProfile(profile);
+
+ // now send the fetch command, which will likely send back a lot of "FETCH" responses.
+ // Suck all of those reponses out of the queue and send them back for processing.
+ sendCommand(command);
+ // we can have a large number of messages here, so just grab all of the fetches
+ // we get back, and let the Folder sort out who gets what.
+ return extractResponses("FETCH");
}
-
-
+
+
/**
- * Set the ACL rights for a mailbox. This replaces
+ * Set the ACL rights for a mailbox. This replaces
* any existing ACLs defined.
- *
+ *
* @param mailbox The target mailbox.
* @param acl The new ACL to be used for the mailbox.
- *
+ *
* @exception MessagingException
*/
public synchronized void setACLRights(String mailbox, ACL acl) throws MessagingException {
IMAPCommand command = new IMAPCommand("SETACL");
command.appendEncodedString(mailbox);
-
- command.appendACL(acl);
-
- sendSimpleCommand(command);
+
+ command.appendACL(acl);
+
+ sendSimpleCommand(command);
}
-
-
+
+
/**
* Add a set of ACL rights to a mailbox.
- *
+ *
* @param mailbox The mailbox to alter.
* @param acl The ACL to add.
- *
+ *
* @exception MessagingException
*/
public synchronized void addACLRights(String mailbox, ACL acl) throws MessagingException {
if (!hasCapability("ACL")) {
- throw new MethodNotSupportedException("ACL not available from this IMAP server");
+ throw new MethodNotSupportedException("ACL not available from this IMAP server");
}
IMAPCommand command = new IMAPCommand("SETACL");
command.appendEncodedString(mailbox);
-
- command.appendACL(acl, "+");
-
- sendSimpleCommand(command);
+
+ command.appendACL(acl, "+");
+
+ sendSimpleCommand(command);
}
-
-
+
+
/**
* Remove an ACL from a given mailbox.
- *
+ *
* @param mailbox The mailbox to alter.
* @param acl The particular ACL to revoke.
- *
+ *
* @exception MessagingException
*/
public synchronized void removeACLRights(String mailbox, ACL acl) throws MessagingException {
if (!hasCapability("ACL")) {
- throw new MethodNotSupportedException("ACL not available from this IMAP server");
+ throw new MethodNotSupportedException("ACL not available from this IMAP server");
}
IMAPCommand command = new IMAPCommand("SETACL");
command.appendEncodedString(mailbox);
-
- command.appendACL(acl, "-");
-
- sendSimpleCommand(command);
+
+ command.appendACL(acl, "-");
+
+ sendSimpleCommand(command);
}
-
-
+
+
/**
* Get the ACL rights assigned to a given mailbox.
- *
+ *
* @param mailbox The target mailbox.
- *
- * @return The an array of ACL items describing the access
+ *
+ * @return The an array of ACL items describing the access
* rights to the mailbox.
* @exception MessagingException
*/
public synchronized ACL[] getACLRights(String mailbox) throws MessagingException {
if (!hasCapability("ACL")) {
- throw new MethodNotSupportedException("ACL not available from this IMAP server");
+ throw new MethodNotSupportedException("ACL not available from this IMAP server");
}
IMAPCommand command = new IMAPCommand("GETACL");
command.appendEncodedString(mailbox);
-
- // now send the GETACL command, which will return a single ACL untagged response.
- sendCommand(command);
- // there should be just a single ACL response back from this command.
- IMAPACLResponse response = (IMAPACLResponse)extractResponse("ACL");
- return response.acls;
+
+ // now send the GETACL command, which will return a single ACL untagged response.
+ sendCommand(command);
+ // there should be just a single ACL response back from this command.
+ IMAPACLResponse response = (IMAPACLResponse)extractResponse("ACL");
+ return response.acls;
}
-
-
+
+
/**
- * Get the current user's ACL rights to a given mailbox.
- *
+ * Get the current user's ACL rights to a given mailbox.
+ *
* @param mailbox The target mailbox.
- *
- * @return The Rights associated with this mailbox.
+ *
+ * @return The Rights associated with this mailbox.
* @exception MessagingException
*/
public synchronized Rights getMyRights(String mailbox) throws MessagingException {
if (!hasCapability("ACL")) {
- throw new MethodNotSupportedException("ACL not available from this IMAP server");
+ throw new MethodNotSupportedException("ACL not available from this IMAP server");
}
IMAPCommand command = new IMAPCommand("MYRIGHTS");
command.appendEncodedString(mailbox);
-
- // now send the MYRIGHTS command, which will return a single MYRIGHTS untagged response.
- sendCommand(command);
- // there should be just a single MYRIGHTS response back from this command.
- IMAPMyRightsResponse response = (IMAPMyRightsResponse)extractResponse("MYRIGHTS");
- return response.rights;
+
+ // now send the MYRIGHTS command, which will return a single MYRIGHTS untagged response.
+ sendCommand(command);
+ // there should be just a single MYRIGHTS response back from this command.
+ IMAPMyRightsResponse response = (IMAPMyRightsResponse)extractResponse("MYRIGHTS");
+ return response.rights;
}
-
-
+
+
/**
- * List the ACL rights that a particular user has
+ * List the ACL rights that a particular user has
* to a mailbox.
- *
+ *
* @param mailbox The target mailbox.
* @param name The user we're querying.
- *
- * @return An array of rights the use has to this mailbox.
+ *
+ * @return An array of rights the use has to this mailbox.
* @exception MessagingException
*/
public synchronized Rights[] listACLRights(String mailbox, String name) throws MessagingException {
if (!hasCapability("ACL")) {
- throw new MethodNotSupportedException("ACL not available from this IMAP server");
+ throw new MethodNotSupportedException("ACL not available from this IMAP server");
}
IMAPCommand command = new IMAPCommand("LISTRIGHTS");
command.appendEncodedString(mailbox);
- command.appendString(name);
-
- // now send the GETACL command, which will return a single ACL untagged response.
- sendCommand(command);
- // there should be just a single ACL response back from this command.
- IMAPListRightsResponse response = (IMAPListRightsResponse)extractResponse("LISTRIGHTS");
- return response.rights;
+ command.appendString(name);
+
+ // now send the GETACL command, which will return a single ACL untagged response.
+ sendCommand(command);
+ // there should be just a single ACL response back from this command.
+ IMAPListRightsResponse response = (IMAPListRightsResponse)extractResponse("LISTRIGHTS");
+ return response.rights;
}
-
-
+
+
/**
- * Delete an ACL item for a given user name from
- * a target mailbox.
- *
+ * Delete an ACL item for a given user name from
+ * a target mailbox.
+ *
* @param mailbox The mailbox we're altering.
* @param name The user name.
- *
+ *
* @exception MessagingException
*/
public synchronized void deleteACL(String mailbox, String name) throws MessagingException {
if (!hasCapability("ACL")) {
- throw new MethodNotSupportedException("ACL not available from this IMAP server");
+ throw new MethodNotSupportedException("ACL not available from this IMAP server");
}
IMAPCommand command = new IMAPCommand("DELETEACL");
command.appendEncodedString(mailbox);
- command.appendString(name);
-
- // just send the command. No response to handle.
- sendSimpleCommand(command);
+ command.appendString(name);
+
+ // just send the command. No response to handle.
+ sendSimpleCommand(command);
}
-
+
/**
* Fetch the quota root information for a target mailbox.
- *
+ *
* @param mailbox The mailbox of interest.
- *
+ *
* @return An array of quotas describing all of the quota roots
* that apply to the target mailbox.
* @exception MessagingException
*/
public synchronized Quota[] fetchQuotaRoot(String mailbox) throws MessagingException {
if (!hasCapability("QUOTA")) {
- throw new MethodNotSupportedException("QUOTA not available from this IMAP server");
+ throw new MethodNotSupportedException("QUOTA not available from this IMAP server");
}
IMAPCommand command = new IMAPCommand("GETQUOTAROOT");
command.appendEncodedString(mailbox);
-
- // This will return a single QUOTAROOT response, plust a series of QUOTA responses for
- // each root names in the first response.
- sendCommand(command);
- // we don't really need this, but pull it from the response queue anyway.
- extractResponse("QUOTAROOT");
-
- // now get the real meat of the matter
- List responses = extractResponses("QUOTA");
-
- // now copy all of the returned quota items into the response array.
- Quota[] quotas = new Quota[responses.size()];
+
+ // This will return a single QUOTAROOT response, plust a series of QUOTA responses for
+ // each root names in the first response.
+ sendCommand(command);
+ // we don't really need this, but pull it from the response queue anyway.
+ extractResponse("QUOTAROOT");
+
+ // now get the real meat of the matter
+ List responses = extractResponses("QUOTA");
+
+ // now copy all of the returned quota items into the response array.
+ Quota[] quotas = new Quota[responses.size()];
for (int i = 0; i < quotas.length; i++) {
- IMAPQuotaResponse q = (IMAPQuotaResponse)responses.get(i);
- quotas[i] = q.quota;
+ IMAPQuotaResponse q = (IMAPQuotaResponse)responses.get(i);
+ quotas[i] = q.quota;
}
-
- return quotas;
+
+ return quotas;
}
-
+
/**
* Fetch QUOTA information from a named QUOTE root.
- *
+ *
* @param root The target root name.
- *
+ *
* @return An array of Quota items associated with that root name.
* @exception MessagingException
*/
public synchronized Quota[] fetchQuota(String root) throws MessagingException {
if (!hasCapability("QUOTA")) {
- throw new MethodNotSupportedException("QUOTA not available from this IMAP server");
+ throw new MethodNotSupportedException("QUOTA not available from this IMAP server");
}
IMAPCommand command = new IMAPCommand("GETQUOTA");
command.appendString(root);
-
- // This will return a single QUOTAROOT response, plust a series of QUOTA responses for
- // each root names in the first response.
- sendCommand(command);
-
- // now get the real meat of the matter
- List responses = extractResponses("QUOTA");
-
- // now copy all of the returned quota items into the response array.
- Quota[] quotas = new Quota[responses.size()];
+
+ // This will return a single QUOTAROOT response, plust a series of QUOTA responses for
+ // each root names in the first response.
+ sendCommand(command);
+
+ // now get the real meat of the matter
+ List responses = extractResponses("QUOTA");
+
+ // now copy all of the returned quota items into the response array.
+ Quota[] quotas = new Quota[responses.size()];
for (int i = 0; i < quotas.length; i++) {
- IMAPQuotaResponse q = (IMAPQuotaResponse)responses.get(i);
- quotas[i] = q.quota;
+ IMAPQuotaResponse q = (IMAPQuotaResponse)responses.get(i);
+ quotas[i] = q.quota;
}
-
- return quotas;
+
+ return quotas;
}
-
+
/**
- * Set a Quota item for the currently accessed
- * userid/folder resource.
- *
+ * Set a Quota item for the currently accessed
+ * userid/folder resource.
+ *
* @param quota The new QUOTA information.
- *
+ *
* @exception MessagingException
*/
public synchronized void setQuota(Quota quota) throws MessagingException {
if (!hasCapability("QUOTA")) {
- throw new MethodNotSupportedException("QUOTA not available from this IMAP server");
+ throw new MethodNotSupportedException("QUOTA not available from this IMAP server");
}
IMAPCommand command = new IMAPCommand("GETQUOTA");
- // this gets appended as a list of resource values
- command.appendQuota(quota);
-
- // This will return a single QUOTAROOT response, plust a series of QUOTA responses for
- // each root names in the first response.
- sendCommand(command);
- // we don't really need this, but pull it from the response queue anyway.
- extractResponses("QUOTA");
+ // this gets appended as a list of resource values
+ command.appendQuota(quota);
+
+ // This will return a single QUOTAROOT response, plust a series of QUOTA responses for
+ // each root names in the first response.
+ sendCommand(command);
+ // we don't really need this, but pull it from the response queue anyway.
+ extractResponses("QUOTA");
}
-
-
+
+
/**
- * Test if this connection has a given capability.
- *
+ * Test if this connection has a given capability.
+ *
* @param capability The capability name.
- *
- * @return true if this capability is in the list, false for a mismatch.
+ *
+ * @return true if this capability is in the list, false for a mismatch.
*/
public boolean hasCapability(String capability) {
if (capabilities == null) {
- return false;
+ return false;
}
- return capabilities.containsKey(capability);
+ return capabilities.containsKey(capability);
}
-
+
/**
- * Tag this connection as having been closed by the
- * server. This will not be returned to the
- * connection pool.
+ * Tag this connection as having been closed by the
+ * server. This will not be returned to the
+ * connection pool.
*/
public void setClosed() {
closed = true;
}
-
+
/**
* Test if the connnection has been forcibly closed.
- *
+ *
* @return True if the server disconnected the connection.
*/
public boolean isClosed() {
- return closed;
+ return closed;
}
}
diff --git a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/connection/IMAPResponseBuffer.java b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/connection/IMAPResponseBuffer.java
index 0c2e458..cd28d54 100644
--- a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/connection/IMAPResponseBuffer.java
+++ b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/connection/IMAPResponseBuffer.java
@@ -18,6 +18,7 @@
package org.apache.geronimo.javamail.store.imap.connection;
import java.io.ByteArrayOutputStream;
+import java.io.UnsupportedEncodingException;
/**
* Simple extension to the ByteArrayOutputStream to allow inspection
@@ -120,11 +121,14 @@
return -1;
}
- String lenString = new String(buf, literalStart + 1, size() - (literalStart + 2));
try {
- return Integer.parseInt(lenString);
- } catch (NumberFormatException e) {
- e.printStackTrace();
+ String lenString = new String(buf, literalStart + 1, size() - (literalStart + 2), "US-ASCII");
+ try {
+ return Integer.parseInt(lenString);
+ } catch (NumberFormatException e) {
+ }
+ } catch (UnsupportedEncodingException ex) {
+ // should never happen
}
}
// not a literal
diff --git a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/connection/IMAPResponseStream.java b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/connection/IMAPResponseStream.java
index 9c8e365..26c787f 100644
--- a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/connection/IMAPResponseStream.java
+++ b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/connection/IMAPResponseStream.java
@@ -20,62 +20,63 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
-import javax.mail.MessagingException;
-import javax.mail.event.FolderEvent;
+import javax.mail.MessagingException;
+import javax.mail.event.FolderEvent;
import org.apache.geronimo.javamail.store.imap.connection.IMAPResponseTokenizer.Token;
import org.apache.geronimo.javamail.util.ConnectionException;
public class IMAPResponseStream {
- protected final int BUFFER_SIZE = 1024;
-
+ protected final int BUFFER_SIZE = 1024;
+
// our source input stream
protected InputStream in;
- // The response buffer
- IMAPResponseBuffer out;
- // the buffer array
- protected byte[] buffer = new byte[BUFFER_SIZE];
- // the current buffer position
- int position;
- // the current buffer read length
- int length;
+ // The response buffer
+ IMAPResponseBuffer out;
+ // the buffer array
+ protected byte[] buffer = new byte[BUFFER_SIZE];
+ // the current buffer position
+ int position;
+ // the current buffer read length
+ int length;
public IMAPResponseStream(InputStream in) {
this.in = in;
out = new IMAPResponseBuffer();
}
-
+
public int read() throws IOException {
- // if we can't read any more, that's an EOF condition.
+ // if we can't read any more, that's an EOF condition.
if (!fillBufferIfNeeded()) {
- return -1;
+ return -1;
}
- // just grab the next character
- return buffer[position++];
+ // just grab the next character
+ return buffer[position++];
}
-
+
protected boolean fillBufferIfNeeded() throws IOException {
// used up all of the data in the buffer?
if (position >= length) {
- int readLength = 0;
- // a read from a network connection can return 0 bytes,
- // so we need to be prepared to handle a spin loop.
+ int readLength = 0;
+ // a read from a network connection can return 0 bytes,
+ // so we need to be prepared to handle a spin loop.
while (readLength == 0) {
- readLength = in.read(buffer, 0, buffer.length);
+ readLength = in.read(buffer, 0, buffer.length);
}
- // we may have hit the EOF. Indicate the read failure
+ // we may have hit the EOF. Indicate the read failure
if (readLength == -1) {
- return false;
+ return false;
}
- // set our new buffer positions.
- position = 0;
- length = readLength;
+ // set our new buffer positions.
+ position = 0;
+ length = readLength;
}
- return true;
+ return true;
}
@@ -86,180 +87,180 @@
* @return A parsed IMAPResponse item using the response data.
* @exception MessagingException
*/
- public IMAPResponse readResponse() throws MessagingException
- {
- // reset our accumulator
- out.reset();
+ public IMAPResponse readResponse() throws MessagingException
+ {
+ // reset our accumulator
+ out.reset();
// now read a buffer of data
byte[] data = readData();
-
+
// and create a tokenizer for parsing this down.
IMAPResponseTokenizer tokenizer = new IMAPResponseTokenizer(data);
// get the first token.
Token token = tokenizer.next();
-
- int type = token.getType();
-
- // a continuation response. This will terminate a response set.
+
+ int type = token.getType();
+
+ // a continuation response. This will terminate a response set.
if (type == Token.CONTINUATION) {
- return new IMAPContinuationResponse(data);
+ return new IMAPContinuationResponse(data);
}
- // unsolicited response. There are multiple forms of these, which might actually be
- // part of the response for the last issued command.
+ // unsolicited response. There are multiple forms of these, which might actually be
+ // part of the response for the last issued command.
else if (type == Token.UNTAGGED) {
// step to the next token, which will give us the type
- token = tokenizer.next();
- // if the token is numeric, then this is a size response in the
+ token = tokenizer.next();
+ // if the token is numeric, then this is a size response in the
// form "* nn type"
if (token.isType(Token.NUMERIC)) {
- int size = token.getInteger();
-
- token = tokenizer.next();
-
- String keyword = token.getValue();
-
- // FETCH responses require fairly complicated parsing. Other
- // size/message updates are fairly generic.
+ int size = token.getInteger();
+
+ token = tokenizer.next();
+
+ String keyword = token.getValue();
+
+ // FETCH responses require fairly complicated parsing. Other
+ // size/message updates are fairly generic.
if (keyword.equals("FETCH")) {
- return new IMAPFetchResponse(size, data, tokenizer);
+ return new IMAPFetchResponse(size, data, tokenizer);
}
- return new IMAPSizeResponse(keyword, size, data);
+ return new IMAPSizeResponse(keyword, size, data);
}
-
- // this needs to be an ATOM type, which will tell us what format this untagged
- // response is in. There are many different untagged formats, some general, some
- // specific to particular command types.
+
+ // this needs to be an ATOM type, which will tell us what format this untagged
+ // response is in. There are many different untagged formats, some general, some
+ // specific to particular command types.
if (token.getType() != Token.ATOM) {
- throw new MessagingException("Unknown server response: " + new String(data));
+ throw new MessagingException("Unknown server response: " + new String(data, Charset.forName("ISO8859-1")));
}
-
- String keyword = token.getValue();
- // many response are in the form "* OK [keyword value] message".
+
+ String keyword = token.getValue();
+ // many response are in the form "* OK [keyword value] message".
if (keyword.equals("OK")) {
- return parseUntaggedOkResponse(data, tokenizer);
+ return parseUntaggedOkResponse(data, tokenizer);
}
- // preauth status response
+ // preauth status response
else if (keyword.equals("PREAUTH")) {
- return new IMAPServerStatusResponse("PREAUTH", tokenizer.getRemainder(), data);
+ return new IMAPServerStatusResponse("PREAUTH", tokenizer.getRemainder(), data);
}
- // preauth status response
+ // preauth status response
else if (keyword.equals("BYE")) {
- return new IMAPServerStatusResponse("BYE", tokenizer.getRemainder(), data);
+ return new IMAPServerStatusResponse("BYE", tokenizer.getRemainder(), data);
}
else if (keyword.equals("BAD")) {
- // these are generally ignored.
- return new IMAPServerStatusResponse("BAD", tokenizer.getRemainder(), data);
+ // these are generally ignored.
+ return new IMAPServerStatusResponse("BAD", tokenizer.getRemainder(), data);
}
else if (keyword.equals("NO")) {
- // these are generally ignored.
- return new IMAPServerStatusResponse("NO", tokenizer.getRemainder(), data);
+ // these are generally ignored.
+ return new IMAPServerStatusResponse("NO", tokenizer.getRemainder(), data);
}
- // a complex CAPABILITY response
+ // a complex CAPABILITY response
else if (keyword.equals("CAPABILITY")) {
- return new IMAPCapabilityResponse(tokenizer, data);
+ return new IMAPCapabilityResponse(tokenizer, data);
}
- // a complex LIST response
+ // a complex LIST response
else if (keyword.equals("LIST")) {
- return new IMAPListResponse("LIST", data, tokenizer);
+ return new IMAPListResponse("LIST", data, tokenizer);
}
- // a complex FLAGS response
+ // a complex FLAGS response
else if (keyword.equals("FLAGS")) {
- // parse this into a flags set.
- return new IMAPFlagsResponse(data, tokenizer);
+ // parse this into a flags set.
+ return new IMAPFlagsResponse(data, tokenizer);
}
// a complex LSUB response (identical in format to LIST)
else if (keyword.equals("LSUB")) {
- return new IMAPListResponse("LSUB", data, tokenizer);
+ return new IMAPListResponse("LSUB", data, tokenizer);
}
- // a STATUS response, which will contain a list of elements
+ // a STATUS response, which will contain a list of elements
else if (keyword.equals("STATUS")) {
- return new IMAPStatusResponse(data, tokenizer);
+ return new IMAPStatusResponse(data, tokenizer);
}
- // SEARCH requests return an variable length list of message matches.
+ // SEARCH requests return an variable length list of message matches.
else if (keyword.equals("SEARCH")) {
- return new IMAPSearchResponse(data, tokenizer);
+ return new IMAPSearchResponse(data, tokenizer);
}
- // ACL requests return an variable length list of ACL values .
+ // ACL requests return an variable length list of ACL values .
else if (keyword.equals("ACL")) {
- return new IMAPACLResponse(data, tokenizer);
+ return new IMAPACLResponse(data, tokenizer);
}
- // LISTRIGHTS requests return a variable length list of RIGHTS values .
+ // LISTRIGHTS requests return a variable length list of RIGHTS values .
else if (keyword.equals("LISTRIGHTS")) {
- return new IMAPListRightsResponse(data, tokenizer);
+ return new IMAPListRightsResponse(data, tokenizer);
}
- // MYRIGHTS requests return a list of user rights for a mailbox name.
+ // MYRIGHTS requests return a list of user rights for a mailbox name.
else if (keyword.equals("MYRIGHTS")) {
- return new IMAPMyRightsResponse(data, tokenizer);
+ return new IMAPMyRightsResponse(data, tokenizer);
}
- // QUOTAROOT requests return a list of mailbox quota root names
+ // QUOTAROOT requests return a list of mailbox quota root names
else if (keyword.equals("QUOTAROOT")) {
- return new IMAPQuotaRootResponse(data, tokenizer);
+ return new IMAPQuotaRootResponse(data, tokenizer);
}
- // QUOTA requests return a list of quota values for a root name
+ // QUOTA requests return a list of quota values for a root name
else if (keyword.equals("QUOTA")) {
- return new IMAPQuotaResponse(data, tokenizer);
+ return new IMAPQuotaResponse(data, tokenizer);
}
else if (keyword.equals("NAMESPACE")) {
- return new IMAPNamespaceResponse(data, tokenizer);
+ return new IMAPNamespaceResponse(data, tokenizer);
}
}
- // begins with a word, this should be the tagged response from the last command.
+ // begins with a word, this should be the tagged response from the last command.
else if (type == Token.ATOM) {
- String tag = token.getValue();
- token = tokenizer.next();
- String status = token.getValue();
- // primary information in one of these is the status field, which hopefully
+ String tag = token.getValue();
+ token = tokenizer.next();
+ String status = token.getValue();
+ // primary information in one of these is the status field, which hopefully
// is 'OK'
- return new IMAPTaggedResponse(tag, status, tokenizer.getRemainder(), data);
+ return new IMAPTaggedResponse(tag, status, tokenizer.getRemainder(), data);
}
- throw new MessagingException("Unknown server response: " + new String(data));
- }
-
- /**
- * Parse an unsolicited OK status response. These
- * responses are of the form:
- *
- * * OK [keyword arguments ...] message
- *
- * The part in the brackets are optional, but
- * most OK messages will have some sort of update.
- *
- * @param data The raw message data
- * @param tokenizer The tokenizer being used for this message.
- *
- * @return An IMAPResponse instance for this message.
- */
- private IMAPResponse parseUntaggedOkResponse(byte [] data, IMAPResponseTokenizer tokenizer) throws MessagingException {
- Token token = tokenizer.peek();
- // we might have an optional value here
- if (token.getType() != '[') {
- // this has no tagging item, so there's nothing to be processed
- // later.
- return new IMAPOkResponse("OK", null, tokenizer.getRemainder(), data);
- }
- // skip over the "[" token
- tokenizer.next();
- token = tokenizer.next();
- String keyword = token.getValue();
-
- // Permanent flags gets special handling
- if (keyword.equals("PERMANENTFLAGS")) {
- return new IMAPPermanentFlagsResponse(data, tokenizer);
- }
-
- ArrayList arguments = new ArrayList();
-
- // strip off all of the argument tokens until the "]" list terminator.
- token = tokenizer.next();
- while (token.getType() != ']') {
- arguments.add(token);
- token = tokenizer.next();
- }
- // this has a tagged keyword and arguments that will be processed later.
- return new IMAPOkResponse(keyword, arguments, tokenizer.getRemainder(), data);
+ throw new MessagingException("Unknown server response: " + new String(data, Charset.forName("ISO8859-1")));
}
-
+ /**
+ * Parse an unsolicited OK status response. These
+ * responses are of the form:
+ *
+ * * OK [keyword arguments ...] message
+ *
+ * The part in the brackets are optional, but
+ * most OK messages will have some sort of update.
+ *
+ * @param data The raw message data
+ * @param tokenizer The tokenizer being used for this message.
+ *
+ * @return An IMAPResponse instance for this message.
+ */
+ private IMAPResponse parseUntaggedOkResponse(byte [] data, IMAPResponseTokenizer tokenizer) throws MessagingException {
+ Token token = tokenizer.peek();
+ // we might have an optional value here
+ if (token.getType() != '[') {
+ // this has no tagging item, so there's nothing to be processed
+ // later.
+ return new IMAPOkResponse("OK", null, tokenizer.getRemainder(), data);
+ }
+ // skip over the "[" token
+ tokenizer.next();
+ token = tokenizer.next();
+ String keyword = token.getValue();
+
+ // Permanent flags gets special handling
+ if (keyword.equals("PERMANENTFLAGS")) {
+ return new IMAPPermanentFlagsResponse(data, tokenizer);
+ }
+
+ ArrayList arguments = new ArrayList();
+
+ // strip off all of the argument tokens until the "]" list terminator.
+ token = tokenizer.next();
+ while (token.getType() != ']') {
+ arguments.add(token);
+ token = tokenizer.next();
+ }
+ // this has a tagged keyword and arguments that will be processed later.
+ return new IMAPOkResponse(keyword, arguments, tokenizer.getRemainder(), data);
+ }
+
+
/**
* Read a "line" of server response data. An individual line
* may span multiple line breaks, depending on syntax implications.
@@ -322,7 +323,7 @@
try {
// see if we have a literal length signature at the end.
int length = out.getLiteralLength();
-
+
// -1 means no literal length, so we're done reading this particular response.
if (length == -1) {
return;
@@ -341,11 +342,11 @@
// The InputStream can return less than the requested length if it needs to block.
// This may take a couple iterations to get everything, particularly if it's long.
while (length > 0) {
- int read = -1;
+ int read = -1;
try {
read = in.read(bytes, offset, length);
} catch (IOException e) {
- throw new MessagingException("Unexpected read error on server connection", e);
+ throw new MessagingException("Unexpected read error on server connection", e);
}
// premature EOF we can't ignore.
if (read == -1) {
@@ -362,7 +363,7 @@
// additional literals). Just recurse on the line reading logic.
readBuffer();
} catch (IOException e) {
- e.printStackTrace();
+ e.printStackTrace();
// this is a byte array output stream...should never happen
}
}
diff --git a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/connection/IMAPResponseTokenizer.java b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/connection/IMAPResponseTokenizer.java
index 8bafb2b..7641344 100644
--- a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/connection/IMAPResponseTokenizer.java
+++ b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/connection/IMAPResponseTokenizer.java
@@ -19,6 +19,7 @@
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@@ -186,7 +187,7 @@
return "";
}
- return new String(response, pos, response.length - pos);
+ return new String(response, pos, response.length - pos, Charset.forName("ISO8859-1"));
}
@@ -236,7 +237,7 @@
}
// Numeric tokens we store as a different type.
- String value = new String(response, start, pos - start);
+ String value = new String(response, start, pos - start, Charset.forName("ISO8859-1"));
try {
int intValue = Integer.parseInt(value);
return new Token(Token.NUMERIC, value);
@@ -376,7 +377,7 @@
*/
private Token readQuotedString() throws MessagingException {
- String value = new String(readQuotedStringData());
+ String value = new String(readQuotedStringData(), Charset.forName("ISO8859-1"));
return new Token(Token.QUOTEDSTRING, value);
}
@@ -428,7 +429,7 @@
* @exception ResponseFormatException
*/
protected Token readLiteral() throws MessagingException {
- String value = new String(readLiteralData());
+ String value = new String(readLiteralData(), Charset.forName("ISO8859-1"));
return new Token(Token.LITERAL, value);
}
@@ -480,7 +481,7 @@
* @return A String extracted from the buffer.
*/
protected String substring(int start, int end ) {
- return new String(response, start, end - start);
+ return new String(response, start, end - start, Charset.forName("ISO8859-1"));
}
diff --git a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/connection/POP3Connection.java b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/connection/POP3Connection.java
index 0b12a09..0721840 100644
--- a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/connection/POP3Connection.java
+++ b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/connection/POP3Connection.java
@@ -22,6 +22,7 @@
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
+import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
@@ -35,48 +36,48 @@
import javax.mail.MessagingException;
import javax.mail.internet.InternetHeaders;
-import org.apache.geronimo.javamail.authentication.AuthenticatorFactory;
+import org.apache.geronimo.javamail.authentication.AuthenticatorFactory;
import org.apache.geronimo.javamail.authentication.ClientAuthenticator;
-import org.apache.geronimo.javamail.store.pop3.POP3Constants;
-import org.apache.geronimo.javamail.util.CommandFailedException;
-import org.apache.geronimo.javamail.util.InvalidCommandException;
+import org.apache.geronimo.javamail.store.pop3.POP3Constants;
+import org.apache.geronimo.javamail.util.CommandFailedException;
+import org.apache.geronimo.javamail.util.InvalidCommandException;
import org.apache.geronimo.javamail.util.MIMEInputReader;
-import org.apache.geronimo.javamail.util.MailConnection;
-import org.apache.geronimo.javamail.util.ProtocolProperties;
+import org.apache.geronimo.javamail.util.MailConnection;
+import org.apache.geronimo.javamail.util.ProtocolProperties;
import org.apache.geronimo.mail.util.Base64;
import org.apache.geronimo.mail.util.Hex;
/**
- * Simple implementation of POP3 transport.
+ * Simple implementation of POP3 transport.
*
* @version $Rev$ $Date$
*/
public class POP3Connection extends MailConnection implements POP3Constants {
-
- static final protected String MAIL_APOP_ENABLED = "apop.enable";
- static final protected String MAIL_AUTH_ENABLED = "auth.enable";
- static final protected String MAIL_RESET_QUIT = "rsetbeforequit";
+
+ static final protected String MAIL_APOP_ENABLED = "apop.enable";
+ static final protected String MAIL_AUTH_ENABLED = "auth.enable";
+ static final protected String MAIL_RESET_QUIT = "rsetbeforequit";
static final protected String MAIL_DISABLE_TOP = "disabletop";
- static final protected String MAIL_FORGET_TOP = "forgettopheaders";
-
- // the initial greeting string, which might be required for APOP authentication.
- protected String greeting;
- // is use of the AUTH command enabled
- protected boolean authEnabled;
- // is use of APOP command enabled
- protected boolean apopEnabled;
- // input reader wrapped around the socket input stream
- protected BufferedReader reader;
- // output writer wrapped around the socket output stream.
- protected PrintWriter writer;
+ static final protected String MAIL_FORGET_TOP = "forgettopheaders";
+
+ // the initial greeting string, which might be required for APOP authentication.
+ protected String greeting;
+ // is use of the AUTH command enabled
+ protected boolean authEnabled;
+ // is use of APOP command enabled
+ protected boolean apopEnabled;
+ // input reader wrapped around the socket input stream
+ protected BufferedReader reader;
+ // output writer wrapped around the socket output stream.
+ protected PrintWriter writer;
// this connection was closed unexpectedly
protected boolean closed;
- // indicates whether this conneciton is currently logged in. Once
- // we send a QUIT, we're finished.
- protected boolean loggedIn;
- // indicates whether we need to avoid using the TOP command
+ // indicates whether this conneciton is currently logged in. Once
+ // we send a QUIT, we're finished.
+ protected boolean loggedIn;
+ // indicates whether we need to avoid using the TOP command
// when retrieving headers
- protected boolean topDisabled = false;
+ protected boolean topDisabled = false;
/**
* Normal constructor for an POP3Connection() object.
@@ -95,40 +96,40 @@
*/
public POP3Connection(ProtocolProperties props) {
super(props);
-
- // get our login properties flags
- authEnabled = props.getBooleanProperty(MAIL_AUTH_ENABLED, false);
- apopEnabled = props.getBooleanProperty(MAIL_APOP_ENABLED, false);
- topDisabled = props.getBooleanProperty(MAIL_DISABLE_TOP, false);
+
+ // get our login properties flags
+ authEnabled = props.getBooleanProperty(MAIL_AUTH_ENABLED, false);
+ apopEnabled = props.getBooleanProperty(MAIL_APOP_ENABLED, false);
+ topDisabled = props.getBooleanProperty(MAIL_DISABLE_TOP, false);
}
-
+
/**
* Connect to the server and do the initial handshaking.
*
* @exception MessagingException
*/
public boolean protocolConnect(String host, int port, String authid, String realm, String username, String password) throws MessagingException {
- this.serverHost = host;
- this.serverPort = port;
- this.realm = realm;
- this.authid = authid;
- this.username = username;
- this.password = password;
-
+ this.serverHost = host;
+ this.serverPort = port;
+ this.realm = realm;
+ this.authid = authid;
+ this.username = username;
+ this.password = password;
+
try {
// create socket and connect to server.
getConnection();
- // consume the welcome line
- getWelcome();
+ // consume the welcome line
+ getWelcome();
- // go login with the server
- if (login())
+ // go login with the server
+ if (login())
{
- loggedIn = true;
+ loggedIn = true;
return true;
}
- return false;
+ return false;
} catch (IOException e) {
if (debug) {
debugOut("I/O exception establishing connection", e);
@@ -147,23 +148,25 @@
protected void getConnection() throws MessagingException
{
try {
- // do all of the non-protocol specific set up. This will get our socket established
- // and ready use.
- super.getConnection();
+ // do all of the non-protocol specific set up. This will get our socket established
+ // and ready use.
+ super.getConnection();
} catch (IOException e) {
- throw new MessagingException("Unable to obtain a connection to the POP3 server", e);
+ throw new MessagingException("Unable to obtain a connection to the POP3 server", e);
}
-
- // The POp3 protocol is inherently a string-based protocol, so we get
- // string readers/writers for the connection streams
- reader = new BufferedReader(new InputStreamReader(inputStream));
- writer = new PrintWriter(new BufferedOutputStream(outputStream));
+
+ // The POp3 protocol is inherently a string-based protocol, so we get
+ // string readers/writers for the connection streams. Note that we explicitly
+ // set the encoding to ensure that an inappropriate native encoding is not picked up.
+ Charset iso88591 = Charset.forName("ISO8859-1");
+ reader = new BufferedReader(new InputStreamReader(inputStream, iso88591));
+ writer = new PrintWriter(new OutputStreamWriter(new BufferedOutputStream(outputStream), iso88591));
}
-
+
protected void getWelcome() throws IOException {
- // just read the line and consume it. If debug is
+ // just read the line and consume it. If debug is
// enabled, there I/O stream will be traced
- greeting = reader.readLine();
+ greeting = reader.readLine();
}
public String toString() {
@@ -184,70 +187,70 @@
}
try {
// say goodbye
- logout();
+ logout();
} finally {
// and close up the connection. We do this in a finally block to make sure the connection
// is shut down even if quit gets an error.
closeServerConnection();
- // get rid of our response processor too.
- reader = null;
- writer = null;
+ // get rid of our response processor too.
+ reader = null;
+ writer = null;
}
}
-
+
/**
- * Tag this connection as having been closed by the
- * server. This will not be returned to the
- * connection pool.
+ * Tag this connection as having been closed by the
+ * server. This will not be returned to the
+ * connection pool.
*/
public void setClosed() {
closed = true;
}
-
+
/**
* Test if the connnection has been forcibly closed.
- *
+ *
* @return True if the server disconnected the connection.
*/
public boolean isClosed() {
- return closed;
+ return closed;
}
-
+
protected POP3Response sendCommand(String cmd) throws MessagingException {
- return sendCommand(cmd, false);
+ return sendCommand(cmd, false);
}
-
+
protected POP3Response sendMultiLineCommand(String cmd) throws MessagingException {
- return sendCommand(cmd, true);
+ return sendCommand(cmd, true);
}
protected synchronized POP3Response sendCommand(String cmd, boolean multiLine) throws MessagingException {
if (socket.isConnected()) {
{
- // NOTE: We don't use println() because it uses the platform concept of a newline rather
- // than using CRLF, which is required by the POP3 protocol.
+ // NOTE: We don't use println() because it uses the platform concept of a newline rather
+ // than using CRLF, which is required by the POP3 protocol.
writer.write(cmd);
- writer.write("\r\n");
+ writer.write("\r\n");
writer.flush();
-
- POP3Response response = buildResponse(multiLine);
+
+ POP3Response response = buildResponse(multiLine);
if (response.isError()) {
- throw new CommandFailedException("Error issuing POP3 command: " + cmd);
+ throw new CommandFailedException("Error issuing POP3 command: " + cmd);
}
- return response;
+ return response;
}
}
throw new MessagingException("Connection to Mail Server is lost, connection " + this.toString());
}
-
+
/**
* Build a POP3Response item from the response stream.
- *
+ *
* @param isMultiLineResponse
* If true, this command is expecting multiple lines back from the server.
- *
- * @return A POP3Response item with all of the command response data.
+ *
+ * @return A POP3Response item with all of the command response data.
* @exception MessagingException
*/
protected POP3Response buildResponse(boolean isMultiLineResponse) throws MessagingException {
@@ -255,18 +258,18 @@
byte[] data = null;
String line;
- MIMEInputReader source = new MIMEInputReader(reader);
-
+ MIMEInputReader source = new MIMEInputReader(reader);
+
try {
line = reader.readLine();
} catch (IOException e) {
throw new MessagingException("Error in receving response");
}
-
+
if (line == null || line.trim().equals("")) {
throw new MessagingException("Empty Response");
}
-
+
if (line.startsWith("+OK")) {
status = OK;
line = removeStatusField(line);
@@ -297,314 +300,314 @@
*/
private byte[] getMultiLineResponse() throws MessagingException {
- MIMEInputReader source = new MIMEInputReader(reader);
-
+ MIMEInputReader source = new MIMEInputReader(reader);
+
ByteArrayOutputStream out = new ByteArrayOutputStream();
-
- // it's more efficient to do this a buffer at a time.
- // the MIMEInputReader takes care of the byte-stuffing and
- // ".\r\n" input terminator for us.
- OutputStreamWriter outWriter = new OutputStreamWriter(out);
- char buffer[] = new char[500];
+
+ // it's more efficient to do this a buffer at a time.
+ // the MIMEInputReader takes care of the byte-stuffing and
+ // ".\r\n" input terminator for us.
+ OutputStreamWriter outWriter = new OutputStreamWriter(out);
+ char buffer[] = new char[500];
try {
int charsRead = -1;
while ((charsRead = source.read(buffer)) >= 0) {
outWriter.write(buffer, 0, charsRead);
}
- outWriter.flush();
+ outWriter.flush();
} catch (IOException e) {
throw new MessagingException("Error processing a multi-line response", e);
}
-
+
return out.toByteArray();
}
-
-
+
+
/**
- * Retrieve the raw message content from the POP3
- * server. This is all of the message data, including
- * the header.
- *
+ * Retrieve the raw message content from the POP3
+ * server. This is all of the message data, including
+ * the header.
+ *
* @param sequenceNumber
* The message sequence number.
- *
- * @return A byte array containing all of the message data.
+ *
+ * @return A byte array containing all of the message data.
* @exception MessagingException
*/
public byte[] retrieveMessageData(int sequenceNumber) throws MessagingException {
- POP3Response msgResponse = sendMultiLineCommand("RETR " + sequenceNumber);
- // we want the data directly in this case.
- return msgResponse.getData();
+ POP3Response msgResponse = sendMultiLineCommand("RETR " + sequenceNumber);
+ // we want the data directly in this case.
+ return msgResponse.getData();
}
-
+
/**
- * Retrieve the message header information for a given
- * message, returned as an input stream suitable
+ * Retrieve the message header information for a given
+ * message, returned as an input stream suitable
* for loading the message data.
- *
+ *
* @param sequenceNumber
* The server sequence number for the message.
- *
- * @return An inputstream that can be used to read the message
+ *
+ * @return An inputstream that can be used to read the message
* data.
* @exception MessagingException
*/
public ByteArrayInputStream retrieveMessageHeaders(int sequenceNumber) throws MessagingException {
- POP3Response msgResponse;
-
- // some POP3 servers don't correctly implement TOP, so this can be disabled. If
- // we can't use TOP, then use RETR and retrieve everything. We can just hand back
- // the stream, as the header loading routine will stop at the first
- // null line.
+ POP3Response msgResponse;
+
+ // some POP3 servers don't correctly implement TOP, so this can be disabled. If
+ // we can't use TOP, then use RETR and retrieve everything. We can just hand back
+ // the stream, as the header loading routine will stop at the first
+ // null line.
if (topDisabled) {
- msgResponse = sendMultiLineCommand("RETR " + sequenceNumber);
+ msgResponse = sendMultiLineCommand("RETR " + sequenceNumber);
}
else {
- msgResponse = sendMultiLineCommand("TOP " + sequenceNumber + " 0");
+ msgResponse = sendMultiLineCommand("TOP " + sequenceNumber + " 0");
}
-
- // just load the returned message data as a set of headers
+
+ // just load the returned message data as a set of headers
return msgResponse.getContentStream();
}
-
+
/**
- * Retrieve the total message size from the mail
- * server. This is the size of the headers plus
- * the size of the message content.
- *
+ * Retrieve the total message size from the mail
+ * server. This is the size of the headers plus
+ * the size of the message content.
+ *
* @param sequenceNumber
* The message sequence number.
- *
+ *
* @return The full size of the message.
* @exception MessagingException
*/
public int retrieveMessageSize(int sequenceNumber) throws MessagingException {
- POP3Response msgResponse = sendCommand("LIST " + sequenceNumber);
- // Convert this into the parsed response type we need.
- POP3ListResponse list = new POP3ListResponse(msgResponse);
- // this returns the total message size
- return list.getSize();
+ POP3Response msgResponse = sendCommand("LIST " + sequenceNumber);
+ // Convert this into the parsed response type we need.
+ POP3ListResponse list = new POP3ListResponse(msgResponse);
+ // this returns the total message size
+ return list.getSize();
}
-
+
/**
* Retrieve the mail drop status information.
- *
- * @return An object representing the returned mail drop status.
+ *
+ * @return An object representing the returned mail drop status.
* @exception MessagingException
*/
public POP3StatusResponse retrieveMailboxStatus() throws MessagingException {
- // issue the STAT command and return this into a status response
- return new POP3StatusResponse(sendCommand("STAT"));
+ // issue the STAT command and return this into a status response
+ return new POP3StatusResponse(sendCommand("STAT"));
}
-
-
+
+
/**
* Retrieve the UID for an individual message.
- *
+ *
* @param sequenceNumber
* The target message sequence number.
- *
- * @return The string UID maintained by the server.
+ *
+ * @return The string UID maintained by the server.
* @exception MessagingException
*/
public String retrieveMessageUid(int sequenceNumber) throws MessagingException {
- POP3Response msgResponse = sendCommand("UIDL " + sequenceNumber);
-
- String message = msgResponse.getFirstLine();
- // the UID is everything after the blank separating the message number and the UID.
- // there's not supposed to be anything else on the message, but trim it of whitespace
- // just to be on the safe side.
- return message.substring(message.indexOf(' ') + 1).trim();
+ POP3Response msgResponse = sendCommand("UIDL " + sequenceNumber);
+
+ String message = msgResponse.getFirstLine();
+ // the UID is everything after the blank separating the message number and the UID.
+ // there's not supposed to be anything else on the message, but trim it of whitespace
+ // just to be on the safe side.
+ return message.substring(message.indexOf(' ') + 1).trim();
}
-
-
+
+
/**
* Delete a single message from the mail server.
- *
+ *
* @param sequenceNumber
* The sequence number of the message to delete.
- *
+ *
* @exception MessagingException
*/
public void deleteMessage(int sequenceNumber) throws MessagingException {
- // just issue the command...we ignore the command response
- sendCommand("DELE " + sequenceNumber);
+ // just issue the command...we ignore the command response
+ sendCommand("DELE " + sequenceNumber);
}
-
+
/**
- * Logout from the mail server. This sends a QUIT
+ * Logout from the mail server. This sends a QUIT
* command, which will likely sever the mail connection.
- *
+ *
* @exception MessagingException
*/
public void logout() throws MessagingException {
// we may have already sent the QUIT command
if (!loggedIn) {
- return;
+ return;
}
- // just issue the command...we ignore the command response
- sendCommand("QUIT");
- loggedIn = false;
+ // just issue the command...we ignore the command response
+ sendCommand("QUIT");
+ loggedIn = false;
}
-
+
/**
- * Perform a reset on the mail server.
- *
+ * Perform a reset on the mail server.
+ *
* @exception MessagingException
*/
public void reset() throws MessagingException {
- // some mail servers mark retrieved messages for deletion
- // automatically. This will reset the read flags before
- // we go through normal cleanup.
+ // some mail servers mark retrieved messages for deletion
+ // automatically. This will reset the read flags before
+ // we go through normal cleanup.
if (props.getBooleanProperty(MAIL_RESET_QUIT, false)) {
// just send an RSET command first
- sendCommand("RSET");
+ sendCommand("RSET");
}
}
-
+
/**
- * Ping the mail server to see if we still have an active connection.
- *
- * @exception MessagingException thrown if we do not have an active connection.
+ * Ping the mail server to see if we still have an active connection.
+ *
+ * @exception MessagingException thrown if we do not have an active connection.
*/
public void pingServer() throws MessagingException {
- // just issue the command...we ignore the command response
- sendCommand("NOOP");
+ // just issue the command...we ignore the command response
+ sendCommand("NOOP");
}
-
+
/**
- * Login to the mail server, using whichever method is
- * configured. This will try multiple methods, if allowed,
- * in decreasing levels of security.
- *
- * @return true if the login was successful.
+ * Login to the mail server, using whichever method is
+ * configured. This will try multiple methods, if allowed,
+ * in decreasing levels of security.
+ *
+ * @return true if the login was successful.
* @exception MessagingException
*/
public synchronized boolean login() throws MessagingException {
// permitted to use the AUTH command?
if (authEnabled) {
try {
- // go do the SASL thing
- return processSaslAuthentication();
+ // go do the SASL thing
+ return processSaslAuthentication();
} catch (MessagingException e) {
- // Any error here means fall back to the next mechanism
+ // Any error here means fall back to the next mechanism
}
}
-
+
if (apopEnabled) {
try {
- // go do the SASL thing
- return processAPOPAuthentication();
+ // go do the SASL thing
+ return processAPOPAuthentication();
} catch (MessagingException e) {
- // Any error here means fall back to the next mechanism
+ // Any error here means fall back to the next mechanism
}
}
-
+
try {
- // do the tried and true login processing.
- return processLogin();
+ // do the tried and true login processing.
+ return processLogin();
} catch (MessagingException e) {
}
- // everything failed...can't get in
- return false;
+ // everything failed...can't get in
+ return false;
}
-
-
+
+
/**
- * Process a basic LOGIN operation, using the
- * plain test USER/PASS command combo.
- *
- * @return true if we logged successfully.
+ * Process a basic LOGIN operation, using the
+ * plain test USER/PASS command combo.
+ *
+ * @return true if we logged successfully.
* @exception MessagingException
*/
public boolean processLogin() throws MessagingException {
- // start by sending the USER command, followed by
+ // start by sending the USER command, followed by
// the PASS command
- sendCommand("USER " + username);
- sendCommand("PASS " + password);
- return true; // we're in
+ sendCommand("USER " + username);
+ sendCommand("PASS " + password);
+ return true; // we're in
}
-
+
/**
- * Process logging in using the APOP command. Only
- * works on servers that give a timestamp value
- * in the welcome response.
- *
- * @return true if the login was accepted.
+ * Process logging in using the APOP command. Only
+ * works on servers that give a timestamp value
+ * in the welcome response.
+ *
+ * @return true if the login was accepted.
* @exception MessagingException
*/
public boolean processAPOPAuthentication() throws MessagingException {
- int timeStart = greeting.indexOf('<');
- // if we didn't get an APOP challenge on the greeting, throw an exception
- // the main login processor will swallow that and fall back to the next
- // mechanism
+ int timeStart = greeting.indexOf('<');
+ // if we didn't get an APOP challenge on the greeting, throw an exception
+ // the main login processor will swallow that and fall back to the next
+ // mechanism
if (timeStart == -1) {
- throw new MessagingException("POP3 Server does not support APOP");
+ throw new MessagingException("POP3 Server does not support APOP");
}
- int timeEnd = greeting.indexOf('>');
- String timeStamp = greeting.substring(timeStart, timeEnd + 1);
-
- // we create the digest password using the timestamp value sent to use
- // concatenated with the password.
- String digestPassword = timeStamp + password;
-
- byte[] digest;
-
+ int timeEnd = greeting.indexOf('>');
+ String timeStamp = greeting.substring(timeStart, timeEnd + 1);
+
+ // we create the digest password using the timestamp value sent to use
+ // concatenated with the password.
+ String digestPassword = timeStamp + password;
+
+ byte[] digest;
+
try {
- // create a digest value from the password.
- MessageDigest md = MessageDigest.getInstance("MD5");
- digest = md.digest(digestPassword.getBytes("iso-8859-1"));
+ // create a digest value from the password.
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ digest = md.digest(digestPassword.getBytes("iso-8859-1"));
} catch (NoSuchAlgorithmException e) {
- // this shouldn't happen, but if it does, we'll just try a plain
- // login.
- throw new MessagingException("Unable to create MD5 digest", e);
+ // this shouldn't happen, but if it does, we'll just try a plain
+ // login.
+ throw new MessagingException("Unable to create MD5 digest", e);
} catch (UnsupportedEncodingException e) {
- // this shouldn't happen, but if it does, we'll just try a plain
- // login.
- throw new MessagingException("Unable to create MD5 digest", e);
+ // this shouldn't happen, but if it does, we'll just try a plain
+ // login.
+ throw new MessagingException("Unable to create MD5 digest", e);
}
// this will throw an exception if it gives an error failure
- sendCommand("APOP " + username + " " + Hex.encode(digest));
- // no exception, we must have passed
- return true;
+ sendCommand("APOP " + username + " " + Hex.encode(digest));
+ // no exception, we must have passed
+ return true;
}
-
+
/**
* Process SASL-type authentication.
- *
+ *
* @return Returns true if the server support a SASL authentication mechanism and
* accepted reponse challenges.
* @exception MessagingException
*/
protected boolean processSaslAuthentication() throws MessagingException {
- // if unable to get an appropriate authenticator, just fail it.
- ClientAuthenticator authenticator = getSaslAuthenticator();
+ // if unable to get an appropriate authenticator, just fail it.
+ ClientAuthenticator authenticator = getSaslAuthenticator();
if (authenticator == null) {
- throw new MessagingException("Unable to obtain SASL authenticator");
+ throw new MessagingException("Unable to obtain SASL authenticator");
}
-
+
// go process the login.
return processLogin(authenticator);
}
-
+
/**
- * Attempt to retrieve a SASL authenticator for this
- * protocol.
- *
- * @return A SASL authenticator, or null if a suitable one
+ * Attempt to retrieve a SASL authenticator for this
+ * protocol.
+ *
+ * @return A SASL authenticator, or null if a suitable one
* was not located.
*/
protected ClientAuthenticator getSaslAuthenticator() {
- return AuthenticatorFactory.getAuthenticator(props, selectSaslMechanisms(), serverHost, username, password, authid, realm);
+ return AuthenticatorFactory.getAuthenticator(props, selectSaslMechanisms(), serverHost, username, password, authid, realm);
}
/**
* Process a login using the provided authenticator object.
- *
- * NB: This method is synchronized because we have a multi-step process going on
- * here. No other commands should be sent to the server until we complete.
+ *
+ * NB: This method is synchronized because we have a multi-step process going on
+ * here. No other commands should be sent to the server until we complete.
*
* @return Returns true if the server support a SASL authentication mechanism and
* accepted reponse challenges.
@@ -615,41 +618,44 @@
debugOut("Authenticating for user: " + username + " using " + authenticator.getMechanismName());
}
- POP3Response response = sendCommand("AUTH " + authenticator.getMechanismName());
+ POP3Response response = sendCommand("AUTH " + authenticator.getMechanismName());
- // now process the challenge sequence. We get a continuation response back for each stage of the
- // authentication, and finally an OK when everything passes muster.
+ // now process the challenge sequence. We get a continuation response back for each stage of the
+ // authentication, and finally an OK when everything passes muster.
while (true) {
// this should be a continuation reply, if things are still good.
if (response.isChallenge()) {
// we're passed back a challenge value, Base64 encoded.
byte[] challenge = response.decodeChallengeResponse();
-
- String responseString = new String(Base64.encode(authenticator.evaluateChallenge(challenge)));
- // have the authenticator evaluate and send back the encoded response.
- response = sendCommand(responseString);
+ try {
+ String responseString = new String(Base64.encode(authenticator.evaluateChallenge(challenge)), "US_ASCII");
+
+ // have the authenticator evaluate and send back the encoded response.
+ response = sendCommand(responseString);
+ } catch (UnsupportedEncodingException ex) {
+ }
}
else {
- // there are only two choices here, OK or a continuation. OK means
- // we've passed muster and are in.
- return true;
+ // there are only two choices here, OK or a continuation. OK means
+ // we've passed muster and are in.
+ return true;
}
}
}
-
-
+
+
/**
- * Merge the configured SASL mechanisms with the capabilities that the
- * server has indicated it supports, returning a merged list that can
- * be used for selecting a mechanism.
- *
- * @return A List representing the intersection of the configured list and the
+ * Merge the configured SASL mechanisms with the capabilities that the
+ * server has indicated it supports, returning a merged list that can
+ * be used for selecting a mechanism.
+ *
+ * @return A List representing the intersection of the configured list and the
* capabilities list.
*/
protected List selectSaslMechanisms() {
- // just return the set that have been explicity permitted
- return getSaslMechanisms();
+ // just return the set that have been explicity permitted
+ return getSaslMechanisms();
}
}
diff --git a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/transport/nntp/NNTPConnection.java b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/transport/nntp/NNTPConnection.java
index de490dc..5b2db9c 100644
--- a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/transport/nntp/NNTPConnection.java
+++ b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/transport/nntp/NNTPConnection.java
@@ -20,18 +20,20 @@
package org.apache.geronimo.javamail.transport.nntp;
import java.io.BufferedReader;
-import java.io.BufferedOutputStream;
+import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.Socket;
-import java.util.ArrayList;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.StringTokenizer;
@@ -40,17 +42,17 @@
import javax.mail.MessagingException;
import javax.mail.Session;
-import org.apache.geronimo.javamail.authentication.ClientAuthenticator;
-import org.apache.geronimo.javamail.authentication.AuthenticatorFactory;
-import org.apache.geronimo.javamail.util.MailConnection;
+import org.apache.geronimo.javamail.authentication.ClientAuthenticator;
+import org.apache.geronimo.javamail.authentication.AuthenticatorFactory;
+import org.apache.geronimo.javamail.util.MailConnection;
import org.apache.geronimo.javamail.util.MIMEOutputStream;
-import org.apache.geronimo.javamail.util.ProtocolProperties;
+import org.apache.geronimo.javamail.util.ProtocolProperties;
import org.apache.geronimo.mail.util.Base64;
import org.apache.geronimo.mail.util.SessionUtil;
/**
* Simple implementation of NNTP transport. Just does plain RFC977-ish delivery.
- *
+ *
* @version $Rev$ $Date$
*/
public class NNTPConnection extends MailConnection {
@@ -68,53 +70,53 @@
protected static final int DEFAULT_NNTP_PORT = 119;
// does the server support posting?
protected boolean postingAllowed = true;
-
- // different authentication mechanisms
- protected boolean authInfoUserAllowed = false;
- protected boolean authInfoSaslAllowed = false;
-
+
+ // different authentication mechanisms
+ protected boolean authInfoUserAllowed = false;
+ protected boolean authInfoSaslAllowed = false;
+
// the last response line received from the server.
protected NNTPReply lastServerResponse = null;
// the welcome string from the server.
protected String welcomeString = null;
-
- // input reader wrapped around the socket input stream
- protected BufferedReader reader;
- // output writer wrapped around the socket output stream.
- protected PrintWriter writer;
+
+ // input reader wrapped around the socket input stream
+ protected BufferedReader reader;
+ // output writer wrapped around the socket output stream.
+ protected PrintWriter writer;
/**
* Normal constructor for an NNTPConnection() object.
- *
+ *
* @param props The property bundle for this protocol instance.
*/
public NNTPConnection(ProtocolProperties props) {
super(props);
}
-
-
+
+
/**
* Connect to the server and do the initial handshaking.
- *
+ *
* @param host The target host name.
* @param port The target port
* @param username The connection username (can be null)
* @param password The authentication password (can be null).
- *
- * @return true if we were able to obtain a connection and
+ *
+ * @return true if we were able to obtain a connection and
* authenticate.
* @exception MessagingException
*/
public boolean protocolConnect(String host, int port, String username, String password) throws MessagingException {
- super.protocolConnect(host, port, username, password);
+ super.protocolConnect(host, port, username, password);
// create socket and connect to server.
getConnection();
// receive welcoming message
getWelcome();
-
- return true;
+
+ return true;
}
@@ -127,24 +129,26 @@
protected void getConnection() throws MessagingException
{
try {
- // do all of the non-protocol specific set up. This will get our socket established
- // and ready use.
- super.getConnection();
+ // do all of the non-protocol specific set up. This will get our socket established
+ // and ready use.
+ super.getConnection();
} catch (IOException e) {
- throw new MessagingException("Unable to obtain a connection to the NNTP server", e);
+ throw new MessagingException("Unable to obtain a connection to the NNTP server", e);
}
-
- // The NNTP protocol is inherently a string-based protocol, so we get
- // string readers/writers for the connection streams
- reader = new BufferedReader(new InputStreamReader(inputStream));
+
+ // The NNTP protocol is inherently a string-based protocol, so we get
+ // string readers/writers for the connection streams. Note that we explicitly
+ // set the encoding to ensure that an inappropriate native encoding is not picked up.
+ Charset iso88591 = Charset.forName("ISO8859-1");
+ reader = new BufferedReader(new InputStreamReader(inputStream, iso88591));
writer = new PrintWriter(new BufferedOutputStream(outputStream));
}
-
+
/**
* Close the connection. On completion, we'll be disconnected from the
* server and unable to send more data.
- *
+ *
* @exception MessagingException
*/
public void close() throws MessagingException {
@@ -160,16 +164,16 @@
// make sure the connection
// is shut down even if quit gets an error.
closeServerConnection();
- // get rid of our response processor too.
- reader = null;
- writer = null;
+ // get rid of our response processor too.
+ reader = null;
+ writer = null;
}
}
public String toString() {
return "NNTPConnection host: " + serverHost + " port: " + serverPort;
}
-
+
/**
* Get the servers welcome blob from the wire....
@@ -196,32 +200,32 @@
getExtensions();
}
-
+
/**
* Sends the QUIT message and receieves the response
*/
public void sendQuit() throws MessagingException {
sendLine("QUIT");
}
-
+
/**
* Tell the server to switch to a named group.
- *
+ *
* @param name
* The name of the target group.
- *
+ *
* @return The server response to the GROUP command.
*/
public NNTPReply selectGroup(String name) throws MessagingException {
// send the GROUP command
return sendCommand("GROUP " + name);
}
-
+
/**
* Ask the server what extensions it supports.
- *
+ *
* @return True if the command was accepted ok, false for any errors.
* @exception MessagingException
*/
@@ -237,7 +241,7 @@
// get a fresh extension mapping table.
capabilities = new HashMap();
- authentications = new ArrayList();
+ authentications = new ArrayList();
// get the extension data lines.
List extensions = reply.getData();
@@ -249,10 +253,10 @@
}
}
-
+
/**
* Process an extension string passed back as the LIST EXTENSIONS response.
- *
+ *
* @param extension
* The string value of the extension (which will be of the form
* "NAME arguments").
@@ -272,18 +276,18 @@
// add this to the map so it can be tested later.
capabilities.put(extensionName, argument);
- // we need to determine which authentication mechanisms are supported here
+ // we need to determine which authentication mechanisms are supported here
if (extensionName.equals("AUTHINFO")) {
- StringTokenizer tokenizer = new StringTokenizer(argument);
-
+ StringTokenizer tokenizer = new StringTokenizer(argument);
+
while (tokenizer.hasMoreTokens()) {
- // we only know how to do USER or SASL
+ // we only know how to do USER or SASL
String mechanism = tokenizer.nextToken().toUpperCase();
if (mechanism.equals("SASL")) {
- authInfoSaslAllowed = true;
+ authInfoSaslAllowed = true;
}
else if (mechanism.equals("USER")) {
- authInfoUserAllowed = true;
+ authInfoUserAllowed = true;
}
}
}
@@ -298,15 +302,15 @@
}
}
}
-
+
/**
* Retrieve any argument information associated with a extension reported
* back by the server on the EHLO command.
- *
+ *
* @param name
* The name of the target server extension.
- *
+ *
* @return Any argument passed on a server extension. Returns null if the
* extension did not include an argument or the extension was not
* supported.
@@ -320,10 +324,10 @@
/**
* Tests whether the target server supports a named extension.
- *
+ *
* @param name
* The target extension name.
- *
+ *
* @return true if the target server reported on the EHLO command that is
* supports the targer server, false if the extension was not
* supported.
@@ -333,7 +337,7 @@
return extensionParameter(name) != null;
}
-
+
/**
* Sends the data in the message down the socket. This presumes the server
* is in the right place and ready for getting the DATA message and the data
@@ -370,9 +374,9 @@
msg.writeTo(mimeOut);
// now to finish, we send a CRLF sequence, followed by a ".".
- mimeOut.writeSMTPTerminator();
- // and flush the data to send it along
- mimeOut.flush();
+ mimeOut.writeSMTPTerminator();
+ // and flush the data to send it along
+ mimeOut.flush();
} catch (IOException e) {
throw new MessagingException("I/O error posting message", e);
} catch (MessagingException e) {
@@ -392,13 +396,13 @@
* Issue a command and retrieve the response. If the given success indicator
* is received, the command is returning a longer response, terminated by a
* "crlf.crlf" sequence. These lines are attached to the reply.
- *
+ *
* @param command
* The command to issue.
* @param success
* The command reply that indicates additional data should be
* retrieved.
- *
+ *
* @return The command reply.
*/
public synchronized NNTPReply sendCommand(String command, int success) throws MessagingException {
@@ -412,10 +416,10 @@
/**
* Send a command to the server, returning the first response line back as a
* reply.
- *
+ *
* @param data
* The data to send.
- *
+ *
* @return A reply object with the reply line.
* @exception MessagingException
*/
@@ -441,10 +445,10 @@
/**
* Send a command to the server, returning the first response line back as a
* reply.
- *
+ *
* @param data
* The data to send.
- *
+ *
* @return A reply object with the reply line.
* @exception MessagingException
*/
@@ -461,7 +465,7 @@
throw new MessagingException("no connection");
}
try {
- outputStream.write(data.getBytes());
+ outputStream.write(data.getBytes("ISO8859-1"));
outputStream.write(CR);
outputStream.write(LF);
outputStream.flush();
@@ -472,7 +476,7 @@
/**
* Get a reply line for an NNTP command.
- *
+ *
* @return An NNTP reply object from the stream.
*/
public NNTPReply getReply() throws MessagingException {
@@ -482,7 +486,7 @@
/**
* Retrieve the last response received from the NNTP server.
- *
+ *
* @return The raw response string (including the error code) returned from
* the NNTP server.
*/
@@ -496,7 +500,7 @@
/**
* Receives one line from the server. A line is a sequence of bytes
* terminated by a CRLF
- *
+ *
* @return the line from the server as String
*/
public String receiveLine() throws MessagingException {
@@ -515,7 +519,7 @@
}
}
-
+
/**
* Authenticate with the server, if necessary (or possible).
*/
@@ -539,7 +543,7 @@
/**
* Process an AUTHINFO SIMPLE command. Not widely used, but if the server
* asks for it, we can respond.
- *
+ *
* @exception MessagingException
*/
protected void processAuthinfoSimple() throws MessagingException {
@@ -553,46 +557,46 @@
}
}
-
+
/**
* Process SASL-type authentication.
- *
+ *
* @return Returns true if the server support a SASL authentication mechanism and
* accepted reponse challenges.
* @exception MessagingException
*/
protected boolean processSaslAuthentication() throws MessagingException {
- // only do this if permitted
+ // only do this if permitted
if (!authInfoSaslAllowed) {
- return false;
+ return false;
}
- // if unable to get an appropriate authenticator, just fail it.
- ClientAuthenticator authenticator = getSaslAuthenticator();
+ // if unable to get an appropriate authenticator, just fail it.
+ ClientAuthenticator authenticator = getSaslAuthenticator();
if (authenticator == null) {
- throw new MessagingException("Unable to obtain SASL authenticator");
+ throw new MessagingException("Unable to obtain SASL authenticator");
}
-
+
// go process the login.
return processLogin(authenticator);
}
-
+
/**
- * Attempt to retrieve a SASL authenticator for this
- * protocol.
- *
- * @return A SASL authenticator, or null if a suitable one
+ * Attempt to retrieve a SASL authenticator for this
+ * protocol.
+ *
+ * @return A SASL authenticator, or null if a suitable one
* was not located.
*/
protected ClientAuthenticator getSaslAuthenticator() {
- return AuthenticatorFactory.getAuthenticator(props, selectSaslMechanisms(), serverHost, username, password, authid, realm);
+ return AuthenticatorFactory.getAuthenticator(props, selectSaslMechanisms(), serverHost, username, password, authid, realm);
}
/**
* Process a login using the provided authenticator object.
- *
- * NB: This method is synchronized because we have a multi-step process going on
- * here. No other commands should be sent to the server until we complete.
+ *
+ * NB: This method is synchronized because we have a multi-step process going on
+ * here. No other commands should be sent to the server until we complete.
*
* @return Returns true if the server support a SASL authentication mechanism and
* accepted reponse challenges.
@@ -611,7 +615,10 @@
command.append(authenticator.getMechanismName());
command.append(" ");
// and append the response data
- command.append(new String(Base64.encode(authenticator.evaluateChallenge(null))));
+ try {
+ command.append(new String(Base64.encode(authenticator.evaluateChallenge(null)), "US-ASCII"));
+ } catch (UnsupportedEncodingException e) {
+ }
// send the command now
sendLine(command.toString());
}
@@ -650,11 +657,14 @@
}
// we're passed back a challenge value, Base64 encoded.
- byte[] challenge = Base64.decode(line.getMessage().getBytes());
+ try {
+ byte[] challenge = Base64.decode(line.getMessage().getBytes("ISO8859-1"));
- // have the authenticator evaluate and send back the encoded
- // response.
- sendLine(new String(Base64.encode(authenticator.evaluateChallenge(challenge))));
+ // have the authenticator evaluate and send back the encoded
+ // response.
+ sendLine(new String(Base64.encode(authenticator.evaluateChallenge(challenge)), "US-ASCII"));
+ } catch (UnsupportedEncodingException e) {
+ }
}
// completion or challenge are the only responses we know how to
// handle. Anything else must
@@ -666,17 +676,17 @@
}
}
-
+
/**
* Process an AUTHINFO USER command. Most common form of NNTP
* authentication.
- *
+ *
* @exception MessagingException
*/
protected void processAuthinfoUser() throws MessagingException {
- // only do this if allowed by the server
+ // only do this if allowed by the server
if (!authInfoUserAllowed) {
- return;
+ return;
}
NNTPReply reply = sendAuthCommand("AUTHINFO USER " + username);
// accepted without a password (uncommon, but allowed), we're done
@@ -694,10 +704,10 @@
}
}
-
+
/**
* Indicate whether posting is allowed for a given server.
- *
+ *
* @return True if the server allows posting, false if the server is
* read-only.
*/
@@ -707,7 +717,7 @@
/**
* Retrieve the welcome string sent back from the server.
- *
+ *
* @return The server provided welcome string.
*/
public String getWelcomeString() {
diff --git a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/transport/smtp/SMTPConnection.java b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/transport/smtp/SMTPConnection.java
index 32f7572..5abe7e9 100644
--- a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/transport/smtp/SMTPConnection.java
+++ b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/transport/smtp/SMTPConnection.java
@@ -19,21 +19,16 @@
package org.apache.geronimo.javamail.transport.smtp;
-import java.io.BufferedReader;
-import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.InputStreamReader;
import java.io.OutputStream;
-import java.io.PrintStream;
-import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.Socket;
-import java.net.SocketException;
-import java.util.ArrayList;
+import java.net.SocketException;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.StringTokenizer;
@@ -43,23 +38,23 @@
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.internet.InternetAddress;
-import javax.mail.internet.MimeMessage;
-import javax.mail.internet.MimeMultipart;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimePart;
import javax.mail.Session;
-import org.apache.geronimo.javamail.authentication.ClientAuthenticator;
-import org.apache.geronimo.javamail.authentication.AuthenticatorFactory;
+import org.apache.geronimo.javamail.authentication.ClientAuthenticator;
+import org.apache.geronimo.javamail.authentication.AuthenticatorFactory;
import org.apache.geronimo.javamail.util.CountingOutputStream;
-import org.apache.geronimo.javamail.util.MailConnection;
+import org.apache.geronimo.javamail.util.MailConnection;
import org.apache.geronimo.javamail.util.MIMEOutputStream;
-import org.apache.geronimo.javamail.util.ProtocolProperties;
+import org.apache.geronimo.javamail.util.ProtocolProperties;
import org.apache.geronimo.mail.util.Base64;
import org.apache.geronimo.mail.util.XText;
/**
* Simple implementation of SMTP transport. Just does plain RFC977-ish delivery.
- *
+ *
* @version $Rev$ $Date$
*/
public class SMTPConnection extends MailConnection {
@@ -78,15 +73,10 @@
* property keys for protocol properties.
*/
protected static final int DEFAULT_NNTP_PORT = 119;
-
+
// the last response line received from the server.
protected SMTPReply lastServerResponse = null;
-
- // input reader wrapped around the socket input stream
- protected BufferedReader reader;
- // output writer wrapped around the socket output stream.
- protected PrintWriter writer;
-
+
// do we report success after completion of each mail send.
protected boolean reportSuccess;
// does the server support transport level security?
@@ -94,34 +84,34 @@
// is TLS enabled on our part?
protected boolean useTLS = false;
// should we use 8BITMIME encoding if supported by the server?
- protected boolean use8bit = false;
+ protected boolean use8bit = false;
/**
* Normal constructor for an SMTPConnection() object.
- *
+ *
* @param props The property bundle for this protocol instance.
*/
public SMTPConnection(ProtocolProperties props) {
super(props);
-
+
// check to see if we need to throw an exception after a send operation.
reportSuccess = props.getBooleanProperty(MAIL_SMTP_REPORT_SUCCESS, false);
// and also check for TLS enablement.
useTLS = props.getBooleanProperty(MAIL_SMTP_STARTTLS_ENABLE, false);
- // and also check for 8bitmime support
+ // and also check for 8bitmime support
use8bit = props.getBooleanProperty(MAIL_SMTP_ALLOW8BITMIME, false);
}
-
-
+
+
/**
* Connect to the server and do the initial handshaking.
- *
+ *
* @param host The target host name.
* @param port The target port
* @param username The connection username (can be null)
* @param password The authentication password (can be null).
- *
- * @return true if we were able to obtain a connection and
+ *
+ * @return true if we were able to obtain a connection and
* authenticate.
* @exception MessagingException
*/
@@ -142,22 +132,22 @@
debugOut("Failing connection for missing authentication information");
return false;
}
-
- super.protocolConnect(host, port, username, password);
-
+
+ super.protocolConnect(host, port, username, password);
+
try {
// create socket and connect to server.
getConnection();
// receive welcoming message
if (!getWelcome()) {
- debugOut("Error getting welcome message");
+ debugOut("Error getting welcome message");
throw new MessagingException("Error in getting welcome msg");
}
// say hello
if (!sendHandshake()) {
- debugOut("Error getting processing handshake message");
+ debugOut("Error getting processing handshake message");
throw new MessagingException("Error in saying EHLO to server");
}
@@ -170,15 +160,15 @@
debugOut("I/O exception establishing connection", e);
throw new MessagingException("Connection error", e);
}
- debugOut("Successful connection");
+ debugOut("Successful connection");
return true;
}
-
+
/**
* Close the connection. On completion, we'll be disconnected from the
* server and unable to send more data.
- *
+ *
* @exception MessagingException
*/
public void close() throws MessagingException {
@@ -201,14 +191,14 @@
return "SMTPConnection host: " + serverHost + " port: " + serverPort;
}
-
+
/**
* Set the sender for this mail.
- *
+ *
* @param message
* The message we're sending.
- *
- * @return True if the command was accepted, false otherwise.
+ *
+ * @return True if the command was accepted, false otherwise.
* @exception MessagingException
*/
protected boolean sendMailFrom(Message message) throws MessagingException {
@@ -242,7 +232,7 @@
else {
InternetAddress local = InternetAddress.getLocalAddress(session);
if (local != null) {
- from = local.getAddress();
+ from = local.getAddress();
}
}
}
@@ -256,32 +246,32 @@
// start building up the command
command.append("MAIL FROM: ");
command.append(fixEmailAddress(from));
-
- // If the server supports the 8BITMIME extension, we might need to change the
- // transfer encoding for the content to allow for direct transmission of the
- // 8-bit codes.
+
+ // If the server supports the 8BITMIME extension, we might need to change the
+ // transfer encoding for the content to allow for direct transmission of the
+ // 8-bit codes.
if (supportsExtension("8BITMIME")) {
- // we only do this if the capability was enabled via a property option or
- // by explicitly setting the property on the message object.
+ // we only do this if the capability was enabled via a property option or
+ // by explicitly setting the property on the message object.
if (use8bit || (message instanceof SMTPMessage && ((SMTPMessage)message).getAllow8bitMIME())) {
- // make sure we add the BODY= option to the FROM message.
- command.append(" BODY=8BITMIME");
-
- // go check the content and see if the can convert the transfer encoding to
- // allow direct 8-bit transmission.
+ // make sure we add the BODY= option to the FROM message.
+ command.append(" BODY=8BITMIME");
+
+ // go check the content and see if the can convert the transfer encoding to
+ // allow direct 8-bit transmission.
if (convertTransferEncoding((MimeMessage)message)) {
- // if we changed the encoding on any of the parts, then we
- // need to save the message again
- message.saveChanges();
+ // if we changed the encoding on any of the parts, then we
+ // need to save the message again
+ message.saveChanges();
}
}
}
-
- // some servers ask for a size estimate on the initial send
+
+ // some servers ask for a size estimate on the initial send
if (supportsExtension("SIZE")) {
- int estimate = getSizeEstimate(message);
+ int estimate = getSizeEstimate(message);
if (estimate > 0) {
- command.append(" SIZE=" + estimate);
+ command.append(" SIZE=" + estimate);
}
}
@@ -342,7 +332,7 @@
command.append(" AUTH=");
try {
// add this encoded
- command.append(new String(XText.encode(submitter.getBytes("US-ASCII"))));
+ command.append(new String(XText.encode(submitter.getBytes("US-ASCII")), "US-ASCII"));
} catch (UnsupportedEncodingException e) {
throw new MessagingException("Invalid submitter value " + submitter);
}
@@ -375,70 +365,70 @@
// 250 response indicates success.
return line.getCode() == SMTPReply.COMMAND_ACCEPTED;
}
-
-
+
+
/**
- * Check to see if a MIME body part can have its
+ * Check to see if a MIME body part can have its
* encoding changed from quoted-printable or base64
- * encoding to 8bit encoding. In order for this
- * to work, it must follow the rules laid out in
- * RFC 2045. To qualify for conversion, the text
- * must be:
- *
- * 1) No more than 998 bytes long
+ * encoding to 8bit encoding. In order for this
+ * to work, it must follow the rules laid out in
+ * RFC 2045. To qualify for conversion, the text
+ * must be:
+ *
+ * 1) No more than 998 bytes long
* 2) All lines are terminated with CRLF sequences
- * 3) CR and LF characters only occur in properly
- * formed line separators
- * 4) No null characters are allowed.
- *
- * The conversion will only be applied to text
- * elements, and this will recurse through the
- * different elements of MultiPart content.
- *
+ * 3) CR and LF characters only occur in properly
+ * formed line separators
+ * 4) No null characters are allowed.
+ *
+ * The conversion will only be applied to text
+ * elements, and this will recurse through the
+ * different elements of MultiPart content.
+ *
* @param bodyPart The bodyPart to convert. Initially, this will be
* the message itself.
- *
- * @return true if any conversion was performed, false if
+ *
+ * @return true if any conversion was performed, false if
* nothing was converted.
*/
protected boolean convertTransferEncoding(MimePart bodyPart)
{
- boolean converted = false;
+ boolean converted = false;
try {
- // if this is a multipart element, apply the conversion rules
- // to each of the parts.
+ // if this is a multipart element, apply the conversion rules
+ // to each of the parts.
if (bodyPart.isMimeType("multipart/")) {
- MimeMultipart parts = (MimeMultipart)bodyPart.getContent();
+ MimeMultipart parts = (MimeMultipart)bodyPart.getContent();
for (int i = 0; i < parts.getCount(); i++) {
- // convert each body part, and accumulate the conversion result
- converted = converted && convertTransferEncoding((MimePart)parts.getBodyPart(i));
+ // convert each body part, and accumulate the conversion result
+ converted = converted && convertTransferEncoding((MimePart)parts.getBodyPart(i));
}
}
else {
// we only do this if the encoding is quoted-printable or base64
- String encoding = bodyPart.getEncoding();
+ String encoding = bodyPart.getEncoding();
if (encoding != null) {
- encoding = encoding.toLowerCase();
+ encoding = encoding.toLowerCase();
if (encoding.equals("quoted-printable") || encoding.equals("base64")) {
- // this requires encoding. Read the actual content to see if
- // it conforms to the 8bit encoding rules.
+ // this requires encoding. Read the actual content to see if
+ // it conforms to the 8bit encoding rules.
if (isValid8bit(bodyPart.getInputStream())) {
- // There's a huge hidden gotcha lurking under the covers here.
- // If the content just exists as an encoded byte array, then just
- // switching the transfer encoding will mess things up because the
- // already encoded data gets transmitted in encoded form, but with
- // and 8bit encoding style. As a result, it doesn't get unencoded on
- // the receiving end. This is a nasty problem to debug.
+ // There's a huge hidden gotcha lurking under the covers here.
+ // If the content just exists as an encoded byte array, then just
+ // switching the transfer encoding will mess things up because the
+ // already encoded data gets transmitted in encoded form, but with
+ // and 8bit encoding style. As a result, it doesn't get unencoded on
+ // the receiving end. This is a nasty problem to debug.
//
- // The solution is to get the content as it's object type, set it back
- // on the the message in raw form. Requesting the content will apply the
- // current transfer encoding value to the data. Once we have set the
- // content value back, we can reset the transfer encoding.
- bodyPart.setContent(bodyPart.getContent(), bodyPart.getContentType());
-
- // it's valid, so change the transfer encoding to just
- // pass the data through.
- bodyPart.setHeader("Content-Transfer-Encoding", "8bit");
+ // The solution is to get the content as it's object type, set it back
+ // on the the message in raw form. Requesting the content will apply the
+ // current transfer encoding value to the data. Once we have set the
+ // content value back, we can reset the transfer encoding.
+ bodyPart.setContent(bodyPart.getContent(), bodyPart.getContentType());
+
+ // it's valid, so change the transfer encoding to just
+ // pass the data through.
+ bodyPart.setHeader("Content-Transfer-Encoding", "8bit");
converted = true; // we've changed something
}
}
@@ -447,36 +437,36 @@
} catch (MessagingException e) {
} catch (IOException e) {
}
- return converted;
+ return converted;
}
-
+
/**
* Get the server's welcome blob from the wire....
*/
protected boolean getWelcome() throws MessagingException {
SMTPReply line = getReply();
- // just return the error status...we don't care about any of the
+ // just return the error status...we don't care about any of the
// response information
return !line.isError();
}
-
-
+
+
/**
- * Get an estimate of the transmission size for this
- * message. This size is the complete message as it is
- * encoded and transmitted on the DATA command, not counting
- * the terminating ".CRLF".
- *
+ * Get an estimate of the transmission size for this
+ * message. This size is the complete message as it is
+ * encoded and transmitted on the DATA command, not counting
+ * the terminating ".CRLF".
+ *
* @param msg The message we're sending.
- *
- * @return The count of bytes, if it can be calculated.
+ *
+ * @return The count of bytes, if it can be calculated.
*/
protected int getSizeEstimate(Message msg) {
// now the data... I could look at the type, but
try {
- CountingOutputStream outputStream = new CountingOutputStream();
-
+ CountingOutputStream outputStream = new CountingOutputStream();
+
// the data content has two requirements we need to meet by
// filtering the
// output stream. Requirement 1 is to conicalize any line breaks.
@@ -495,19 +485,19 @@
msg.writeTo(mimeOut);
- // now to finish, we make sure there's a line break at the end.
- mimeOut.forceTerminatingLineBreak();
- // and flush the data to send it along
- mimeOut.flush();
-
- return outputStream.getCount();
+ // now to finish, we make sure there's a line break at the end.
+ mimeOut.forceTerminatingLineBreak();
+ // and flush the data to send it along
+ mimeOut.flush();
+
+ return outputStream.getCount();
} catch (IOException e) {
- return 0; // can't get an estimate
+ return 0; // can't get an estimate
} catch (MessagingException e) {
- return 0; // can't get an estimate
+ return 0; // can't get an estimate
}
}
-
+
/**
* Sends the data in the message down the socket. This presumes the server
@@ -544,9 +534,9 @@
msg.writeTo(mimeOut);
// now to finish, we send a CRLF sequence, followed by a ".".
- mimeOut.writeSMTPTerminator();
- // and flush the data to send it along
- mimeOut.flush();
+ mimeOut.writeSMTPTerminator();
+ // and flush the data to send it along
+ mimeOut.flush();
} catch (IOException e) {
throw new MessagingException(e.toString());
} catch (MessagingException e) {
@@ -573,14 +563,14 @@
*/
protected void sendQuit() throws MessagingException {
// there's yet another property that controls whether we should wait for
- // a reply for a QUIT command. If true, we're suppposed to wait for a response
- // from the QUIT command. Otherwise we just send the QUIT and bail. The default
+ // a reply for a QUIT command. If true, we're suppposed to wait for a response
+ // from the QUIT command. Otherwise we just send the QUIT and bail. The default
// is "false"
if (props.getBooleanProperty(MAIL_SMTP_QUITWAIT, true)) {
// handle as a real command...we're going to ignore the response.
sendCommand("QUIT");
} else {
- // just send the command without waiting for a response.
+ // just send the command without waiting for a response.
sendLine("QUIT");
}
}
@@ -673,7 +663,7 @@
throw new MessagingException("no connection");
}
try {
- outputStream.write(data.getBytes());
+ outputStream.write(data.getBytes("ISO8859-1"));
outputStream.write(CR);
outputStream.write(LF);
outputStream.flush();
@@ -700,10 +690,10 @@
protected SMTPReply getReply() throws MessagingException {
try {
lastServerResponse = new SMTPReply(receiveLine());
- // if the first line we receive is a continuation, continue
- // reading lines until we reach the non-continued one.
+ // if the first line we receive is a continuation, continue
+ // reading lines until we reach the non-continued one.
while (lastServerResponse.isContinued()) {
- lastServerResponse.addLine(receiveLine());
+ lastServerResponse.addLine(receiveLine());
}
} catch (MalformedSMTPReplyException e) {
throw new MessagingException(e.toString());
@@ -720,9 +710,9 @@
* the SMTP server.
*/
public SMTPReply getLastServerResponse() {
- return lastServerResponse;
+ return lastServerResponse;
}
-
+
/**
* Receives one line from the server. A line is a sequence of bytes
@@ -852,14 +842,14 @@
debugOut("STARTTLS command rejected by SMTP server " + serverHost);
throw new MessagingException("Unable to make TLS server connection");
}
-
- debugOut("STARTTLS command accepted");
-
- // the base class handles the socket switch details
- super.getConnectedTLSSocket();
+
+ debugOut("STARTTLS command accepted");
+
+ // the base class handles the socket switch details
+ super.getConnectedTLSSocket();
}
-
+
/**
* Send the EHLO command to the SMTP server.
*
@@ -881,11 +871,11 @@
return false;
}
- // create a fresh mapping and authentications table
+ // create a fresh mapping and authentications table
capabilities = new HashMap();
- authentications = new ArrayList();
+ authentications = new ArrayList();
- List lines = reply.getLines();
+ List lines = reply.getLines();
// process all of the continuation lines
for (int i = 1; i < lines.size(); i++) {
// go process the extention
@@ -900,11 +890,11 @@
* @exception MessagingException
*/
protected void sendHelo() throws MessagingException {
- // create a fresh mapping and authentications table
- // these will be empty, but it will prevent NPEs
+ // create a fresh mapping and authentications table
+ // these will be empty, but it will prevent NPEs
capabilities = new HashMap();
- authentications = new ArrayList();
-
+ authentications = new ArrayList();
+
sendLine("HELO " + getLocalHost());
SMTPReply line = getReply();
@@ -927,7 +917,7 @@
return useTLS;
}
-
+
/**
* Set a new value for the startTLS property.
*
@@ -938,7 +928,7 @@
useTLS = start;
}
-
+
/**
* Process an extension string passed back as the EHLP response.
*
@@ -947,7 +937,7 @@
* "NAME arguments").
*/
protected void processExtension(String extension) {
- debugOut("Processing extension " + extension);
+ debugOut("Processing extension " + extension);
String extensionName = extension.toUpperCase();
String argument = "";
@@ -958,7 +948,7 @@
extensionName = extension.substring(0, delimiter).toUpperCase();
argument = extension.substring(delimiter + 1);
}
-
+
// add this to the map so it can be tested later.
capabilities.put(extensionName, argument);
@@ -989,7 +979,7 @@
}
}
-
+
/**
* Retrieve any argument information associated with a extension reported
* back by the server on the EHLO command.
@@ -1007,7 +997,7 @@
}
return null;
}
-
+
/**
* Tests whether the target server supports a named extension.
@@ -1023,7 +1013,7 @@
// this only returns null if we don't have this extension
return extensionParameter(name) != null;
}
-
+
/**
* Authenticate with the server, if necessary (or possible).
@@ -1043,14 +1033,14 @@
if (username == null || password == null) {
return false;
}
-
- // if unable to get an appropriate authenticator, just fail it.
- ClientAuthenticator authenticator = getSaslAuthenticator();
+
+ // if unable to get an appropriate authenticator, just fail it.
+ ClientAuthenticator authenticator = getSaslAuthenticator();
if (authenticator == null) {
- throw new MessagingException("Unable to obtain SASL authenticator");
+ throw new MessagingException("Unable to obtain SASL authenticator");
}
-
-
+
+
if (debug) {
debugOut("Authenticating for user: " + username + " using " + authenticator.getMechanismName());
}
@@ -1065,7 +1055,10 @@
command.append(authenticator.getMechanismName());
command.append(" ");
// and append the response data
- command.append(new String(Base64.encode(authenticator.evaluateChallenge(null))));
+ try {
+ command.append(new String(Base64.encode(authenticator.evaluateChallenge(null)), "US-ASCII"));
+ } catch (UnsupportedEncodingException e) {
+ }
// send the command now
sendLine(command.toString());
}
@@ -1109,12 +1102,15 @@
return false;
}
- // we're passed back a challenge value, Base64 encoded.
- byte[] challenge = Base64.decode(line.getMessage().getBytes());
+ try {
+ // we're passed back a challenge value, Base64 encoded.
+ byte[] challenge = Base64.decode(line.getMessage().getBytes("ISO8859-1"));
- // have the authenticator evaluate and send back the encoded
- // response.
- sendLine(new String(Base64.encode(authenticator.evaluateChallenge(challenge))));
+ // have the authenticator evaluate and send back the encoded
+ // response.
+ sendLine(new String(Base64.encode(authenticator.evaluateChallenge(challenge)), "US-ASCII"));
+ } catch (UnsupportedEncodingException e) {
+ }
}
// completion or challenge are the only responses we know how to
// handle. Anything else must
@@ -1127,74 +1123,74 @@
}
}
}
-
-
+
+
/**
- * Attempt to retrieve a SASL authenticator for this
- * protocol.
- *
- * @return A SASL authenticator, or null if a suitable one
+ * Attempt to retrieve a SASL authenticator for this
+ * protocol.
+ *
+ * @return A SASL authenticator, or null if a suitable one
* was not located.
*/
protected ClientAuthenticator getSaslAuthenticator() {
- return AuthenticatorFactory.getAuthenticator(props, selectSaslMechanisms(), serverHost, username, password, authid, realm);
+ return AuthenticatorFactory.getAuthenticator(props, selectSaslMechanisms(), serverHost, username, password, authid, realm);
}
-
+
/**
- * Read the bytes in a stream a test to see if this
- * conforms to the RFC 2045 rules for 8bit encoding.
- *
- * 1) No more than 998 bytes long
+ * Read the bytes in a stream a test to see if this
+ * conforms to the RFC 2045 rules for 8bit encoding.
+ *
+ * 1) No more than 998 bytes long
* 2) All lines are terminated with CRLF sequences
- * 3) CR and LF characters only occur in properly
- * formed line separators
- * 4) No null characters are allowed.
- *
+ * 3) CR and LF characters only occur in properly
+ * formed line separators
+ * 4) No null characters are allowed.
+ *
* @param inStream The source input stream.
- *
- * @return true if this can be transmitted successfully
+ *
+ * @return true if this can be transmitted successfully
* using 8bit encoding, false if an alternate encoding
* will be required.
*/
- protected boolean isValid8bit(InputStream inStream) {
+ protected boolean isValid8bit(InputStream inStream) {
try {
- int ch;
- int lineLength = 0;
+ int ch;
+ int lineLength = 0;
while ((ch = inStream.read()) >= 0) {
- // nulls are decidedly not allowed
+ // nulls are decidedly not allowed
if (ch == 0) {
- return false;
+ return false;
}
- // start of a CRLF sequence (potentially)
+ // start of a CRLF sequence (potentially)
else if (ch == '\r') {
- // check the next character. There must be one,
- // and it must be a LF for this to be value
- ch = inStream.read();
+ // check the next character. There must be one,
+ // and it must be a LF for this to be value
+ ch = inStream.read();
if (ch != '\n') {
- return false;
+ return false;
}
- // reset the line length
- lineLength = 0;
+ // reset the line length
+ lineLength = 0;
}
else {
- // a normal character
- lineLength++;
- // make sure the line is not too long
+ // a normal character
+ lineLength++;
+ // make sure the line is not too long
if (lineLength > 998) {
- return false;
+ return false;
}
}
-
+
}
} catch (IOException e) {
- return false; // can't read this, don't try passing it
+ return false; // can't read this, don't try passing it
}
- // this converted ok
- return true;
+ // this converted ok
+ return true;
}
-
+
/**
* Simple holder class for the address/send status duple, as we can have
* mixed success for a set of addresses and a message
@@ -1299,7 +1295,7 @@
}
}
-
+
/**
* Reset the server connection after an error.
*
@@ -1322,14 +1318,14 @@
lastServerResponse = last;
}
-
+
/**
* Return the current reportSuccess property.
*
* @return The current reportSuccess property.
*/
public boolean getReportSuccess() {
- return reportSuccess;
+ return reportSuccess;
}
/**
@@ -1339,7 +1335,7 @@
* The new setting.
*/
public void setReportSuccess(boolean report) {
- reportSuccess = report;
+ reportSuccess = report;
}
}
diff --git a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/test/java/org/apache/geronimo/javamail/store/imap/connection/IMAPBodyStructureTest.java b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/test/java/org/apache/geronimo/javamail/store/imap/connection/IMAPBodyStructureTest.java
index e172d91..9ef05e7 100644
--- a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/test/java/org/apache/geronimo/javamail/store/imap/connection/IMAPBodyStructureTest.java
+++ b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/test/java/org/apache/geronimo/javamail/store/imap/connection/IMAPBodyStructureTest.java
@@ -31,7 +31,7 @@
InputStream in = IMAPStoreTest.class.getResourceAsStream("/imap/multipart.bodystructure");
BufferedReader r = new BufferedReader(new InputStreamReader(in));
try {
- IMAPResponseTokenizer tokenizer = new IMAPResponseTokenizer(r.readLine().getBytes());
+ IMAPResponseTokenizer tokenizer = new IMAPResponseTokenizer(r.readLine().getBytes("ISO8859-1"));
IMAPBodyStructure s = new IMAPBodyStructure(tokenizer);
assertNull(s.disposition.getDisposition());
assertNull(s.md5Hash);