You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by ri...@apache.org on 2006/05/01 18:56:09 UTC
svn commit: r398634 [1/3] - in
/geronimo/branches/1.1/modules/javamail-transport/src:
java/org/apache/geronimo/javamail/authentication/
java/org/apache/geronimo/javamail/transport/smtp/
java/org/apache/geronimo/javamail/util/ resources/META-INF/
Author: rickmcguire
Date: Mon May 1 09:56:06 2006
New Revision: 398634
URL: http://svn.apache.org/viewcvs?rev=398634&view=rev
Log:
GERONIMO-1957 upgrade the SMTP transport version to match the javamail spec implementation.
Added:
geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/authentication/
geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/authentication/ClientAuthenticator.java
geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/authentication/CramMD5Authenticator.java
geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/authentication/DigestMD5Authenticator.java
geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/authentication/LoginAuthenticator.java
geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/authentication/PlainAuthenticator.java
geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/SMTPAddressFailedException.java
geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/SMTPAddressSucceededException.java
geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/SMTPMessage.java
geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/SMTPSTransport.java
geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/SMTPSendFailedException.java
geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/util/
geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/util/MIMEOutputStream.java
geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/util/TraceInputStream.java
geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/util/TraceOutputStream.java
Modified:
geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/MalformedSMTPReplyException.java
geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/SMTPReply.java
geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/SMTPTransport.java
geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/SMTPTransportException.java
geronimo/branches/1.1/modules/javamail-transport/src/resources/META-INF/javamail.default.providers
Added: geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/authentication/ClientAuthenticator.java
URL: http://svn.apache.org/viewcvs/geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/authentication/ClientAuthenticator.java?rev=398634&view=auto
==============================================================================
--- geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/authentication/ClientAuthenticator.java (added)
+++ geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/authentication/ClientAuthenticator.java Mon May 1 09:56:06 2006
@@ -0,0 +1,84 @@
+/**
+ *
+ * Copyright 2003-2005 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.geronimo.javamail.authentication;
+
+import javax.mail.MessagingException;
+
+/**
+ * Simplified version of the Java 5 SaslClient interface. This is used to
+ * implement a javamail authentication framework that mimics the Sasl framework
+ * on a 1.4.2 JVM. Only the methods required by the Javamail code are
+ * implemented here, but it should be a simple migration to the fuller SASL
+ * interface.
+ */
+public interface ClientAuthenticator {
+ /**
+ * Evaluate a challenge and return a response that can be sent back to the
+ * server. Bot the challenge information and the response information are
+ * "raw data", minus any special encodings used by the transport. For
+ * example, SMTP DIGEST-MD5 authentication protocol passes information as
+ * Base64 encoded strings. That encoding must be removed before calling
+ * evaluateChallenge() and the resulting respose must be Base64 encoced
+ * before transmission to the server.
+ *
+ * It is the authenticator's responsibility to keep track of the state of
+ * the evaluations. That is, if the authentication process requires multiple
+ * challenge/response cycles, then the authenticator needs to keep track of
+ * context of the challenges.
+ *
+ * @param challenge
+ * The challenge data.
+ *
+ * @return An appropriate response for the challenge data.
+ */
+
+ public byte[] evaluateChallenge(byte[] challenge) throws MessagingException;
+
+ /**
+ * Indicates that the authenticator has data that should be sent when the
+ * authentication process is initiated. For example, the SMTP PLAIN
+ * authentication sends userid/password without waiting for a challenge
+ * response.
+ *
+ * If this method returns true, then the initial response is retrieved using
+ * evaluateChallenge() passing null for the challenge information.
+ *
+ * @return True if the challenge/response process starts with an initial
+ * response on the client side.
+ */
+ public boolean hasInitialResponse();
+
+ /**
+ * Indicates whether the client believes the challenge/response sequence is
+ * now complete.
+ *
+ * @return true if the client has evaluated what it believes to be the last
+ * challenge, false if there are additional stages to evaluate.
+ */
+
+ public boolean isComplete();
+
+ /**
+ * Return the mechanism name implemented by this authenticator.
+ *
+ * @return The string name of the authentication mechanism. This name should
+ * match the names commonly used by the mail servers (e.g., "PLAIN",
+ * "LOGIN", "DIGEST-MD5", etc.).
+ */
+ public String getMechanismName();
+}
Added: geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/authentication/CramMD5Authenticator.java
URL: http://svn.apache.org/viewcvs/geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/authentication/CramMD5Authenticator.java?rev=398634&view=auto
==============================================================================
--- geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/authentication/CramMD5Authenticator.java (added)
+++ geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/authentication/CramMD5Authenticator.java Mon May 1 09:56:06 2006
@@ -0,0 +1,173 @@
+/**
+ *
+ * Copyright 2003-2005 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.geronimo.javamail.authentication;
+
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+import javax.mail.MessagingException;
+
+import org.apache.geronimo.mail.util.Hex;
+
+public class CramMD5Authenticator implements ClientAuthenticator {
+
+ // the user we're authenticating
+ protected String username;
+
+ // the user's password (the "shared secret")
+ protected String password;
+
+ // indicates whether we've gone through the entire challenge process.
+ protected boolean complete = false;
+
+ /**
+ * Main constructor.
+ *
+ * @param username
+ * The login user name.
+ * @param password
+ * The login password.
+ */
+ public CramMD5Authenticator(String username, String password) {
+ this.username = username;
+ this.password = password;
+ }
+
+ /**
+ * Respond to the hasInitialResponse query. This mechanism does not have an
+ * initial response.
+ *
+ * @return Always returns false.
+ */
+ public boolean hasInitialResponse() {
+ return false;
+ }
+
+ /**
+ * Indicate whether the challenge/response process is complete.
+ *
+ * @return True if the last challenge has been processed, false otherwise.
+ */
+ public boolean isComplete() {
+ return complete;
+ }
+
+ /**
+ * Retrieve the authenticator mechanism name.
+ *
+ * @return Always returns the string "CRAM-MD5"
+ */
+ public String getMechanismName() {
+ return "CRAM-MD5";
+ }
+
+ /**
+ * 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
+ */
+ public byte[] evaluateChallenge(byte[] challenge) throws MessagingException {
+ // we create the challenge from the userid and password information (the
+ // "shared secret").
+ byte[] passBytes;
+
+ try {
+ // get the password in an UTF-8 encoding to create the token
+ passBytes = password.getBytes("UTF-8");
+ // compute the password digest using the key
+ byte[] digest = computeCramDigest(passBytes, challenge);
+
+ // create a unified string using the user name and the hex encoded
+ // digest
+ String responseString = username + " " + new String(Hex.encode(digest));
+ complete = true;
+ return responseString.getBytes();
+ } catch (UnsupportedEncodingException e) {
+ // got an error, fail this
+ throw new MessagingException("Invalid character encodings");
+ }
+
+ }
+
+ /**
+ * 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
+ */
+ protected byte[] computeCramDigest(byte[] key, byte[] input) throws MessagingException {
+ // CRAM digests are computed using the MD5 algorithm.
+ MessageDigest digest;
+ try {
+ digest = MessageDigest.getInstance("MD5");
+ } catch (NoSuchAlgorithmException e) {
+ throw new MessagingException("Unable to access MD5 message digest", e);
+ }
+
+ // if the key is longer than 64 bytes, then we get a digest of the key
+ // and use that instead.
+ // this is required by RFC 2104.
+ if (key.length > 64) {
+ digest.update(key);
+ key = digest.digest();
+ }
+
+ // now we create two 64 bit padding keys, initialized with the key
+ // information.
+ byte[] ipad = new byte[64];
+ byte[] opad = new byte[64];
+
+ System.arraycopy(key, 0, ipad, 0, key.length);
+ System.arraycopy(key, 0, opad, 0, key.length);
+
+ // and these versions are munged by XORing with "magic" values.
+
+ for (int i = 0; i < 64; i++) {
+ ipad[i] ^= 0x36;
+ opad[i] ^= 0x5c;
+ }
+
+ // now there are a pair of MD5 operations performed, and inner and an
+ // outer. The spec defines this as
+ // H(K XOR opad, H(K XOR ipad, text)), where H is the MD5 operation.
+
+ // inner operation
+ digest.reset();
+ digest.update(ipad);
+ digest.update(input); // this appends the text to the pad
+ byte[] md5digest = digest.digest();
+
+ // outer operation
+ digest.reset();
+ digest.update(opad);
+ digest.update(md5digest);
+ return digest.digest(); // final result
+ }
+}
Added: geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/authentication/DigestMD5Authenticator.java
URL: http://svn.apache.org/viewcvs/geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/authentication/DigestMD5Authenticator.java?rev=398634&view=auto
==============================================================================
--- geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/authentication/DigestMD5Authenticator.java (added)
+++ geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/authentication/DigestMD5Authenticator.java Mon May 1 09:56:06 2006
@@ -0,0 +1,622 @@
+/**
+ *
+ * Copyright 2003-2005 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.geronimo.javamail.authentication;
+
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.ArrayList;
+
+import javax.mail.AuthenticationFailedException;
+import javax.mail.MessagingException;
+
+import org.apache.geronimo.mail.util.Base64;
+import org.apache.geronimo.mail.util.Hex;
+
+/**
+ * Process a DIGEST-MD5 authentication, using the challenge/response mechanisms.
+ */
+public class DigestMD5Authenticator implements ClientAuthenticator {
+
+ protected static final int AUTHENTICATE_CLIENT = 0;
+
+ protected static final int AUTHENTICATE_SERVER = 1;
+
+ protected static final int AUTHENTICATION_COMPLETE = 2;
+
+ // the host server name
+ protected String host;
+
+ // the user we're authenticating
+ protected String username;
+
+ // the user's password (the "shared secret")
+ protected String password;
+
+ // the target login realm
+ protected String realm;
+
+ // our message digest for processing the challenges.
+ MessageDigest digest;
+
+ // the string we send to the server on the first challenge.
+ protected String clientResponse;
+
+ // the response back from an authentication challenge.
+ protected String authenticationResponse = null;
+
+ // our list of realms received from the server (normally just one).
+ protected ArrayList realms;
+
+ // the nonce value sent from the server
+ protected String nonce;
+
+ // indicates whether we've gone through the entire challenge process.
+ protected int stage = AUTHENTICATE_CLIENT;
+
+ /**
+ * Main constructor.
+ *
+ * @param host
+ * The server host name.
+ * @param username
+ * The login user name.
+ * @param password
+ * The login password.
+ * @param realm
+ * The target login realm (can be null).
+ */
+ public DigestMD5Authenticator(String host, String username, String password, String realm) {
+ this.host = host;
+ this.username = username;
+ this.password = password;
+ this.realm = realm;
+ }
+
+ /**
+ * Respond to the hasInitialResponse query. This mechanism does not have an
+ * initial response.
+ *
+ * @return Always returns false.
+ */
+ public boolean hasInitialResponse() {
+ return false;
+ }
+
+ /**
+ * Indicate whether the challenge/response process is complete.
+ *
+ * @return True if the last challenge has been processed, false otherwise.
+ */
+ public boolean isComplete() {
+ return stage == AUTHENTICATION_COMPLETE;
+ }
+
+ /**
+ * Retrieve the authenticator mechanism name.
+ *
+ * @return Always returns the string "DIGEST-MD5"
+ */
+ public String getMechanismName() {
+ return "DIGEST-MD5";
+ }
+
+ /**
+ * 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
+ */
+ public byte[] evaluateChallenge(byte[] challenge) throws MessagingException {
+
+ // DIGEST-MD5 authentication goes in two stages. First state involves us
+ // validating with the
+ // server, the second stage is the server validating with us, using the
+ // shared secret.
+ switch (stage) {
+ // stage one of the process.
+ case AUTHENTICATE_CLIENT: {
+ // get the response and advance the processing stage.
+ byte[] response = authenticateClient(challenge);
+ stage = AUTHENTICATE_SERVER;
+ return response;
+ }
+
+ // stage two of the process.
+ case AUTHENTICATE_SERVER: {
+ // get the response and advance the processing stage to completed.
+ byte[] response = authenticateServer(challenge);
+ stage = AUTHENTICATION_COMPLETE;
+ return response;
+ }
+
+ // should never happen.
+ default:
+ throw new MessagingException("Invalid LOGIN challenge");
+ }
+ }
+
+ /**
+ * 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
+ */
+ public byte[] authenticateServer(byte[] challenge) throws MessagingException {
+ // parse the challenge string and validate.
+ if (!parseChallenge(challenge)) {
+ return null;
+ }
+
+ try {
+ // like all of the client validation steps, the following is order
+ // critical.
+ // 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()));
+ digest.update(responseString.getBytes("US-ASCII"));
+
+ // now convert that into a hex encoded string.
+ String validationText = new String(Hex.encode(digest.digest()));
+
+ // if everything went well, this calculated value should match what
+ // we got back from the server.
+ // our response back is just a null string....
+ if (validationText.equals(authenticationResponse)) {
+ return new byte[0];
+ }
+ throw new AuthenticationFailedException("Invalid DIGEST-MD5 response from server");
+ } catch (UnsupportedEncodingException e) {
+ throw new MessagingException("Invalid character encodings");
+ }
+
+ }
+
+ /**
+ * 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
+ */
+ public byte[] authenticateClient(byte[] challenge) throws MessagingException {
+ // parse the challenge string and validate.
+ if (!parseChallenge(challenge)) {
+ return null;
+ }
+
+ SecureRandom randomGenerator;
+ // before doing anything, make sure we can get the required crypto
+ // support.
+ try {
+ randomGenerator = new SecureRandom();
+ digest = MessageDigest.getInstance("MD5");
+ } catch (NoSuchAlgorithmException e) {
+ throw new MessagingException("Unable to access cryptography libraries");
+ }
+
+ // if not configured for a realm, take the first realm from the list, if
+ // any
+ if (realm == null) {
+ // if not handed any realms, just use the host name.
+ if (realms.isEmpty()) {
+ realm = host;
+ } else {
+ // pretty arbitrary at this point, so just use the first one.
+ realm = (String) realms.get(0);
+ }
+ }
+
+ // use secure random to generate a collection of bytes. that is our
+ // cnonce value.
+ 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 {
+ // 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
+ // first stage
+ // of the next digest operation.
+ digest.update(digest.digest(idString.getBytes("US-ASCII")));
+
+ // now we add the nonce strings to the digest.
+ String nonceString = ":" + nonce + ":" + cnonce;
+ digest.update(nonceString.getBytes("US-ASCII"));
+
+ // hex encode this digest, and add on the string values
+ // NB, we only support "auth" for the quality of protection value
+ // (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:";
+
+ // 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()));
+ // 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()));
+
+ // now finally build the keyword/value part of the challenge
+ // response. These can be
+ // in any order.
+ StringBuffer response = new StringBuffer();
+
+ response.append("username=\"");
+ response.append(username);
+ response.append("\"");
+
+ response.append(",realm=\"");
+ response.append(realm);
+ response.append("\"");
+
+ // we only support auth qop values, and the nonce-count (nc) is
+ // always 1.
+ response.append(",qop=auth");
+ response.append(",nc=00000001");
+
+ response.append(",nonce=\"");
+ response.append(nonce);
+ response.append("\"");
+
+ response.append(",cnonce=\"");
+ response.append(cnonce);
+ response.append("\"");
+
+ response.append(",digest-uri=\"smtp/");
+ response.append(host);
+ response.append("\"");
+
+ response.append(",response=");
+ response.append(challengeResponse);
+
+ return response.toString().getBytes("US-ASCII");
+
+ } catch (UnsupportedEncodingException e) {
+ throw new MessagingException("Invalid character encodings");
+ }
+ }
+
+ /**
+ * 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));
+
+ // parse the entire string...but we ignore everything but the options we
+ // support.
+ while (parser.hasMore()) {
+ NameValuePair pair = parser.parseNameValuePair();
+
+ String name = pair.name;
+
+ // realm to add to our list?
+ if (name.equalsIgnoreCase("realm")) {
+ realms.add(pair.value);
+ }
+ // we need the nonce to evaluate the client challenge.
+ else if (name.equalsIgnoreCase("nonce")) {
+ nonce = pair.value;
+ }
+ // rspauth is the challenge replay back, which allows us to validate
+ // that server is also legit.
+ else if (name.equalsIgnoreCase("rspauth")) {
+ authenticationResponse = pair.value;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Inner class for parsing a DIGEST-MD5 challenge string, which is composed
+ * of "name=value" pairs, separated by "," characters.
+ */
+ class DigestParser {
+ // the challenge we're parsing
+ String challenge;
+
+ // length of the challenge
+ int length;
+
+ // current parsing position
+ int position;
+
+ /**
+ * Normal constructor.
+ *
+ * @param challenge
+ * The challenge string to be parsed.
+ */
+ public DigestParser(String challenge) {
+ this.challenge = challenge;
+ this.length = challenge.length();
+ position = 0;
+ }
+
+ /**
+ * 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.
+ */
+ private boolean hasMore() {
+ return position < length;
+ }
+
+ /**
+ * Return the character at the current parsing position.
+ *
+ * @return The string character for the current parse position.
+ */
+ private char currentChar() {
+ return challenge.charAt(position);
+ }
+
+ /**
+ * step forward to the next character position.
+ */
+ private void nextChar() {
+ position++;
+ }
+
+ /**
+ * Skip over any white space characters in the challenge string.
+ */
+ private void skipSpaces() {
+ while (position < length && Character.isWhitespace(currentChar())) {
+ position++;
+ }
+ }
+
+ /**
+ * 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() {
+ // we're here because we found the starting double quote. Step over
+ // it and parse to the closing
+ // one.
+ nextChar();
+
+ StringBuffer value = new StringBuffer();
+
+ while (hasMore()) {
+ char ch = currentChar();
+
+ // is this an escape char?
+ if (ch == '\\') {
+ // step past this, and grab the following character
+ nextChar();
+ // we have an invalid quoted string....
+ if (!hasMore()) {
+ return null;
+ }
+ value.append(currentChar());
+ }
+ // end of the string?
+ else if (ch == '"') {
+ // step over this so the caller doesn't process it.
+ nextChar();
+ // return the constructed string.
+ return value.toString();
+ } else {
+ // step over the character and contine with the next
+ // characteer1
+ value.append(ch);
+ }
+ nextChar();
+ }
+ /* fell off the end without finding a closing quote! */
+ return null;
+ }
+
+ /**
+ * 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.
+ */
+ private String parseTokenValue() {
+
+ StringBuffer value = new StringBuffer();
+
+ while (hasMore()) {
+ char ch = currentChar();
+ switch (ch) {
+ // process the token separators.
+ case ' ':
+ case '\t':
+ case '(':
+ case ')':
+ case '<':
+ case '>':
+ case '@':
+ case ',':
+ case ';':
+ case ':':
+ case '\\':
+ case '"':
+ case '/':
+ case '[':
+ case ']':
+ case '?':
+ case '=':
+ case '{':
+ case '}':
+ // no token characters found? this is bad.
+ if (value.length() == 0) {
+ return null;
+ }
+ // return the accumulated characters.
+ return value.toString();
+
+ default:
+ // is this a control character? That's a delimiter (likely
+ // invalid for the next step,
+ // but it is a token terminator.
+ if (ch < 32 || ch > 127) {
+ // no token characters found? this is bad.
+ if (value.length() == 0) {
+ return null;
+ }
+ // return the accumulated characters.
+ return value.toString();
+ }
+ value.append(ch);
+ break;
+ }
+ // step to the next character.
+ nextChar();
+ }
+ // no token characters found? this is bad.
+ if (value.length() == 0) {
+ return null;
+ }
+ // return the accumulated characters.
+ return value.toString();
+ }
+
+ /**
+ * Parse out a name token of a name/value pair.
+ *
+ * @return The string value of the name.
+ */
+ private String parseName() {
+ // skip to the value start
+ skipSpaces();
+
+ // the name is a token.
+ return parseTokenValue();
+ }
+
+ /**
+ * Parse out a a value of a name/value pair.
+ *
+ * @return The string value associated with the name.
+ */
+ private String parseValue() {
+ // skip to the value start
+ skipSpaces();
+
+ // start of a quoted string?
+ if (currentChar() == '"') {
+ // parse it out as a string.
+ return parseQuotedValue();
+ }
+ // the value must be a token.
+ return parseTokenValue();
+ }
+
+ /**
+ * Parse a name/value pair in an DIGEST-MD5 string.
+ *
+ * @return A NameValuePair object containing the two parts of the value.
+ * @exception MessagingException
+ */
+ public NameValuePair parseNameValuePair() throws MessagingException {
+ // get the name token
+ String name = parseName();
+ if (name == null) {
+ throw new MessagingException("Name syntax error");
+ }
+
+ // the name should be followed by an "=" sign
+ if (!hasMore() || currentChar() != '=') {
+ throw new MessagingException("Name/value pair syntax error");
+ }
+
+ // step over the equals
+ nextChar();
+
+ // now get the value part
+ String value = parseValue();
+ if (value == null) {
+ throw new MessagingException("Name/value pair syntax error");
+ }
+
+ // skip forward to the terminator, which should either be the end of
+ // the line or a ","
+ skipSpaces();
+ // all that work, only to have a syntax error at the end (sigh)
+ if (hasMore()) {
+ if (currentChar() != ',') {
+ throw new MessagingException("Name/value pair syntax error");
+ }
+ // step over, and make sure we position ourselves at either the
+ // end or the first
+ // real character for parsing the next name/value pair.
+ nextChar();
+ skipSpaces();
+ }
+ return new NameValuePair(name, value);
+ }
+ }
+
+ /**
+ * Simple inner class to represent a name/value pair.
+ */
+ public class NameValuePair {
+ public String name;
+
+ public String value;
+
+ NameValuePair(String name, String value) {
+ this.name = name;
+ this.value = value;
+ }
+
+ }
+}
Added: geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/authentication/LoginAuthenticator.java
URL: http://svn.apache.org/viewcvs/geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/authentication/LoginAuthenticator.java?rev=398634&view=auto
==============================================================================
--- geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/authentication/LoginAuthenticator.java (added)
+++ geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/authentication/LoginAuthenticator.java Mon May 1 09:56:06 2006
@@ -0,0 +1,138 @@
+/**
+ *
+ * Copyright 2003-2005 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.geronimo.javamail.authentication;
+
+import java.io.UnsupportedEncodingException;
+
+import javax.mail.MessagingException;
+
+public class LoginAuthenticator implements ClientAuthenticator {
+
+ // constants for the authentication stages
+ protected static final int USERNAME = 0;
+
+ protected static final int PASSWORD = 1;
+
+ protected static final int COMPLETE = 2;
+
+ // the user we're authenticating
+ protected String username;
+
+ // the user's password (the "shared secret")
+ protected String password;
+
+ // indicates whether we've gone through the entire challenge process.
+ protected int stage = USERNAME;
+
+ /**
+ * Main constructor.
+ *
+ * @param username
+ * The login user name.
+ * @param password
+ * The login password.
+ */
+ public LoginAuthenticator(String username, String password) {
+ this.username = username;
+ this.password = password;
+ }
+
+ /**
+ * Respond to the hasInitialResponse query. This mechanism does not have an
+ * initial response.
+ *
+ * @return Always returns false;
+ */
+ public boolean hasInitialResponse() {
+ return false;
+ }
+
+ /**
+ * Indicate whether the challenge/response process is complete.
+ *
+ * @return True if the last challenge has been processed, false otherwise.
+ */
+ public boolean isComplete() {
+ return stage == COMPLETE;
+ }
+
+ /**
+ * Retrieve the authenticator mechanism name.
+ *
+ * @return Always returns the string "LOGIN"
+ */
+ public String getMechanismName() {
+ return "LOGIN";
+ }
+
+ /**
+ * Evaluate a PLAIN 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
+ */
+ public byte[] evaluateChallenge(byte[] challenge) throws MessagingException {
+
+ // process the correct stage for the challenge
+ switch (stage) {
+ // should never happen
+ case COMPLETE:
+ throw new MessagingException("Invalid LOGIN challenge");
+
+ case USERNAME: {
+ byte[] userBytes;
+
+ try {
+ // get the username and password in an UTF-8 encoding to create
+ // the token
+ userBytes = username.getBytes("UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ // got an error, fail this (this should never happen).
+ throw new MessagingException("Invalid encoding");
+ }
+
+ // next time through we're looking for a password.
+ stage = PASSWORD;
+ // the user bytes are the entire challenge respose.
+ return userBytes;
+ }
+
+ case PASSWORD: {
+ byte[] passBytes;
+
+ try {
+ // get the username and password in an UTF-8 encoding to create
+ // the token
+ passBytes = password.getBytes("UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ // got an error, fail this (this should never happen).
+ throw new MessagingException("Invalid encoding");
+ }
+ // we're finished
+ stage = COMPLETE;
+ return passBytes;
+ }
+ }
+ // should never get here.
+ throw new MessagingException("Invalid LOGIN challenge");
+ }
+}
Added: geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/authentication/PlainAuthenticator.java
URL: http://svn.apache.org/viewcvs/geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/authentication/PlainAuthenticator.java?rev=398634&view=auto
==============================================================================
--- geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/authentication/PlainAuthenticator.java (added)
+++ geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/authentication/PlainAuthenticator.java Mon May 1 09:56:06 2006
@@ -0,0 +1,110 @@
+/**
+ *
+ * Copyright 2003-2005 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.geronimo.javamail.authentication;
+
+import java.io.UnsupportedEncodingException;
+
+import javax.mail.MessagingException;
+
+public class PlainAuthenticator implements ClientAuthenticator {
+
+ // the user we're authenticating
+ protected String username;
+
+ // the user's password (the "shared secret")
+ protected String password;
+
+ // indicates whether we've gone through the entire challenge process.
+ protected boolean complete = false;
+
+ /**
+ * Main constructor.
+ *
+ * @param username
+ * The login user name.
+ * @param password
+ * The login password.
+ */
+ public PlainAuthenticator(String username, String password) {
+ this.username = username;
+ this.password = password;
+ }
+
+ /**
+ * Respond to the hasInitialResponse query. This mechanism does have an
+ * initial response, which is the entire challenge sequence.
+ *
+ * @return Always returns true.
+ */
+ public boolean hasInitialResponse() {
+ return true;
+ }
+
+ /**
+ * Indicate whether the challenge/response process is complete.
+ *
+ * @return True if the last challenge has been processed, false otherwise.
+ */
+ public boolean isComplete() {
+ return complete;
+ }
+
+ /**
+ * Retrieve the authenticator mechanism name.
+ *
+ * @return Always returns the string "PLAIN"
+ */
+ public String getMechanismName() {
+ return "PLAIN";
+ }
+
+ /**
+ * Evaluate a PLAIN login challenge, returning the a result string that
+ * should satisfy the clallenge.
+ *
+ * @param challenge
+ * The decoded challenge data, as byte array.
+ *
+ * @return A formatted challege response, as an array of bytes.
+ * @exception MessagingException
+ */
+ public byte[] evaluateChallenge(byte[] challenge) throws MessagingException {
+ try {
+ // get the username and password in an UTF-8 encoding to create the
+ // token
+ byte[] userBytes = username.getBytes("UTF-8");
+ byte[] passBytes = password.getBytes("UTF-8");
+
+ // our token has two copies of the username, one copy of the
+ // password, and nulls
+ // between
+ byte[] tokenBytes = new byte[(userBytes.length * 2) + passBytes.length + 2];
+
+ System.arraycopy(userBytes, 0, tokenBytes, 0, userBytes.length);
+ System.arraycopy(userBytes, 0, tokenBytes, userBytes.length + 1, userBytes.length);
+ System.arraycopy(passBytes, 0, tokenBytes, (userBytes.length * 2) + 2, passBytes.length);
+
+ complete = true;
+ return tokenBytes;
+
+ } catch (UnsupportedEncodingException e) {
+ // got an error, fail this
+ throw new MessagingException("Invalid encoding");
+ }
+ }
+}
Modified: geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/MalformedSMTPReplyException.java
URL: http://svn.apache.org/viewcvs/geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/MalformedSMTPReplyException.java?rev=398634&r1=398633&r2=398634&view=diff
==============================================================================
--- geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/MalformedSMTPReplyException.java (original)
+++ geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/MalformedSMTPReplyException.java Mon May 1 09:56:06 2006
@@ -22,7 +22,7 @@
*
* @version $Rev$ $Date$
*/
-class MalformedSMTPReplyException extends Exception {
+class MalformedSMTPReplyException extends Exception {
MalformedSMTPReplyException() {
super();
}
@@ -31,7 +31,7 @@
super(msg);
}
- MalformedSMTPReplyException(String msg, Throwable t) {
+ MalformedSMTPReplyException(String msg, Exception t) {
super(msg, t);
}
}
Added: geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/SMTPAddressFailedException.java
URL: http://svn.apache.org/viewcvs/geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/SMTPAddressFailedException.java?rev=398634&view=auto
==============================================================================
--- geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/SMTPAddressFailedException.java (added)
+++ geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/SMTPAddressFailedException.java Mon May 1 09:56:06 2006
@@ -0,0 +1,78 @@
+/**
+ *
+ * Copyright 2003-2005 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.geronimo.javamail.transport.smtp;
+
+import javax.mail.MessagingException;
+import javax.mail.internet.InternetAddress;
+
+public class SMTPAddressFailedException extends MessagingException {
+ // the failing address
+ InternetAddress addr;
+
+ // the failing command
+ protected String cmd;
+
+ // the error code for the failure
+ protected int rc;
+
+ /**
+ * Constructor for an SMTPAddressFailingException.
+ *
+ * @param addr
+ * The failing address.
+ * @param cmd
+ * The failing command string.
+ * @param rc
+ * The error code for the command.
+ * @param err
+ * An error message for the exception.
+ */
+ SMTPAddressFailedException(InternetAddress addr, java.lang.String cmd, int rc, java.lang.String err) {
+ super(err);
+ this.cmd = cmd;
+ this.rc = rc;
+ this.addr = addr;
+ }
+
+ /**
+ * Get the failing command string for the exception.
+ *
+ * @return The string value of the failing command.
+ */
+ public String getCommand() {
+ return cmd;
+ }
+
+ /**
+ * The failing command return code.
+ *
+ * @return The failure return code.
+ */
+ public int getReturnCode() {
+ return rc;
+ }
+
+ /**
+ * Retrieve the internet address associated with this exception.
+ *
+ * @return The provided InternetAddress object.
+ */
+ public InternetAddress getAddress() {
+ return addr;
+ }
+}
Added: geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/SMTPAddressSucceededException.java
URL: http://svn.apache.org/viewcvs/geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/SMTPAddressSucceededException.java?rev=398634&view=auto
==============================================================================
--- geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/SMTPAddressSucceededException.java (added)
+++ geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/SMTPAddressSucceededException.java Mon May 1 09:56:06 2006
@@ -0,0 +1,78 @@
+/**
+ *
+ * Copyright 2003-2005 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.geronimo.javamail.transport.smtp;
+
+import javax.mail.MessagingException;
+import javax.mail.internet.InternetAddress;
+
+public class SMTPAddressSucceededException extends MessagingException {
+ // the succeeding address
+ InternetAddress addr;
+
+ // the failing command
+ protected String cmd;
+
+ // the error code for the failure
+ protected int rc;
+
+ /**
+ * Constructor for an SMTPAddressSucceededException.
+ *
+ * @param addr
+ * The succeeding address.
+ * @param cmd
+ * The succeeding command string.
+ * @param rc
+ * The error code for the command.
+ * @param err
+ * An error message for the exception.
+ */
+ SMTPAddressSucceededException(InternetAddress addr, java.lang.String cmd, int rc, java.lang.String err) {
+ super(err);
+ this.cmd = cmd;
+ this.rc = rc;
+ this.addr = addr;
+ }
+
+ /**
+ * Get the failing command string for the exception.
+ *
+ * @return The string value of the failing command.
+ */
+ public String getCommand() {
+ return cmd;
+ }
+
+ /**
+ * The failing command return code.
+ *
+ * @return The failure return code.
+ */
+ public int getReturnCode() {
+ return rc;
+ }
+
+ /**
+ * Retrieve the internet address associated with this exception.
+ *
+ * @return The provided InternetAddress object.
+ */
+ public InternetAddress getAddress() {
+ return addr;
+ }
+}
Added: geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/SMTPMessage.java
URL: http://svn.apache.org/viewcvs/geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/SMTPMessage.java?rev=398634&view=auto
==============================================================================
--- geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/SMTPMessage.java (added)
+++ geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/SMTPMessage.java Mon May 1 09:56:06 2006
@@ -0,0 +1,235 @@
+/**
+ *
+ * Copyright 2003-2005 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.geronimo.javamail.transport.smtp;
+
+import java.io.InputStream;
+
+import javax.mail.MessagingException;
+import javax.mail.Session;
+import javax.mail.internet.MimeMessage;
+
+public class SMTPMessage extends MimeMessage {
+
+ // never notify
+ public static final int NOTIFY_NEVER = -1;
+
+ // notify of successful deliveries.
+ public static final int NOTIFY_SUCCESS = 1;
+
+ // notify of delivery failures.
+ public static final int NOTIFY_FAILURE = 2;
+
+ // notify of delivery delays
+ public static final int NOTIFY_DELAY = 4;
+
+ // return full message with status notifications
+ public static final int RETURN_FULL = 1;
+
+ // return only message headers with status notifications
+ public static final int RETURN_HDRS = 2;
+
+ // support 8BitMime encodings
+ protected boolean allow8bitMIME = false;
+
+ // a from address specified in the message envelope. Overrides other from
+ // sources.
+ protected String envelopeFrom = null;
+
+ // an option string to append to the MAIL command on sending.
+ protected String mailExtension = null;
+
+ // SMTP mail notification options if DSN is supported.
+ protected int notifyOptions = 0;
+
+ // DSN return option notification values.
+ protected int returnOption = 0;
+
+ // allow sending if some addresses give errors.
+ protected boolean sendPartial = false;
+
+ // an RFC 2554 AUTH= value.
+ protected String submitter = null;
+
+ /**
+ * Default (and normal) constructor for an SMTPMessage.
+ *
+ * @param session
+ * The hosting Javamail Session.
+ */
+ public SMTPMessage(Session session) {
+ // this is a simple one.
+ super(session);
+ }
+
+ /**
+ * Construct an SMTPMessage instance by reading and parsing the data from
+ * the provided InputStream. The InputStream will be left positioned at the
+ * end of the message data on constructor completion.
+ *
+ * @param session
+ * The hosting Javamail Session.
+ */
+ public SMTPMessage(Session session, InputStream source) throws MessagingException {
+ // this is a simple one.
+ super(session, source);
+ }
+
+ /**
+ * Construct an SMTPMimeMessage from another source MimeMessage object. The
+ * new object and the old object are independent of each other.
+ *
+ * @param source
+ * The source MimeMessage object.
+ */
+ public SMTPMessage(MimeMessage source) throws MessagingException {
+ super(source);
+ }
+
+ /**
+ * Change the allow8BitMime attribute for the message.
+ *
+ * @param a
+ * The new setting.
+ */
+ public void setAllow8bitMIME(boolean a) {
+ allow8bitMIME = a;
+ }
+
+ /**
+ * Retrieve the current 8bitMIME attribute.
+ *
+ * @return The current attribute value.
+ */
+ public boolean getAllow8bitMIME() {
+ return allow8bitMIME;
+ }
+
+ /**
+ * Change the envelopeFrom attribute for the message.
+ *
+ * @param from
+ * The new setting.
+ */
+ public void setEnvelopeFrom(String from) {
+ envelopeFrom = from;
+ }
+
+ /**
+ * Retrieve the current evelopeFrom attribute.
+ *
+ * @return The current attribute value.
+ */
+ public String getEnvelopeFrom() {
+ return envelopeFrom;
+ }
+
+ /**
+ * Change the mailExtension attribute for the message.
+ *
+ * @param e
+ * The new setting.
+ */
+ public void setMailExtension(String e) {
+ mailExtension = e;
+ }
+
+ /**
+ * Retrieve the current mailExtension attribute.
+ *
+ * @return The current attribute value.
+ */
+ public String getMailExtension() {
+ return mailExtension;
+ }
+
+ /**
+ * Change the notifyOptions attribute for the message.
+ *
+ * @param options
+ * The new setting.
+ */
+ public void setNotifyOptions(int options) {
+ notifyOptions = options;
+ }
+
+ /**
+ * Retrieve the current notifyOptions attribute.
+ *
+ * @return The current attribute value.
+ */
+ public int getNotifyOptions() {
+ return notifyOptions;
+ }
+
+ /**
+ * Change the returnOptions attribute for the message.
+ *
+ * @param option
+ * The new setting.
+ */
+ public void setReturnOption(int option) {
+ returnOption = option;
+ }
+
+ /**
+ * Retrieve the current returnOption attribute.
+ *
+ * @return The current attribute value.
+ */
+ public int getReturnOption() {
+ return returnOption;
+ }
+
+ /**
+ * Change the sendPartial attribute for the message.
+ *
+ * @param a
+ * The new setting.
+ */
+ public void setSendPartial(boolean a) {
+ sendPartial = a;
+ }
+
+ /**
+ * Retrieve the current sendPartial attribute.
+ *
+ * @return The current attribute value.
+ */
+ public boolean getSendPartial() {
+ return sendPartial;
+ }
+
+ /**
+ * Change the submitter attribute for the message.
+ *
+ * @param s
+ * The new setting.
+ */
+ public void setSubmitter(String s) {
+ submitter = s;
+ }
+
+ /**
+ * Retrieve the current submitter attribute.
+ *
+ * @return The current attribute value.
+ */
+ public String getSubmitter() {
+ return submitter;
+ }
+}
Modified: geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/SMTPReply.java
URL: http://svn.apache.org/viewcvs/geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/SMTPReply.java?rev=398634&r1=398633&r2=398634&view=diff
==============================================================================
--- geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/SMTPReply.java (original)
+++ geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/SMTPReply.java Mon May 1 09:56:06 2006
@@ -19,26 +19,49 @@
/**
* Util class to represent a reply from a SMTP server
- *
+ *
* @version $Rev$ $Date$
*/
class SMTPReply {
+ // The original reply string
+ private final String reply;
+
+ // returned message code
private final int code;
+
+ // the returned message text
private final String message;
- private final char firstChar;
+
+ // indicates that this is a continuation response
+ private boolean continued;
SMTPReply(String s) throws MalformedSMTPReplyException {
- // first three must be the return code
+ // save the reply
+ reply = s;
+
+ // In a normal response, the first 3 must be the return code. However,
+ // the response back from a QUIT command is frequently a null string.
+ // Therefore, if the result is
+ // too short, just default the code to -1 and use the entire text for
+ // the message.
if (s == null || s.length() < 3) {
- throw new MalformedSMTPReplyException("Too Short! : " + s);
+ code = -1;
+ message = s;
+ return;
}
try {
- firstChar = s.charAt(0);
+ continued = false;
code = Integer.parseInt(s.substring(0, 3));
- // message should be separated by a space
+ // message should be separated by a space OR a continuation
+ // character if this is a
+ // multi-line response.
if (s.length() > 4) {
+ //
+ if (s.charAt(3) == '-') {
+ continued = true;
+ }
message = s.substring(4);
} else {
message = "";
@@ -48,23 +71,50 @@
}
}
- int getCode() {
+ /**
+ * Return the code value associated with the reply.
+ *
+ * @return The integer code associated with the reply.
+ */
+ public int getCode() {
return this.code;
}
- String getMessage() {
+ /**
+ * Get the message text associated with the reply.
+ *
+ * @return The string value of the message from the reply.
+ */
+ public String getMessage() {
return this.message;
}
/**
+ * Retrieve the raw reply string for the reponse.
+ *
+ * @return The original reply string from the server.
+ */
+ public String getReply() {
+ return reply;
+ }
+
+ /**
* Indicates if reply is an error condition
*/
boolean isError() {
- if (firstChar == '5' || firstChar == '4') {
- return true;
- }
+ // error codes are all above 400
+ return code >= 400;
+ }
- return false;
+ /**
+ * Indicates whether this response is flagged as part of a multiple line
+ * response.
+ *
+ * @return true if the response has multiple lines, false if this is the
+ * last line of the response.
+ */
+ public boolean isContinued() {
+ return continued;
}
public String toString() {
Added: geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/SMTPSTransport.java
URL: http://svn.apache.org/viewcvs/geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/SMTPSTransport.java?rev=398634&view=auto
==============================================================================
--- geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/SMTPSTransport.java (added)
+++ geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/SMTPSTransport.java Mon May 1 09:56:06 2006
@@ -0,0 +1,31 @@
+/**
+ *
+ * Copyright 2003-2005 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.geronimo.javamail.transport.smtp;
+
+import javax.mail.Session;
+import javax.mail.URLName;
+
+public class SMTPSTransport extends SMTPTransport {
+ /**
+ * @param session
+ * @param name
+ */
+ public SMTPSTransport(Session session, URLName name) {
+ super(session, name, "smtps", 465, true);
+ }
+}
Added: geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/SMTPSendFailedException.java
URL: http://svn.apache.org/viewcvs/geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/SMTPSendFailedException.java?rev=398634&view=auto
==============================================================================
--- geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/SMTPSendFailedException.java (added)
+++ geronimo/branches/1.1/modules/javamail-transport/src/java/org/apache/geronimo/javamail/transport/smtp/SMTPSendFailedException.java Mon May 1 09:56:06 2006
@@ -0,0 +1,72 @@
+/**
+ *
+ * Copyright 2003-2005 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.geronimo.javamail.transport.smtp;
+
+import javax.mail.Address;
+import javax.mail.SendFailedException;
+
+public class SMTPSendFailedException extends SendFailedException {
+ // the failing command
+ protected String cmd;
+
+ // the error code for the failure
+ protected int rc;
+
+ /**
+ * Constructor for an SMTPSendFaileException.
+ *
+ * @param cmd
+ * The failing command string.
+ * @param rc
+ * The error code for the failing command.
+ * @param err
+ * An error message for the exception.
+ * @param ex
+ * Any associated nested exception.
+ * @param vs
+ * An array of valid, sent addresses.
+ * @param vus
+ * An array of addresses that were valid, but were unsent.
+ * @param inv
+ * An array of addresses deemed invalid.
+ */
+ SMTPSendFailedException(java.lang.String cmd, int rc, java.lang.String err, java.lang.Exception ex, Address[] vs,
+ Address[] vus, Address[] inv) {
+ super(err, ex, vs, vus, inv);
+ this.cmd = cmd;
+ this.rc = rc;
+ }
+
+ /**
+ * Get the failing command string for the exception.
+ *
+ * @return The string value of the failing command.
+ */
+ public String getCommand() {
+ return cmd;
+ }
+
+ /**
+ * The failing command return code.
+ *
+ * @return The failure return code.
+ */
+ public int getReturnCode() {
+ return rc;
+ }
+}