first commit
This commit is contained in:
commit
4d332ef662
27586 changed files with 3281783 additions and 0 deletions
199
rus/WEB-INF/lib/javax.mail_src/com/sun/mail/auth/MD4.java
Normal file
199
rus/WEB-INF/lib/javax.mail_src/com/sun/mail/auth/MD4.java
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
package com.sun.mail.auth;
|
||||
|
||||
public final class MD4 {
|
||||
private final int[] state;
|
||||
|
||||
private final int[] x;
|
||||
|
||||
private static final int blockSize = 64;
|
||||
|
||||
private final byte[] buffer = new byte[64];
|
||||
|
||||
private int bufOfs;
|
||||
|
||||
private long bytesProcessed;
|
||||
|
||||
private static final int S11 = 3;
|
||||
|
||||
private static final int S12 = 7;
|
||||
|
||||
private static final int S13 = 11;
|
||||
|
||||
private static final int S14 = 19;
|
||||
|
||||
private static final int S21 = 3;
|
||||
|
||||
private static final int S22 = 5;
|
||||
|
||||
private static final int S23 = 9;
|
||||
|
||||
private static final int S24 = 13;
|
||||
|
||||
private static final int S31 = 3;
|
||||
|
||||
private static final int S32 = 9;
|
||||
|
||||
private static final int S33 = 11;
|
||||
|
||||
private static final int S34 = 15;
|
||||
|
||||
private static final byte[] padding = new byte[136];
|
||||
|
||||
static {
|
||||
padding[0] = Byte.MIN_VALUE;
|
||||
}
|
||||
|
||||
public MD4() {
|
||||
this.state = new int[4];
|
||||
this.x = new int[16];
|
||||
implReset();
|
||||
}
|
||||
|
||||
public byte[] digest(byte[] in) {
|
||||
implReset();
|
||||
engineUpdate(in, 0, in.length);
|
||||
byte[] out = new byte[16];
|
||||
implDigest(out, 0);
|
||||
return out;
|
||||
}
|
||||
|
||||
private void implReset() {
|
||||
this.state[0] = 1732584193;
|
||||
this.state[1] = -271733879;
|
||||
this.state[2] = -1732584194;
|
||||
this.state[3] = 271733878;
|
||||
this.bufOfs = 0;
|
||||
this.bytesProcessed = 0L;
|
||||
}
|
||||
|
||||
private void implDigest(byte[] out, int ofs) {
|
||||
long bitsProcessed = this.bytesProcessed << 3L;
|
||||
int index = (int)this.bytesProcessed & 0x3F;
|
||||
int padLen = (index < 56) ? (56 - index) : (120 - index);
|
||||
engineUpdate(padding, 0, padLen);
|
||||
this.buffer[56] = (byte)(int)bitsProcessed;
|
||||
this.buffer[57] = (byte)(int)(bitsProcessed >> 8L);
|
||||
this.buffer[58] = (byte)(int)(bitsProcessed >> 16L);
|
||||
this.buffer[59] = (byte)(int)(bitsProcessed >> 24L);
|
||||
this.buffer[60] = (byte)(int)(bitsProcessed >> 32L);
|
||||
this.buffer[61] = (byte)(int)(bitsProcessed >> 40L);
|
||||
this.buffer[62] = (byte)(int)(bitsProcessed >> 48L);
|
||||
this.buffer[63] = (byte)(int)(bitsProcessed >> 56L);
|
||||
implCompress(this.buffer, 0);
|
||||
for (int i = 0; i < this.state.length; i++) {
|
||||
int x = this.state[i];
|
||||
out[ofs++] = (byte)x;
|
||||
out[ofs++] = (byte)(x >> 8);
|
||||
out[ofs++] = (byte)(x >> 16);
|
||||
out[ofs++] = (byte)(x >> 24);
|
||||
}
|
||||
}
|
||||
|
||||
private void engineUpdate(byte[] b, int ofs, int len) {
|
||||
if (len == 0)
|
||||
return;
|
||||
if (ofs < 0 || len < 0 || ofs > b.length - len)
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
if (this.bytesProcessed < 0L)
|
||||
implReset();
|
||||
this.bytesProcessed += (long)len;
|
||||
if (this.bufOfs != 0) {
|
||||
int n = Math.min(len, 64 - this.bufOfs);
|
||||
System.arraycopy(b, ofs, this.buffer, this.bufOfs, n);
|
||||
this.bufOfs += n;
|
||||
ofs += n;
|
||||
len -= n;
|
||||
if (this.bufOfs >= 64) {
|
||||
implCompress(this.buffer, 0);
|
||||
this.bufOfs = 0;
|
||||
}
|
||||
}
|
||||
while (len >= 64) {
|
||||
implCompress(b, ofs);
|
||||
len -= 64;
|
||||
ofs += 64;
|
||||
}
|
||||
if (len > 0) {
|
||||
System.arraycopy(b, ofs, this.buffer, 0, len);
|
||||
this.bufOfs = len;
|
||||
}
|
||||
}
|
||||
|
||||
private static int FF(int a, int b, int c, int d, int x, int s) {
|
||||
a += (b & c | (b ^ 0xFFFFFFFF) & d) + x;
|
||||
return a << s | a >>> 32 - s;
|
||||
}
|
||||
|
||||
private static int GG(int a, int b, int c, int d, int x, int s) {
|
||||
a += (b & c | b & d | c & d) + x + 1518500249;
|
||||
return a << s | a >>> 32 - s;
|
||||
}
|
||||
|
||||
private static int HH(int a, int b, int c, int d, int x, int s) {
|
||||
a += (b ^ c ^ d) + x + 1859775393;
|
||||
return a << s | a >>> 32 - s;
|
||||
}
|
||||
|
||||
private void implCompress(byte[] buf, int ofs) {
|
||||
for (int xfs = 0; xfs < this.x.length; xfs++) {
|
||||
this.x[xfs] = buf[ofs] & 0xFF | (buf[ofs + 1] & 0xFF) << 8 | (buf[ofs + 2] & 0xFF) << 16 | (buf[ofs + 3] & 0xFF) << 24;
|
||||
ofs += 4;
|
||||
}
|
||||
int a = this.state[0];
|
||||
int b = this.state[1];
|
||||
int c = this.state[2];
|
||||
int d = this.state[3];
|
||||
a = FF(a, b, c, d, this.x[0], 3);
|
||||
d = FF(d, a, b, c, this.x[1], 7);
|
||||
c = FF(c, d, a, b, this.x[2], 11);
|
||||
b = FF(b, c, d, a, this.x[3], 19);
|
||||
a = FF(a, b, c, d, this.x[4], 3);
|
||||
d = FF(d, a, b, c, this.x[5], 7);
|
||||
c = FF(c, d, a, b, this.x[6], 11);
|
||||
b = FF(b, c, d, a, this.x[7], 19);
|
||||
a = FF(a, b, c, d, this.x[8], 3);
|
||||
d = FF(d, a, b, c, this.x[9], 7);
|
||||
c = FF(c, d, a, b, this.x[10], 11);
|
||||
b = FF(b, c, d, a, this.x[11], 19);
|
||||
a = FF(a, b, c, d, this.x[12], 3);
|
||||
d = FF(d, a, b, c, this.x[13], 7);
|
||||
c = FF(c, d, a, b, this.x[14], 11);
|
||||
b = FF(b, c, d, a, this.x[15], 19);
|
||||
a = GG(a, b, c, d, this.x[0], 3);
|
||||
d = GG(d, a, b, c, this.x[4], 5);
|
||||
c = GG(c, d, a, b, this.x[8], 9);
|
||||
b = GG(b, c, d, a, this.x[12], 13);
|
||||
a = GG(a, b, c, d, this.x[1], 3);
|
||||
d = GG(d, a, b, c, this.x[5], 5);
|
||||
c = GG(c, d, a, b, this.x[9], 9);
|
||||
b = GG(b, c, d, a, this.x[13], 13);
|
||||
a = GG(a, b, c, d, this.x[2], 3);
|
||||
d = GG(d, a, b, c, this.x[6], 5);
|
||||
c = GG(c, d, a, b, this.x[10], 9);
|
||||
b = GG(b, c, d, a, this.x[14], 13);
|
||||
a = GG(a, b, c, d, this.x[3], 3);
|
||||
d = GG(d, a, b, c, this.x[7], 5);
|
||||
c = GG(c, d, a, b, this.x[11], 9);
|
||||
b = GG(b, c, d, a, this.x[15], 13);
|
||||
a = HH(a, b, c, d, this.x[0], 3);
|
||||
d = HH(d, a, b, c, this.x[8], 9);
|
||||
c = HH(c, d, a, b, this.x[4], 11);
|
||||
b = HH(b, c, d, a, this.x[12], 15);
|
||||
a = HH(a, b, c, d, this.x[2], 3);
|
||||
d = HH(d, a, b, c, this.x[10], 9);
|
||||
c = HH(c, d, a, b, this.x[6], 11);
|
||||
b = HH(b, c, d, a, this.x[14], 15);
|
||||
a = HH(a, b, c, d, this.x[1], 3);
|
||||
d = HH(d, a, b, c, this.x[9], 9);
|
||||
c = HH(c, d, a, b, this.x[5], 11);
|
||||
b = HH(b, c, d, a, this.x[13], 15);
|
||||
a = HH(a, b, c, d, this.x[3], 3);
|
||||
d = HH(d, a, b, c, this.x[11], 9);
|
||||
c = HH(c, d, a, b, this.x[7], 11);
|
||||
b = HH(b, c, d, a, this.x[15], 15);
|
||||
this.state[0] = this.state[0] + a;
|
||||
this.state[1] = this.state[1] + b;
|
||||
this.state[2] = this.state[2] + c;
|
||||
this.state[3] = this.state[3] + d;
|
||||
}
|
||||
}
|
||||
278
rus/WEB-INF/lib/javax.mail_src/com/sun/mail/auth/Ntlm.java
Normal file
278
rus/WEB-INF/lib/javax.mail_src/com/sun/mail/auth/Ntlm.java
Normal file
|
|
@ -0,0 +1,278 @@
|
|||
package com.sun.mail.auth;
|
||||
|
||||
import com.sun.mail.util.BASE64DecoderStream;
|
||||
import com.sun.mail.util.BASE64EncoderStream;
|
||||
import com.sun.mail.util.MailLogger;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Locale;
|
||||
import java.util.logging.Level;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.SecretKeyFactory;
|
||||
import javax.crypto.spec.DESKeySpec;
|
||||
|
||||
public class Ntlm {
|
||||
private byte[] type1;
|
||||
|
||||
private byte[] type3;
|
||||
|
||||
private SecretKeyFactory fac;
|
||||
|
||||
private Cipher cipher;
|
||||
|
||||
private MD4 md4;
|
||||
|
||||
private String hostname;
|
||||
|
||||
private String ntdomain;
|
||||
|
||||
private String username;
|
||||
|
||||
private String password;
|
||||
|
||||
private MailLogger logger;
|
||||
|
||||
private void init0() {
|
||||
this.type1 = new byte[256];
|
||||
this.type3 = new byte[256];
|
||||
System.arraycopy(new byte[] { 78, 84, 76, 77, 83, 83, 80, 0, 1 }, 0, this.type1, 0, 9);
|
||||
this.type1[12] = 3;
|
||||
this.type1[13] = -78;
|
||||
this.type1[28] = 32;
|
||||
System.arraycopy(new byte[] { 78, 84, 76, 77, 83, 83, 80, 0, 3 }, 0, this.type3, 0, 9);
|
||||
this.type3[12] = 24;
|
||||
this.type3[14] = 24;
|
||||
this.type3[20] = 24;
|
||||
this.type3[22] = 24;
|
||||
this.type3[32] = 64;
|
||||
this.type3[60] = 1;
|
||||
this.type3[61] = -126;
|
||||
try {
|
||||
this.fac = SecretKeyFactory.getInstance("DES");
|
||||
this.cipher = Cipher.getInstance("DES/ECB/NoPadding");
|
||||
this.md4 = new MD4();
|
||||
} catch (NoSuchPaddingException e) {
|
||||
assert false;
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
assert false;
|
||||
}
|
||||
}
|
||||
|
||||
public Ntlm(String ntdomain, String hostname, String username, String password, MailLogger logger) {
|
||||
int i = hostname.indexOf('.');
|
||||
if (i != -1)
|
||||
hostname = hostname.substring(0, i);
|
||||
i = username.indexOf('\\');
|
||||
if (i != -1) {
|
||||
ntdomain = username.substring(0, i).toUpperCase(Locale.ENGLISH);
|
||||
username = username.substring(i + 1);
|
||||
} else if (ntdomain == null) {
|
||||
ntdomain = "";
|
||||
}
|
||||
this.ntdomain = ntdomain;
|
||||
this.hostname = hostname;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.logger = logger.getLogger(getClass(), "DEBUG NTLM");
|
||||
init0();
|
||||
}
|
||||
|
||||
private void copybytes(byte[] dest, int destpos, String src, String enc) {
|
||||
try {
|
||||
byte[] x = src.getBytes(enc);
|
||||
System.arraycopy(x, 0, dest, destpos, x.length);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
assert false;
|
||||
}
|
||||
}
|
||||
|
||||
public String generateType1Msg(int flags) {
|
||||
int dlen = this.ntdomain.length();
|
||||
this.type1[16] = (byte)(dlen % 256);
|
||||
this.type1[17] = (byte)(dlen / 256);
|
||||
this.type1[18] = this.type1[16];
|
||||
this.type1[19] = this.type1[17];
|
||||
if (dlen == 0)
|
||||
this.type1[13] = (byte)(this.type1[13] & 0xFFFFFFEF);
|
||||
int hlen = this.hostname.length();
|
||||
this.type1[24] = (byte)(hlen % 256);
|
||||
this.type1[25] = (byte)(hlen / 256);
|
||||
this.type1[26] = this.type1[24];
|
||||
this.type1[27] = this.type1[25];
|
||||
copybytes(this.type1, 32, this.hostname, "iso-8859-1");
|
||||
copybytes(this.type1, hlen + 32, this.ntdomain, "iso-8859-1");
|
||||
this.type1[20] = (byte)((hlen + 32) % 256);
|
||||
this.type1[21] = (byte)((hlen + 32) / 256);
|
||||
byte[] msg = new byte[32 + hlen + dlen];
|
||||
System.arraycopy(this.type1, 0, msg, 0, 32 + hlen + dlen);
|
||||
if (this.logger.isLoggable(Level.FINE))
|
||||
this.logger.fine("type 1 message: " + toHex(msg));
|
||||
String result = null;
|
||||
try {
|
||||
result = new String(BASE64EncoderStream.encode(msg), "iso-8859-1");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
assert false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private byte[] makeDesKey(byte[] input, int off) {
|
||||
int[] in = new int[input.length];
|
||||
for (int i = 0; i < in.length; i++)
|
||||
in[i] = (input[i] < 0) ? (input[i] + 256) : input[i];
|
||||
byte[] out = new byte[8];
|
||||
out[0] = (byte)in[off + 0];
|
||||
out[1] = (byte)(in[off + 0] << 7 & 0xFF | in[off + 1] >> 1);
|
||||
out[2] = (byte)(in[off + 1] << 6 & 0xFF | in[off + 2] >> 2);
|
||||
out[3] = (byte)(in[off + 2] << 5 & 0xFF | in[off + 3] >> 3);
|
||||
out[4] = (byte)(in[off + 3] << 4 & 0xFF | in[off + 4] >> 4);
|
||||
out[5] = (byte)(in[off + 4] << 3 & 0xFF | in[off + 5] >> 5);
|
||||
out[6] = (byte)(in[off + 5] << 2 & 0xFF | in[off + 6] >> 6);
|
||||
out[7] = (byte)(in[off + 6] << 1 & 0xFF);
|
||||
return out;
|
||||
}
|
||||
|
||||
private byte[] calcLMHash() throws GeneralSecurityException {
|
||||
byte[] magic = { 75, 71, 83, 33, 64, 35, 36, 37 };
|
||||
byte[] pwb = null;
|
||||
try {
|
||||
pwb = this.password.toUpperCase(Locale.ENGLISH).getBytes("iso-8859-1");
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
assert false;
|
||||
}
|
||||
byte[] pwb1 = new byte[14];
|
||||
int len = this.password.length();
|
||||
if (len > 14)
|
||||
len = 14;
|
||||
System.arraycopy(pwb, 0, pwb1, 0, len);
|
||||
DESKeySpec dks1 = new DESKeySpec(makeDesKey(pwb1, 0));
|
||||
DESKeySpec dks2 = new DESKeySpec(makeDesKey(pwb1, 7));
|
||||
SecretKey key1 = this.fac.generateSecret(dks1);
|
||||
SecretKey key2 = this.fac.generateSecret(dks2);
|
||||
this.cipher.init(1, key1);
|
||||
byte[] out1 = this.cipher.doFinal(magic, 0, 8);
|
||||
this.cipher.init(1, key2);
|
||||
byte[] out2 = this.cipher.doFinal(magic, 0, 8);
|
||||
byte[] result = new byte[21];
|
||||
System.arraycopy(out1, 0, result, 0, 8);
|
||||
System.arraycopy(out2, 0, result, 8, 8);
|
||||
return result;
|
||||
}
|
||||
|
||||
private byte[] calcNTHash() throws GeneralSecurityException {
|
||||
byte[] pw = null;
|
||||
try {
|
||||
pw = this.password.getBytes("UnicodeLittleUnmarked");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
assert false;
|
||||
}
|
||||
byte[] out = this.md4.digest(pw);
|
||||
byte[] result = new byte[21];
|
||||
System.arraycopy(out, 0, result, 0, 16);
|
||||
return result;
|
||||
}
|
||||
|
||||
private byte[] calcResponse(byte[] key, byte[] text) throws GeneralSecurityException {
|
||||
assert key.length == 21;
|
||||
DESKeySpec dks1 = new DESKeySpec(makeDesKey(key, 0));
|
||||
DESKeySpec dks2 = new DESKeySpec(makeDesKey(key, 7));
|
||||
DESKeySpec dks3 = new DESKeySpec(makeDesKey(key, 14));
|
||||
SecretKey key1 = this.fac.generateSecret(dks1);
|
||||
SecretKey key2 = this.fac.generateSecret(dks2);
|
||||
SecretKey key3 = this.fac.generateSecret(dks3);
|
||||
this.cipher.init(1, key1);
|
||||
byte[] out1 = this.cipher.doFinal(text, 0, 8);
|
||||
this.cipher.init(1, key2);
|
||||
byte[] out2 = this.cipher.doFinal(text, 0, 8);
|
||||
this.cipher.init(1, key3);
|
||||
byte[] out3 = this.cipher.doFinal(text, 0, 8);
|
||||
byte[] result = new byte[24];
|
||||
System.arraycopy(out1, 0, result, 0, 8);
|
||||
System.arraycopy(out2, 0, result, 8, 8);
|
||||
System.arraycopy(out3, 0, result, 16, 8);
|
||||
return result;
|
||||
}
|
||||
|
||||
public String generateType3Msg(String challenge) {
|
||||
try {
|
||||
byte[] type2 = null;
|
||||
try {
|
||||
type2 = BASE64DecoderStream.decode(challenge.getBytes("us-ascii"));
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
assert false;
|
||||
}
|
||||
byte[] nonce = new byte[8];
|
||||
System.arraycopy(type2, 24, nonce, 0, 8);
|
||||
int ulen = this.username.length() * 2;
|
||||
this.type3[38] = (byte)(ulen % 256);
|
||||
this.type3[36] = (byte)(ulen % 256);
|
||||
this.type3[39] = (byte)(ulen / 256);
|
||||
this.type3[37] = (byte)(ulen / 256);
|
||||
int dlen = this.ntdomain.length() * 2;
|
||||
this.type3[30] = (byte)(dlen % 256);
|
||||
this.type3[28] = (byte)(dlen % 256);
|
||||
this.type3[31] = (byte)(dlen / 256);
|
||||
this.type3[29] = (byte)(dlen / 256);
|
||||
int hlen = this.hostname.length() * 2;
|
||||
this.type3[46] = (byte)(hlen % 256);
|
||||
this.type3[44] = (byte)(hlen % 256);
|
||||
this.type3[47] = (byte)(hlen / 256);
|
||||
this.type3[45] = (byte)(hlen / 256);
|
||||
int l = 64;
|
||||
copybytes(this.type3, l, this.ntdomain, "UnicodeLittleUnmarked");
|
||||
this.type3[32] = (byte)(l % 256);
|
||||
this.type3[33] = (byte)(l / 256);
|
||||
l += dlen;
|
||||
copybytes(this.type3, l, this.username, "UnicodeLittleUnmarked");
|
||||
this.type3[40] = (byte)(l % 256);
|
||||
this.type3[41] = (byte)(l / 256);
|
||||
l += ulen;
|
||||
copybytes(this.type3, l, this.hostname, "UnicodeLittleUnmarked");
|
||||
this.type3[48] = (byte)(l % 256);
|
||||
this.type3[49] = (byte)(l / 256);
|
||||
l += hlen;
|
||||
byte[] lmhash = calcLMHash();
|
||||
byte[] lmresponse = calcResponse(lmhash, nonce);
|
||||
byte[] nthash = calcNTHash();
|
||||
byte[] ntresponse = calcResponse(nthash, nonce);
|
||||
System.arraycopy(lmresponse, 0, this.type3, l, 24);
|
||||
this.type3[16] = (byte)(l % 256);
|
||||
this.type3[17] = (byte)(l / 256);
|
||||
l += 24;
|
||||
System.arraycopy(ntresponse, 0, this.type3, l, 24);
|
||||
this.type3[24] = (byte)(l % 256);
|
||||
this.type3[25] = (byte)(l / 256);
|
||||
l += 24;
|
||||
this.type3[56] = (byte)(l % 256);
|
||||
this.type3[57] = (byte)(l / 256);
|
||||
byte[] msg = new byte[l];
|
||||
System.arraycopy(this.type3, 0, msg, 0, l);
|
||||
if (this.logger.isLoggable(Level.FINE))
|
||||
this.logger.fine("type 3 message: " + toHex(msg));
|
||||
String result = null;
|
||||
try {
|
||||
result = new String(BASE64EncoderStream.encode(msg), "iso-8859-1");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
assert false;
|
||||
}
|
||||
return result;
|
||||
} catch (GeneralSecurityException ex) {
|
||||
this.logger.log(Level.FINE, "GeneralSecurityException", (Throwable)ex);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private static char[] hex = new char[] {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'A', 'B', 'C', 'D', 'E', 'F' };
|
||||
|
||||
private static String toHex(byte[] b) {
|
||||
StringBuffer sb = new StringBuffer(b.length * 3);
|
||||
for (int i = 0; i < b.length; i++)
|
||||
sb.append(hex[b[i] >> 4 & 0xF]).append(hex[b[i] & 0xF]).append(' ');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
package com.sun.mail.auth;
|
||||
|
||||
import com.sun.mail.util.ASCIIUtility;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Map;
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
import javax.security.auth.callback.NameCallback;
|
||||
import javax.security.auth.callback.PasswordCallback;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
import javax.security.sasl.SaslClient;
|
||||
import javax.security.sasl.SaslException;
|
||||
|
||||
public class OAuth2SaslClient implements SaslClient {
|
||||
private CallbackHandler cbh;
|
||||
|
||||
private boolean complete = false;
|
||||
|
||||
public OAuth2SaslClient(Map<String, ?> props, CallbackHandler cbh) {
|
||||
this.cbh = cbh;
|
||||
}
|
||||
|
||||
public String getMechanismName() {
|
||||
return "XOAUTH2";
|
||||
}
|
||||
|
||||
public boolean hasInitialResponse() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public byte[] evaluateChallenge(byte[] challenge) throws SaslException {
|
||||
byte[] response;
|
||||
if (this.complete)
|
||||
return new byte[0];
|
||||
NameCallback ncb = new NameCallback("User name:");
|
||||
PasswordCallback pcb = new PasswordCallback("OAuth token:", false);
|
||||
try {
|
||||
this.cbh.handle(new Callback[] { ncb, pcb });
|
||||
} catch (UnsupportedCallbackException ex) {
|
||||
throw new SaslException("Unsupported callback", ex);
|
||||
} catch (IOException ex) {
|
||||
throw new SaslException("Callback handler failed", ex);
|
||||
}
|
||||
String user = ncb.getName();
|
||||
String token = new String(pcb.getPassword());
|
||||
pcb.clearPassword();
|
||||
String resp = "user=" + user + "\001auth=Bearer " + token + "\001\001";
|
||||
try {
|
||||
response = resp.getBytes("utf-8");
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
response = ASCIIUtility.getBytes(resp);
|
||||
}
|
||||
this.complete = true;
|
||||
return response;
|
||||
}
|
||||
|
||||
public boolean isComplete() {
|
||||
return this.complete;
|
||||
}
|
||||
|
||||
public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException {
|
||||
throw new IllegalStateException("OAUTH2 unwrap not supported");
|
||||
}
|
||||
|
||||
public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException {
|
||||
throw new IllegalStateException("OAUTH2 wrap not supported");
|
||||
}
|
||||
|
||||
public Object getNegotiatedProperty(String propName) {
|
||||
if (!this.complete)
|
||||
throw new IllegalStateException("OAUTH2 getNegotiatedProperty");
|
||||
return null;
|
||||
}
|
||||
|
||||
public void dispose() throws SaslException {}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package com.sun.mail.auth;
|
||||
|
||||
import java.security.Provider;
|
||||
import java.security.Security;
|
||||
import java.util.Map;
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
import javax.security.sasl.SaslClient;
|
||||
import javax.security.sasl.SaslClientFactory;
|
||||
import javax.security.sasl.SaslException;
|
||||
|
||||
public class OAuth2SaslClientFactory implements SaslClientFactory {
|
||||
private static final String PROVIDER_NAME = "JavaMail-OAuth2";
|
||||
|
||||
private static final String MECHANISM_NAME = "SaslClientFactory.XOAUTH2";
|
||||
|
||||
static class OAuth2Provider extends Provider {
|
||||
private static final long serialVersionUID = -5371795551562287059L;
|
||||
|
||||
public OAuth2Provider() {
|
||||
super("JavaMail-OAuth2", 1.0D, "XOAUTH2 SASL Mechanism");
|
||||
put("SaslClientFactory.XOAUTH2", OAuth2SaslClientFactory.class.getName());
|
||||
}
|
||||
}
|
||||
|
||||
public SaslClient createSaslClient(String[] mechanisms, String authorizationId, String protocol, String serverName, Map<String, ?> props, CallbackHandler cbh) throws SaslException {
|
||||
for (String m : mechanisms) {
|
||||
if (m.equals("XOAUTH2"))
|
||||
return new OAuth2SaslClient(props, cbh);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String[] getMechanismNames(Map<String, ?> props) {
|
||||
return new String[] { "XOAUTH2" };
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
try {
|
||||
if (Security.getProvider("JavaMail-OAuth2") == null)
|
||||
Security.addProvider(new OAuth2Provider());
|
||||
} catch (SecurityException e) {}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
package com.sun.mail.handlers;
|
||||
|
||||
import java.awt.Image;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.datatransfer.DataFlavor;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import javax.activation.ActivationDataFlavor;
|
||||
import javax.activation.DataContentHandler;
|
||||
import javax.activation.DataSource;
|
||||
|
||||
public class image_gif implements DataContentHandler {
|
||||
private static ActivationDataFlavor myDF = new ActivationDataFlavor(Image.class, "image/gif", "GIF Image");
|
||||
|
||||
protected ActivationDataFlavor getDF() {
|
||||
return myDF;
|
||||
}
|
||||
|
||||
public DataFlavor[] getTransferDataFlavors() {
|
||||
return new DataFlavor[] { (DataFlavor)getDF() };
|
||||
}
|
||||
|
||||
public Object getTransferData(DataFlavor df, DataSource ds) throws IOException {
|
||||
if (getDF().equals(df))
|
||||
return getContent(ds);
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object getContent(DataSource ds) throws IOException {
|
||||
InputStream is = ds.getInputStream();
|
||||
int pos = 0;
|
||||
byte[] buf = new byte[1024];
|
||||
int count;
|
||||
while ((count = is.read(buf, pos, buf.length - pos)) != -1) {
|
||||
pos += count;
|
||||
if (pos >= buf.length) {
|
||||
int size = buf.length;
|
||||
if (size < 262144) {
|
||||
size += size;
|
||||
} else {
|
||||
size += 262144;
|
||||
}
|
||||
byte[] tbuf = new byte[size];
|
||||
System.arraycopy(buf, 0, tbuf, 0, pos);
|
||||
buf = tbuf;
|
||||
}
|
||||
}
|
||||
Toolkit tk = Toolkit.getDefaultToolkit();
|
||||
return tk.createImage(buf, 0, pos);
|
||||
}
|
||||
|
||||
public void writeTo(Object obj, String type, OutputStream os) throws IOException {
|
||||
if (!(obj instanceof Image))
|
||||
throw new IOException("\"" + getDF().getMimeType() + "\" DataContentHandler requires Image object, " + "was given object of type " +
|
||||
|
||||
obj.getClass().toString());
|
||||
throw new IOException(getDF().getMimeType() + " encoding not supported");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.sun.mail.handlers;
|
||||
|
||||
import java.awt.Image;
|
||||
import javax.activation.ActivationDataFlavor;
|
||||
|
||||
public class image_jpeg extends image_gif {
|
||||
private static ActivationDataFlavor myDF = new ActivationDataFlavor(Image.class, "image/jpeg", "JPEG Image");
|
||||
|
||||
protected ActivationDataFlavor getDF() {
|
||||
return myDF;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
package com.sun.mail.handlers;
|
||||
|
||||
import java.awt.datatransfer.DataFlavor;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Properties;
|
||||
import javax.activation.ActivationDataFlavor;
|
||||
import javax.activation.DataContentHandler;
|
||||
import javax.activation.DataSource;
|
||||
import javax.mail.Message;
|
||||
import javax.mail.MessageAware;
|
||||
import javax.mail.MessageContext;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
|
||||
public class message_rfc822 implements DataContentHandler {
|
||||
ActivationDataFlavor ourDataFlavor = new ActivationDataFlavor(Message.class, "message/rfc822", "Message");
|
||||
|
||||
public DataFlavor[] getTransferDataFlavors() {
|
||||
return new DataFlavor[] { (DataFlavor)this.ourDataFlavor };
|
||||
}
|
||||
|
||||
public Object getTransferData(DataFlavor df, DataSource ds) throws IOException {
|
||||
if (this.ourDataFlavor.equals(df))
|
||||
return getContent(ds);
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object getContent(DataSource ds) throws IOException {
|
||||
try {
|
||||
Session session;
|
||||
if (ds instanceof MessageAware) {
|
||||
MessageContext mc = ((MessageAware)ds).getMessageContext();
|
||||
session = mc.getSession();
|
||||
} else {
|
||||
session = Session.getDefaultInstance(new Properties(), null);
|
||||
}
|
||||
return new MimeMessage(session, ds.getInputStream());
|
||||
} catch (MessagingException me) {
|
||||
throw new IOException("Exception creating MimeMessage in message/rfc822 DataContentHandler: " +
|
||||
me.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public void writeTo(Object obj, String mimeType, OutputStream os) throws IOException {
|
||||
if (obj instanceof Message) {
|
||||
Message m = (Message)obj;
|
||||
try {
|
||||
m.writeTo(os);
|
||||
} catch (MessagingException me) {
|
||||
throw new IOException(me.toString());
|
||||
}
|
||||
} else {
|
||||
throw new IOException("unsupported object");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package com.sun.mail.handlers;
|
||||
|
||||
import java.awt.datatransfer.DataFlavor;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import javax.activation.ActivationDataFlavor;
|
||||
import javax.activation.DataContentHandler;
|
||||
import javax.activation.DataSource;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.internet.MimeMultipart;
|
||||
|
||||
public class multipart_mixed implements DataContentHandler {
|
||||
private ActivationDataFlavor myDF = new ActivationDataFlavor(MimeMultipart.class, "multipart/mixed", "Multipart");
|
||||
|
||||
public DataFlavor[] getTransferDataFlavors() {
|
||||
return new DataFlavor[] { (DataFlavor)this.myDF };
|
||||
}
|
||||
|
||||
public Object getTransferData(DataFlavor df, DataSource ds) throws IOException {
|
||||
if (this.myDF.equals(df))
|
||||
return getContent(ds);
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object getContent(DataSource ds) throws IOException {
|
||||
try {
|
||||
return new MimeMultipart(ds);
|
||||
} catch (MessagingException e) {
|
||||
IOException ioex = new IOException("Exception while constructing MimeMultipart");
|
||||
ioex.initCause(e);
|
||||
throw ioex;
|
||||
}
|
||||
}
|
||||
|
||||
public void writeTo(Object obj, String mimeType, OutputStream os) throws IOException {
|
||||
if (obj instanceof MimeMultipart)
|
||||
try {
|
||||
((MimeMultipart)obj).writeTo(os);
|
||||
} catch (MessagingException e) {
|
||||
throw new IOException(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.sun.mail.handlers;
|
||||
|
||||
import javax.activation.ActivationDataFlavor;
|
||||
|
||||
public class text_html extends text_plain {
|
||||
private static ActivationDataFlavor myDF = new ActivationDataFlavor(String.class, "text/html", "HTML String");
|
||||
|
||||
protected ActivationDataFlavor getDF() {
|
||||
return myDF;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
package com.sun.mail.handlers;
|
||||
|
||||
import java.awt.datatransfer.DataFlavor;
|
||||
import java.io.FilterOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import javax.activation.ActivationDataFlavor;
|
||||
import javax.activation.DataContentHandler;
|
||||
import javax.activation.DataSource;
|
||||
import javax.mail.internet.ContentType;
|
||||
import javax.mail.internet.MimeUtility;
|
||||
|
||||
public class text_plain implements DataContentHandler {
|
||||
private static ActivationDataFlavor myDF = new ActivationDataFlavor(String.class, "text/plain", "Text String");
|
||||
|
||||
private static class NoCloseOutputStream extends FilterOutputStream {
|
||||
public NoCloseOutputStream(OutputStream os) {
|
||||
super(os);
|
||||
}
|
||||
|
||||
public void close() {}
|
||||
}
|
||||
|
||||
protected ActivationDataFlavor getDF() {
|
||||
return myDF;
|
||||
}
|
||||
|
||||
public DataFlavor[] getTransferDataFlavors() {
|
||||
return new DataFlavor[] { (DataFlavor)getDF() };
|
||||
}
|
||||
|
||||
public Object getTransferData(DataFlavor df, DataSource ds) throws IOException {
|
||||
if (getDF().equals(df))
|
||||
return getContent(ds);
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object getContent(DataSource ds) throws IOException {
|
||||
String enc = null;
|
||||
InputStreamReader is = null;
|
||||
try {
|
||||
enc = getCharset(ds.getContentType());
|
||||
is = new InputStreamReader(ds.getInputStream(), enc);
|
||||
} catch (IllegalArgumentException iex) {
|
||||
throw new UnsupportedEncodingException(enc);
|
||||
}
|
||||
try {
|
||||
int pos = 0;
|
||||
char[] buf = new char[1024];
|
||||
int count;
|
||||
while ((count = is.read(buf, pos, buf.length - pos)) != -1) {
|
||||
pos += count;
|
||||
if (pos >= buf.length) {
|
||||
int size = buf.length;
|
||||
if (size < 262144) {
|
||||
size += size;
|
||||
} else {
|
||||
size += 262144;
|
||||
}
|
||||
char[] tbuf = new char[size];
|
||||
System.arraycopy(buf, 0, tbuf, 0, pos);
|
||||
buf = tbuf;
|
||||
}
|
||||
}
|
||||
return new String(buf, 0, pos);
|
||||
} finally {
|
||||
try {
|
||||
is.close();
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
}
|
||||
|
||||
public void writeTo(Object obj, String type, OutputStream os) throws IOException {
|
||||
if (!(obj instanceof String))
|
||||
throw new IOException("\"" + getDF().getMimeType() + "\" DataContentHandler requires String object, " + "was given object of type " +
|
||||
|
||||
obj.getClass().toString());
|
||||
String enc = null;
|
||||
OutputStreamWriter osw = null;
|
||||
try {
|
||||
enc = getCharset(type);
|
||||
osw = new OutputStreamWriter(new NoCloseOutputStream(os), enc);
|
||||
} catch (IllegalArgumentException iex) {
|
||||
throw new UnsupportedEncodingException(enc);
|
||||
}
|
||||
String s = (String)obj;
|
||||
osw.write(s, 0, s.length());
|
||||
osw.close();
|
||||
}
|
||||
|
||||
private String getCharset(String type) {
|
||||
try {
|
||||
ContentType ct = new ContentType(type);
|
||||
String charset = ct.getParameter("charset");
|
||||
if (charset == null)
|
||||
charset = "us-ascii";
|
||||
return MimeUtility.javaCharset(charset);
|
||||
} catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
package com.sun.mail.handlers;
|
||||
|
||||
import java.awt.datatransfer.DataFlavor;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import javax.activation.ActivationDataFlavor;
|
||||
import javax.activation.DataSource;
|
||||
import javax.mail.internet.ContentType;
|
||||
import javax.mail.internet.ParseException;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
|
||||
public class text_xml extends text_plain {
|
||||
private final DataFlavor[] flavors = new DataFlavor[] { new ActivationDataFlavor(String.class, "text/xml", "XML String"), new ActivationDataFlavor(String.class, "application/xml", "XML String"), new ActivationDataFlavor(StreamSource.class, "text/xml", "XML"), new ActivationDataFlavor(StreamSource.class, "application/xml", "XML") };
|
||||
|
||||
public DataFlavor[] getTransferDataFlavors() {
|
||||
return (DataFlavor[])this.flavors.clone();
|
||||
}
|
||||
|
||||
public Object getTransferData(DataFlavor df, DataSource ds) throws IOException {
|
||||
for (int i = 0; i < this.flavors.length; i++) {
|
||||
DataFlavor aFlavor = this.flavors[i];
|
||||
if (aFlavor.equals(df)) {
|
||||
if (aFlavor.getRepresentationClass() == String.class)
|
||||
return getContent(ds);
|
||||
if (aFlavor.getRepresentationClass() == StreamSource.class)
|
||||
return new StreamSource(ds.getInputStream());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void writeTo(Object obj, String mimeType, OutputStream os) throws IOException {
|
||||
if (!isXmlType(mimeType))
|
||||
throw new IOException("Invalid content type \"" + mimeType + "\" for text/xml DCH");
|
||||
if (obj instanceof String) {
|
||||
super.writeTo(obj, mimeType, os);
|
||||
return;
|
||||
}
|
||||
if (!(obj instanceof DataSource) && !(obj instanceof Source))
|
||||
throw new IOException("Invalid Object type = " + obj.getClass() + ". XmlDCH can only convert DataSource or Source to XML.");
|
||||
try {
|
||||
Transformer transformer = TransformerFactory.newInstance().newTransformer();
|
||||
StreamResult result = new StreamResult(os);
|
||||
if (obj instanceof DataSource) {
|
||||
transformer.transform(new StreamSource(((DataSource)obj)
|
||||
.getInputStream()), result);
|
||||
} else {
|
||||
transformer.transform((Source)obj, result);
|
||||
}
|
||||
} catch (TransformerException ex) {
|
||||
IOException ioex = new IOException("Unable to run the JAXP transformer on a stream " +
|
||||
|
||||
ex.getMessage());
|
||||
ioex.initCause(ex);
|
||||
throw ioex;
|
||||
} catch (RuntimeException ex) {
|
||||
IOException ioex = new IOException("Unable to run the JAXP transformer on a stream " +
|
||||
|
||||
ex.getMessage());
|
||||
ioex.initCause(ex);
|
||||
throw ioex;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isXmlType(String type) {
|
||||
try {
|
||||
ContentType ct = new ContentType(type);
|
||||
return (ct.getSubType().equals("xml") && (
|
||||
ct.getPrimaryType().equals("text") ||
|
||||
ct.getPrimaryType().equals("application")));
|
||||
} catch (ParseException ex) {
|
||||
return false;
|
||||
} catch (RuntimeException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.sun.mail.iap;
|
||||
|
||||
class AString {
|
||||
byte[] bytes;
|
||||
|
||||
AString(byte[] b) {
|
||||
this.bytes = b;
|
||||
}
|
||||
}
|
||||
203
rus/WEB-INF/lib/javax.mail_src/com/sun/mail/iap/Argument.java
Normal file
203
rus/WEB-INF/lib/javax.mail_src/com/sun/mail/iap/Argument.java
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
package com.sun.mail.iap;
|
||||
|
||||
import com.sun.mail.util.ASCIIUtility;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Argument {
|
||||
protected List items = new ArrayList(1);
|
||||
|
||||
public Argument append(Argument arg) {
|
||||
this.items.addAll(arg.items);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Argument writeString(String s) {
|
||||
this.items.add(new AString(ASCIIUtility.getBytes(s)));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Argument writeString(String s, String charset) throws UnsupportedEncodingException {
|
||||
if (charset == null) {
|
||||
writeString(s);
|
||||
} else {
|
||||
this.items.add(new AString(s.getBytes(charset)));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Argument writeNString(String s) {
|
||||
if (s == null) {
|
||||
this.items.add(new NString(null));
|
||||
} else {
|
||||
this.items.add(new NString(ASCIIUtility.getBytes(s)));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Argument writeNString(String s, String charset) throws UnsupportedEncodingException {
|
||||
if (s == null) {
|
||||
this.items.add(new NString(null));
|
||||
} else if (charset == null) {
|
||||
writeString(s);
|
||||
} else {
|
||||
this.items.add(new NString(s.getBytes(charset)));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Argument writeBytes(byte[] b) {
|
||||
this.items.add(b);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Argument writeBytes(ByteArrayOutputStream b) {
|
||||
this.items.add(b);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Argument writeBytes(Literal b) {
|
||||
this.items.add(b);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Argument writeAtom(String s) {
|
||||
this.items.add(new Atom(s));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Argument writeNumber(int i) {
|
||||
this.items.add(Integer.valueOf(i));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Argument writeNumber(long i) {
|
||||
this.items.add(Long.valueOf(i));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Argument writeArgument(Argument c) {
|
||||
this.items.add(c);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void write(Protocol protocol) throws IOException, ProtocolException {
|
||||
int size = (this.items != null) ? this.items.size() : 0;
|
||||
DataOutputStream os = (DataOutputStream)protocol.getOutputStream();
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (i > 0)
|
||||
os.write(32);
|
||||
Object o = this.items.get(i);
|
||||
if (o instanceof Atom) {
|
||||
os.writeBytes(((Atom)o).string);
|
||||
} else if (o instanceof Number) {
|
||||
os.writeBytes(((Number)o).toString());
|
||||
} else if (o instanceof AString) {
|
||||
astring(((AString)o).bytes, protocol);
|
||||
} else if (o instanceof NString) {
|
||||
nstring(((NString)o).bytes, protocol);
|
||||
} else if (o instanceof byte[]) {
|
||||
literal((byte[])o, protocol);
|
||||
} else if (o instanceof ByteArrayOutputStream) {
|
||||
literal((ByteArrayOutputStream)o, protocol);
|
||||
} else if (o instanceof Literal) {
|
||||
literal((Literal)o, protocol);
|
||||
} else if (o instanceof Argument) {
|
||||
os.write(40);
|
||||
((Argument)o).write(protocol);
|
||||
os.write(41);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void astring(byte[] bytes, Protocol protocol) throws IOException, ProtocolException {
|
||||
nastring(bytes, protocol, false);
|
||||
}
|
||||
|
||||
private void nstring(byte[] bytes, Protocol protocol) throws IOException, ProtocolException {
|
||||
if (bytes == null) {
|
||||
DataOutputStream os = (DataOutputStream)protocol.getOutputStream();
|
||||
os.writeBytes("NIL");
|
||||
} else {
|
||||
nastring(bytes, protocol, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void nastring(byte[] bytes, Protocol protocol, boolean doQuote) throws IOException, ProtocolException {
|
||||
DataOutputStream os = (DataOutputStream)protocol.getOutputStream();
|
||||
int len = bytes.length;
|
||||
if (len > 1024) {
|
||||
literal(bytes, protocol);
|
||||
return;
|
||||
}
|
||||
boolean quote = (len == 0) ? true : doQuote;
|
||||
boolean escape = false;
|
||||
for (int i = 0; i < len; i++) {
|
||||
byte b = bytes[i];
|
||||
if (b == 0 || b == 13 || b == 10 || (b & 0xFF) > 127) {
|
||||
literal(bytes, protocol);
|
||||
return;
|
||||
}
|
||||
if (b == 42 || b == 37 || b == 40 || b == 41 || b == 123 || b == 34 || b == 92 || (b & 0xFF) <= 32) {
|
||||
quote = true;
|
||||
if (b == 34 || b == 92)
|
||||
escape = true;
|
||||
}
|
||||
}
|
||||
if (!quote && bytes.length == 3 && (bytes[0] == 78 || bytes[0] == 110) && (bytes[1] == 73 || bytes[1] == 105) && (bytes[2] == 76 || bytes[2] == 108))
|
||||
quote = true;
|
||||
if (quote)
|
||||
os.write(34);
|
||||
if (escape) {
|
||||
for (int j = 0; j < len; j++) {
|
||||
byte b = bytes[j];
|
||||
if (b == 34 || b == 92)
|
||||
os.write(92);
|
||||
os.write(b);
|
||||
}
|
||||
} else {
|
||||
os.write(bytes);
|
||||
}
|
||||
if (quote)
|
||||
os.write(34);
|
||||
}
|
||||
|
||||
private void literal(byte[] b, Protocol protocol) throws IOException, ProtocolException {
|
||||
startLiteral(protocol, b.length).write(b);
|
||||
}
|
||||
|
||||
private void literal(ByteArrayOutputStream b, Protocol protocol) throws IOException, ProtocolException {
|
||||
b.writeTo(startLiteral(protocol, b.size()));
|
||||
}
|
||||
|
||||
private void literal(Literal b, Protocol protocol) throws IOException, ProtocolException {
|
||||
b.writeTo(startLiteral(protocol, b.size()));
|
||||
}
|
||||
|
||||
private OutputStream startLiteral(Protocol protocol, int size) throws IOException, ProtocolException {
|
||||
DataOutputStream os = (DataOutputStream)protocol.getOutputStream();
|
||||
boolean nonSync = protocol.supportsNonSyncLiterals();
|
||||
os.write(123);
|
||||
os.writeBytes(Integer.toString(size));
|
||||
if (nonSync) {
|
||||
os.writeBytes("+}\r\n");
|
||||
} else {
|
||||
os.writeBytes("}\r\n");
|
||||
}
|
||||
os.flush();
|
||||
if (!nonSync)
|
||||
while (true) {
|
||||
Response r = protocol.readResponse();
|
||||
if (r.isContinuation())
|
||||
break;
|
||||
if (r.isTagged())
|
||||
throw new LiteralException(r);
|
||||
}
|
||||
return os;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.sun.mail.iap;
|
||||
|
||||
class Atom {
|
||||
String string;
|
||||
|
||||
Atom(String s) {
|
||||
this.string = s;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.sun.mail.iap;
|
||||
|
||||
public class BadCommandException extends ProtocolException {
|
||||
private static final long serialVersionUID = 5769722539397237515L;
|
||||
|
||||
public BadCommandException() {}
|
||||
|
||||
public BadCommandException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
public BadCommandException(Response r) {
|
||||
super(r);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
package com.sun.mail.iap;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
public class ByteArray {
|
||||
private byte[] bytes;
|
||||
|
||||
private int start;
|
||||
|
||||
private int count;
|
||||
|
||||
public ByteArray(byte[] b, int start, int count) {
|
||||
this.bytes = b;
|
||||
this.start = start;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public ByteArray(int size) {
|
||||
this(new byte[size], 0, size);
|
||||
}
|
||||
|
||||
public byte[] getBytes() {
|
||||
return this.bytes;
|
||||
}
|
||||
|
||||
public byte[] getNewBytes() {
|
||||
byte[] b = new byte[this.count];
|
||||
System.arraycopy(this.bytes, this.start, b, 0, this.count);
|
||||
return b;
|
||||
}
|
||||
|
||||
public int getStart() {
|
||||
return this.start;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return this.count;
|
||||
}
|
||||
|
||||
public void setCount(int count) {
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public ByteArrayInputStream toByteArrayInputStream() {
|
||||
return new ByteArrayInputStream(this.bytes, this.start, this.count);
|
||||
}
|
||||
|
||||
public void grow(int incr) {
|
||||
byte[] nbuf = new byte[this.bytes.length + incr];
|
||||
System.arraycopy(this.bytes, 0, nbuf, 0, this.bytes.length);
|
||||
this.bytes = nbuf;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.sun.mail.iap;
|
||||
|
||||
public class CommandFailedException extends ProtocolException {
|
||||
private static final long serialVersionUID = 793932807880443631L;
|
||||
|
||||
public CommandFailedException() {}
|
||||
|
||||
public CommandFailedException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
public CommandFailedException(Response r) {
|
||||
super(r);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.sun.mail.iap;
|
||||
|
||||
public class ConnectionException extends ProtocolException {
|
||||
private transient Protocol p;
|
||||
|
||||
private static final long serialVersionUID = 5749739604257464727L;
|
||||
|
||||
public ConnectionException() {}
|
||||
|
||||
public ConnectionException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
public ConnectionException(Protocol p, Response r) {
|
||||
super(r);
|
||||
this.p = p;
|
||||
}
|
||||
|
||||
public Protocol getProtocol() {
|
||||
return this.p;
|
||||
}
|
||||
}
|
||||
10
rus/WEB-INF/lib/javax.mail_src/com/sun/mail/iap/Literal.java
Normal file
10
rus/WEB-INF/lib/javax.mail_src/com/sun/mail/iap/Literal.java
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
package com.sun.mail.iap;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public interface Literal {
|
||||
int size();
|
||||
|
||||
void writeTo(OutputStream paramOutputStream) throws IOException;
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.sun.mail.iap;
|
||||
|
||||
public class LiteralException extends ProtocolException {
|
||||
private static final long serialVersionUID = -6919179828339609913L;
|
||||
|
||||
public LiteralException(Response r) {
|
||||
super(r.toString());
|
||||
this.response = r;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.sun.mail.iap;
|
||||
|
||||
class NString {
|
||||
byte[] bytes;
|
||||
|
||||
NString(byte[] b) {
|
||||
this.bytes = b;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.sun.mail.iap;
|
||||
|
||||
public class ParsingException extends ProtocolException {
|
||||
private static final long serialVersionUID = 7756119840142724839L;
|
||||
|
||||
public ParsingException() {}
|
||||
|
||||
public ParsingException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
public ParsingException(Response r) {
|
||||
super(r);
|
||||
}
|
||||
}
|
||||
315
rus/WEB-INF/lib/javax.mail_src/com/sun/mail/iap/Protocol.java
Normal file
315
rus/WEB-INF/lib/javax.mail_src/com/sun/mail/iap/Protocol.java
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
package com.sun.mail.iap;
|
||||
|
||||
import com.sun.mail.util.MailLogger;
|
||||
import com.sun.mail.util.PropUtil;
|
||||
import com.sun.mail.util.SocketFetcher;
|
||||
import com.sun.mail.util.TraceInputStream;
|
||||
import com.sun.mail.util.TraceOutputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.Properties;
|
||||
import java.util.Vector;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class Protocol {
|
||||
protected String host;
|
||||
|
||||
private Socket socket;
|
||||
|
||||
protected boolean quote;
|
||||
|
||||
protected MailLogger logger;
|
||||
|
||||
protected MailLogger traceLogger;
|
||||
|
||||
protected Properties props;
|
||||
|
||||
protected String prefix;
|
||||
|
||||
private TraceInputStream traceInput;
|
||||
|
||||
private volatile ResponseInputStream input;
|
||||
|
||||
private TraceOutputStream traceOutput;
|
||||
|
||||
private volatile DataOutputStream output;
|
||||
|
||||
private int tagCounter = 0;
|
||||
|
||||
private String localHostName;
|
||||
|
||||
private final Vector handlers = new Vector();
|
||||
|
||||
private volatile long timestamp;
|
||||
|
||||
private static final byte[] CRLF = new byte[] { 13, 10 };
|
||||
|
||||
public Protocol(String host, int port, Properties props, String prefix, boolean isSSL, MailLogger logger) throws IOException, ProtocolException {
|
||||
boolean connected = false;
|
||||
try {
|
||||
this.host = host;
|
||||
this.props = props;
|
||||
this.prefix = prefix;
|
||||
this.logger = logger;
|
||||
this.traceLogger = logger.getSubLogger("protocol", null);
|
||||
this.socket = SocketFetcher.getSocket(host, port, props, prefix, isSSL);
|
||||
this.quote = PropUtil.getBooleanProperty(props, "mail.debug.quote", false);
|
||||
initStreams();
|
||||
processGreeting(readResponse());
|
||||
this.timestamp = System.currentTimeMillis();
|
||||
connected = true;
|
||||
} finally {
|
||||
if (!connected)
|
||||
disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
private void initStreams() throws IOException {
|
||||
this.traceInput = new TraceInputStream(this.socket.getInputStream(), this.traceLogger);
|
||||
this.traceInput.setQuote(this.quote);
|
||||
this.input = new ResponseInputStream(this.traceInput);
|
||||
this
|
||||
.traceOutput = new TraceOutputStream(this.socket.getOutputStream(), this.traceLogger);
|
||||
this.traceOutput.setQuote(this.quote);
|
||||
this.output = new DataOutputStream(new BufferedOutputStream(this.traceOutput));
|
||||
}
|
||||
|
||||
public Protocol(InputStream in, PrintStream out, Properties props, boolean debug) throws IOException {
|
||||
this.host = "localhost";
|
||||
this.props = props;
|
||||
this.quote = false;
|
||||
this.logger = new MailLogger(getClass(), "DEBUG", debug, System.out);
|
||||
this.traceLogger = this.logger.getSubLogger("protocol", null);
|
||||
this.traceInput = new TraceInputStream(in, this.traceLogger);
|
||||
this.traceInput.setQuote(this.quote);
|
||||
this.input = new ResponseInputStream(this.traceInput);
|
||||
this.traceOutput = new TraceOutputStream(out, this.traceLogger);
|
||||
this.traceOutput.setQuote(this.quote);
|
||||
this.output = new DataOutputStream(new BufferedOutputStream(this.traceOutput));
|
||||
this.timestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return this.timestamp;
|
||||
}
|
||||
|
||||
public void addResponseHandler(ResponseHandler h) {
|
||||
this.handlers.addElement(h);
|
||||
}
|
||||
|
||||
public void removeResponseHandler(ResponseHandler h) {
|
||||
this.handlers.removeElement(h);
|
||||
}
|
||||
|
||||
public void notifyResponseHandlers(Response[] responses) {
|
||||
if (this.handlers.size() == 0)
|
||||
return;
|
||||
for (int i = 0; i < responses.length; i++) {
|
||||
Response r = responses[i];
|
||||
if (r != null) {
|
||||
Object[] h = this.handlers.toArray();
|
||||
for (int j = 0; j < h.length; j++) {
|
||||
if (h[j] != null)
|
||||
((ResponseHandler)h[j]).handleResponse(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void processGreeting(Response r) throws ProtocolException {
|
||||
if (r.isBYE())
|
||||
throw new ConnectionException(this, r);
|
||||
}
|
||||
|
||||
protected ResponseInputStream getInputStream() {
|
||||
return this.input;
|
||||
}
|
||||
|
||||
protected OutputStream getOutputStream() {
|
||||
return this.output;
|
||||
}
|
||||
|
||||
protected synchronized boolean supportsNonSyncLiterals() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Response readResponse() throws IOException, ProtocolException {
|
||||
return new Response(this);
|
||||
}
|
||||
|
||||
public boolean hasResponse() {
|
||||
try {
|
||||
return (this.input.available() > 0);
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected ByteArray getResponseBuffer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String writeCommand(String command, Argument args) throws IOException, ProtocolException {
|
||||
String tag = "A" + Integer.toString(this.tagCounter++, 10);
|
||||
this.output.writeBytes(tag + " " + command);
|
||||
if (args != null) {
|
||||
this.output.write(32);
|
||||
args.write(this);
|
||||
}
|
||||
this.output.write(CRLF);
|
||||
this.output.flush();
|
||||
return tag;
|
||||
}
|
||||
|
||||
public synchronized Response[] command(String command, Argument args) {
|
||||
commandStart(command);
|
||||
Vector<Response> v = new Vector();
|
||||
boolean done = false;
|
||||
String tag = null;
|
||||
Response r = null;
|
||||
try {
|
||||
tag = writeCommand(command, args);
|
||||
} catch (LiteralException lex) {
|
||||
v.addElement(lex.getResponse());
|
||||
done = true;
|
||||
} catch (Exception ex) {
|
||||
v.addElement(Response.byeResponse(ex));
|
||||
done = true;
|
||||
}
|
||||
Response byeResp = null;
|
||||
while (!done) {
|
||||
try {
|
||||
r = readResponse();
|
||||
} catch (IOException ioex) {
|
||||
if (byeResp != null)
|
||||
break;
|
||||
r = Response.byeResponse(ioex);
|
||||
} catch (ProtocolException pex) {
|
||||
this.logger.log(Level.FINE, "ignoring bad response", (Throwable)pex);
|
||||
continue;
|
||||
}
|
||||
if (r.isBYE()) {
|
||||
byeResp = r;
|
||||
continue;
|
||||
}
|
||||
v.addElement(r);
|
||||
if (r.isTagged() && r.getTag().equals(tag))
|
||||
done = true;
|
||||
}
|
||||
if (byeResp != null)
|
||||
v.addElement(byeResp);
|
||||
Response[] responses = new Response[v.size()];
|
||||
v.copyInto(responses);
|
||||
this.timestamp = System.currentTimeMillis();
|
||||
commandEnd();
|
||||
return responses;
|
||||
}
|
||||
|
||||
public void handleResult(Response response) throws ProtocolException {
|
||||
if (response.isOK())
|
||||
return;
|
||||
if (response.isNO())
|
||||
throw new CommandFailedException(response);
|
||||
if (response.isBAD())
|
||||
throw new BadCommandException(response);
|
||||
if (response.isBYE()) {
|
||||
disconnect();
|
||||
throw new ConnectionException(this, response);
|
||||
}
|
||||
}
|
||||
|
||||
public void simpleCommand(String cmd, Argument args) throws ProtocolException {
|
||||
Response[] r = command(cmd, args);
|
||||
notifyResponseHandlers(r);
|
||||
handleResult(r[r.length - 1]);
|
||||
}
|
||||
|
||||
public synchronized void startTLS(String cmd) throws IOException, ProtocolException {
|
||||
if (this.socket instanceof javax.net.ssl.SSLSocket)
|
||||
return;
|
||||
simpleCommand(cmd, null);
|
||||
this.socket = SocketFetcher.startTLS(this.socket, this.host, this.props, this.prefix);
|
||||
initStreams();
|
||||
}
|
||||
|
||||
public boolean isSSL() {
|
||||
return this.socket instanceof javax.net.ssl.SSLSocket;
|
||||
}
|
||||
|
||||
public InetAddress getInetAddress() {
|
||||
return this.socket.getInetAddress();
|
||||
}
|
||||
|
||||
public SocketChannel getChannel() {
|
||||
return this.socket.getChannel();
|
||||
}
|
||||
|
||||
protected synchronized void disconnect() {
|
||||
if (this.socket != null) {
|
||||
try {
|
||||
this.socket.close();
|
||||
} catch (IOException e) {}
|
||||
this.socket = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected synchronized String getLocalHost() {
|
||||
if (this.localHostName == null || this.localHostName.length() <= 0)
|
||||
this
|
||||
.localHostName = this.props.getProperty(this.prefix + ".localhost");
|
||||
if (this.localHostName == null || this.localHostName.length() <= 0)
|
||||
this
|
||||
.localHostName = this.props.getProperty(this.prefix + ".localaddress");
|
||||
try {
|
||||
if (this.localHostName == null || this.localHostName.length() <= 0) {
|
||||
InetAddress localHost = InetAddress.getLocalHost();
|
||||
this.localHostName = localHost.getCanonicalHostName();
|
||||
if (this.localHostName == null)
|
||||
this.localHostName = "[" + localHost.getHostAddress() + "]";
|
||||
}
|
||||
} catch (UnknownHostException e) {}
|
||||
if ((this.localHostName == null || this.localHostName.length() <= 0) &&
|
||||
this.socket != null && this.socket.isBound()) {
|
||||
InetAddress localHost = this.socket.getLocalAddress();
|
||||
this.localHostName = localHost.getCanonicalHostName();
|
||||
if (this.localHostName == null)
|
||||
this.localHostName = "[" + localHost.getHostAddress() + "]";
|
||||
}
|
||||
return this.localHostName;
|
||||
}
|
||||
|
||||
protected boolean isTracing() {
|
||||
return this.traceLogger.isLoggable(Level.FINEST);
|
||||
}
|
||||
|
||||
protected void suspendTracing() {
|
||||
if (this.traceLogger.isLoggable(Level.FINEST)) {
|
||||
this.traceInput.setTrace(false);
|
||||
this.traceOutput.setTrace(false);
|
||||
}
|
||||
}
|
||||
|
||||
protected void resumeTracing() {
|
||||
if (this.traceLogger.isLoggable(Level.FINEST)) {
|
||||
this.traceInput.setTrace(true);
|
||||
this.traceOutput.setTrace(true);
|
||||
}
|
||||
}
|
||||
|
||||
protected void finalize() throws Throwable {
|
||||
super.finalize();
|
||||
disconnect();
|
||||
}
|
||||
|
||||
private void commandStart(String command) {}
|
||||
|
||||
private void commandEnd() {}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package com.sun.mail.iap;
|
||||
|
||||
public class ProtocolException extends Exception {
|
||||
protected transient Response response = null;
|
||||
|
||||
private static final long serialVersionUID = -4360500807971797439L;
|
||||
|
||||
public ProtocolException() {}
|
||||
|
||||
public ProtocolException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ProtocolException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public ProtocolException(Response r) {
|
||||
super(r.toString());
|
||||
this.response = r;
|
||||
}
|
||||
|
||||
public Response getResponse() {
|
||||
return this.response;
|
||||
}
|
||||
}
|
||||
348
rus/WEB-INF/lib/javax.mail_src/com/sun/mail/iap/Response.java
Normal file
348
rus/WEB-INF/lib/javax.mail_src/com/sun/mail/iap/Response.java
Normal file
|
|
@ -0,0 +1,348 @@
|
|||
package com.sun.mail.iap;
|
||||
|
||||
import com.sun.mail.util.ASCIIUtility;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Vector;
|
||||
|
||||
public class Response {
|
||||
protected int index;
|
||||
|
||||
protected int pindex;
|
||||
|
||||
protected int size;
|
||||
|
||||
protected byte[] buffer = null;
|
||||
|
||||
protected int type = 0;
|
||||
|
||||
protected String tag = null;
|
||||
|
||||
protected Exception ex;
|
||||
|
||||
private static final int increment = 100;
|
||||
|
||||
public static final int TAG_MASK = 3;
|
||||
|
||||
public static final int CONTINUATION = 1;
|
||||
|
||||
public static final int TAGGED = 2;
|
||||
|
||||
public static final int UNTAGGED = 3;
|
||||
|
||||
public static final int TYPE_MASK = 28;
|
||||
|
||||
public static final int OK = 4;
|
||||
|
||||
public static final int NO = 8;
|
||||
|
||||
public static final int BAD = 12;
|
||||
|
||||
public static final int BYE = 16;
|
||||
|
||||
public static final int SYNTHETIC = 32;
|
||||
|
||||
private static String ATOM_CHAR_DELIM = " (){%*\"\\]";
|
||||
|
||||
private static String ASTRING_CHAR_DELIM = " (){%*\"\\";
|
||||
|
||||
public Response(String s) {
|
||||
this.buffer = ASCIIUtility.getBytes(s);
|
||||
this.size = this.buffer.length;
|
||||
parse();
|
||||
}
|
||||
|
||||
public Response(Protocol p) throws IOException, ProtocolException {
|
||||
ByteArray ba = p.getResponseBuffer();
|
||||
ByteArray response = p.getInputStream().readResponse(ba);
|
||||
this.buffer = response.getBytes();
|
||||
this.size = response.getCount() - 2;
|
||||
parse();
|
||||
}
|
||||
|
||||
public Response(Response r) {
|
||||
this.index = r.index;
|
||||
this.size = r.size;
|
||||
this.buffer = r.buffer;
|
||||
this.type = r.type;
|
||||
this.tag = r.tag;
|
||||
}
|
||||
|
||||
public static Response byeResponse(Exception ex) {
|
||||
String err = "* BYE JavaMail Exception: " + ex.toString();
|
||||
err = err.replace('\r', ' ').replace('\n', ' ');
|
||||
Response r = new Response(err);
|
||||
r.type |= 0x20;
|
||||
r.ex = ex;
|
||||
return r;
|
||||
}
|
||||
|
||||
private void parse() {
|
||||
this.index = 0;
|
||||
if (this.size == 0)
|
||||
return;
|
||||
if (this.buffer[this.index] == 43) {
|
||||
this.type |= 0x1;
|
||||
this.index++;
|
||||
return;
|
||||
}
|
||||
if (this.buffer[this.index] == 42) {
|
||||
this.type |= 0x3;
|
||||
this.index++;
|
||||
} else {
|
||||
this.type |= 0x2;
|
||||
this.tag = readAtom();
|
||||
if (this.tag == null)
|
||||
this.tag = "";
|
||||
}
|
||||
int mark = this.index;
|
||||
String s = readAtom();
|
||||
if (s == null)
|
||||
s = "";
|
||||
if (s.equalsIgnoreCase("OK")) {
|
||||
this.type |= 0x4;
|
||||
} else if (s.equalsIgnoreCase("NO")) {
|
||||
this.type |= 0x8;
|
||||
} else if (s.equalsIgnoreCase("BAD")) {
|
||||
this.type |= 0xC;
|
||||
} else if (s.equalsIgnoreCase("BYE")) {
|
||||
this.type |= 0x10;
|
||||
} else {
|
||||
this.index = mark;
|
||||
}
|
||||
this.pindex = this.index;
|
||||
}
|
||||
|
||||
public void skipSpaces() {
|
||||
while (this.index < this.size && this.buffer[this.index] == 32)
|
||||
this.index++;
|
||||
}
|
||||
|
||||
public void skipToken() {
|
||||
while (this.index < this.size && this.buffer[this.index] != 32)
|
||||
this.index++;
|
||||
}
|
||||
|
||||
public void skip(int count) {
|
||||
this.index += count;
|
||||
}
|
||||
|
||||
public byte peekByte() {
|
||||
if (this.index < this.size)
|
||||
return this.buffer[this.index];
|
||||
return 0;
|
||||
}
|
||||
|
||||
public byte readByte() {
|
||||
if (this.index < this.size)
|
||||
return this.buffer[this.index++];
|
||||
return 0;
|
||||
}
|
||||
|
||||
public String readAtom() {
|
||||
return readDelimString(ATOM_CHAR_DELIM);
|
||||
}
|
||||
|
||||
private String readDelimString(String delim) {
|
||||
skipSpaces();
|
||||
if (this.index >= this.size)
|
||||
return null;
|
||||
int start = this.index;
|
||||
byte b;
|
||||
while (this.index < this.size && (b = this.buffer[this.index]) > 32 &&
|
||||
delim.indexOf((char)b) < 0 && b >= 32 && b != Byte.MAX_VALUE)
|
||||
this.index++;
|
||||
return ASCIIUtility.toString(this.buffer, start, this.index);
|
||||
}
|
||||
|
||||
public String readString(char delim) {
|
||||
skipSpaces();
|
||||
if (this.index >= this.size)
|
||||
return null;
|
||||
int start = this.index;
|
||||
while (this.index < this.size && this.buffer[this.index] != delim)
|
||||
this.index++;
|
||||
return ASCIIUtility.toString(this.buffer, start, this.index);
|
||||
}
|
||||
|
||||
public String[] readStringList() {
|
||||
return readStringList(false);
|
||||
}
|
||||
|
||||
public String[] readAtomStringList() {
|
||||
return readStringList(true);
|
||||
}
|
||||
|
||||
private String[] readStringList(boolean atom) {
|
||||
skipSpaces();
|
||||
if (this.buffer[this.index] != 40)
|
||||
return null;
|
||||
this.index++;
|
||||
Vector<String> v = new Vector();
|
||||
do {
|
||||
v.addElement(atom ? readAtomString() : readString());
|
||||
} while (this.buffer[this.index++] != 41);
|
||||
int size = v.size();
|
||||
if (size > 0) {
|
||||
String[] s = new String[size];
|
||||
v.copyInto(s);
|
||||
return s;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int readNumber() {
|
||||
skipSpaces();
|
||||
int start = this.index;
|
||||
while (this.index < this.size && Character.isDigit((char)this.buffer[this.index]))
|
||||
this.index++;
|
||||
if (this.index > start)
|
||||
try {
|
||||
return ASCIIUtility.parseInt(this.buffer, start, this.index);
|
||||
} catch (NumberFormatException e) {}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public long readLong() {
|
||||
skipSpaces();
|
||||
int start = this.index;
|
||||
while (this.index < this.size && Character.isDigit((char)this.buffer[this.index]))
|
||||
this.index++;
|
||||
if (this.index > start)
|
||||
try {
|
||||
return ASCIIUtility.parseLong(this.buffer, start, this.index);
|
||||
} catch (NumberFormatException e) {}
|
||||
return -1L;
|
||||
}
|
||||
|
||||
public String readString() {
|
||||
return (String)parseString(false, true);
|
||||
}
|
||||
|
||||
public ByteArrayInputStream readBytes() {
|
||||
ByteArray ba = readByteArray();
|
||||
if (ba != null)
|
||||
return ba.toByteArrayInputStream();
|
||||
return null;
|
||||
}
|
||||
|
||||
public ByteArray readByteArray() {
|
||||
if (isContinuation()) {
|
||||
skipSpaces();
|
||||
return new ByteArray(this.buffer, this.index, this.size - this.index);
|
||||
}
|
||||
return (ByteArray)parseString(false, false);
|
||||
}
|
||||
|
||||
public String readAtomString() {
|
||||
return (String)parseString(true, true);
|
||||
}
|
||||
|
||||
private Object parseString(boolean parseAtoms, boolean returnString) {
|
||||
skipSpaces();
|
||||
byte b = this.buffer[this.index];
|
||||
if (b == 34) {
|
||||
int start = ++this.index;
|
||||
int copyto = this.index;
|
||||
while (this.index < this.size && (b = this.buffer[this.index]) != 34) {
|
||||
if (b == 92)
|
||||
this.index++;
|
||||
if (this.index != copyto)
|
||||
this.buffer[copyto] = this.buffer[this.index];
|
||||
copyto++;
|
||||
this.index++;
|
||||
}
|
||||
if (this.index >= this.size)
|
||||
return null;
|
||||
this.index++;
|
||||
if (returnString)
|
||||
return ASCIIUtility.toString(this.buffer, start, copyto);
|
||||
return new ByteArray(this.buffer, start, copyto - start);
|
||||
}
|
||||
if (b == 123) {
|
||||
int start = ++this.index;
|
||||
while (this.buffer[this.index] != 125)
|
||||
this.index++;
|
||||
int count = 0;
|
||||
try {
|
||||
count = ASCIIUtility.parseInt(this.buffer, start, this.index);
|
||||
} catch (NumberFormatException nex) {
|
||||
return null;
|
||||
}
|
||||
start = this.index + 3;
|
||||
this.index = start + count;
|
||||
if (returnString)
|
||||
return ASCIIUtility.toString(this.buffer, start, start + count);
|
||||
return new ByteArray(this.buffer, start, count);
|
||||
}
|
||||
if (parseAtoms) {
|
||||
int start = this.index;
|
||||
String s = readDelimString(ASTRING_CHAR_DELIM);
|
||||
if (returnString)
|
||||
return s;
|
||||
return new ByteArray(this.buffer, start, this.index);
|
||||
}
|
||||
if (b == 78 || b == 110) {
|
||||
this.index += 3;
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public boolean isContinuation() {
|
||||
return ((this.type & 0x3) == 1);
|
||||
}
|
||||
|
||||
public boolean isTagged() {
|
||||
return ((this.type & 0x3) == 2);
|
||||
}
|
||||
|
||||
public boolean isUnTagged() {
|
||||
return ((this.type & 0x3) == 3);
|
||||
}
|
||||
|
||||
public boolean isOK() {
|
||||
return ((this.type & 0x1C) == 4);
|
||||
}
|
||||
|
||||
public boolean isNO() {
|
||||
return ((this.type & 0x1C) == 8);
|
||||
}
|
||||
|
||||
public boolean isBAD() {
|
||||
return ((this.type & 0x1C) == 12);
|
||||
}
|
||||
|
||||
public boolean isBYE() {
|
||||
return ((this.type & 0x1C) == 16);
|
||||
}
|
||||
|
||||
public boolean isSynthetic() {
|
||||
return ((this.type & 0x20) == 32);
|
||||
}
|
||||
|
||||
public String getTag() {
|
||||
return this.tag;
|
||||
}
|
||||
|
||||
public String getRest() {
|
||||
skipSpaces();
|
||||
return ASCIIUtility.toString(this.buffer, this.index, this.size);
|
||||
}
|
||||
|
||||
public Exception getException() {
|
||||
return this.ex;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
this.index = this.pindex;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return ASCIIUtility.toString(this.buffer, 0, this.size);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package com.sun.mail.iap;
|
||||
|
||||
public interface ResponseHandler {
|
||||
void handleResponse(Response paramResponse);
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
package com.sun.mail.iap;
|
||||
|
||||
import com.sun.mail.util.ASCIIUtility;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class ResponseInputStream {
|
||||
private static final int minIncrement = 256;
|
||||
|
||||
private static final int maxIncrement = 262144;
|
||||
|
||||
private static final int incrementSlop = 16;
|
||||
|
||||
private BufferedInputStream bin;
|
||||
|
||||
public ResponseInputStream(InputStream in) {
|
||||
this.bin = new BufferedInputStream(in, 2048);
|
||||
}
|
||||
|
||||
public ByteArray readResponse() throws IOException {
|
||||
return readResponse(null);
|
||||
}
|
||||
|
||||
public ByteArray readResponse(ByteArray ba) throws IOException {
|
||||
if (ba == null)
|
||||
ba = new ByteArray(new byte[128], 0, 128);
|
||||
byte[] buffer = ba.getBytes();
|
||||
int idx = 0;
|
||||
while (true) {
|
||||
int b = 0;
|
||||
boolean gotCRLF = false;
|
||||
while (!gotCRLF && (
|
||||
b = this.bin.read()) != -1) {
|
||||
if (b == 10 &&
|
||||
idx > 0 && buffer[idx - 1] == 13)
|
||||
gotCRLF = true;
|
||||
if (idx >= buffer.length) {
|
||||
int incr = buffer.length;
|
||||
if (incr > 262144)
|
||||
incr = 262144;
|
||||
ba.grow(incr);
|
||||
buffer = ba.getBytes();
|
||||
}
|
||||
buffer[idx++] = (byte)b;
|
||||
}
|
||||
if (b == -1)
|
||||
throw new IOException("Connection dropped by server?");
|
||||
if (idx < 5 || buffer[idx - 3] != 125)
|
||||
break;
|
||||
int i;
|
||||
for (i = idx - 4; i >= 0 &&
|
||||
buffer[i] != 123; i--);
|
||||
if (i < 0)
|
||||
break;
|
||||
int count = 0;
|
||||
try {
|
||||
count = ASCIIUtility.parseInt(buffer, i + 1, idx - 3);
|
||||
} catch (NumberFormatException e) {
|
||||
break;
|
||||
}
|
||||
if (count > 0) {
|
||||
int avail = buffer.length - idx;
|
||||
if (count + 16 > avail) {
|
||||
ba.grow((256 > count + 16 - avail) ? 256 : (count + 16 - avail));
|
||||
buffer = ba.getBytes();
|
||||
}
|
||||
while (count > 0) {
|
||||
int actual = this.bin.read(buffer, idx, count);
|
||||
count -= actual;
|
||||
idx += actual;
|
||||
}
|
||||
}
|
||||
}
|
||||
ba.setCount(idx);
|
||||
return ba;
|
||||
}
|
||||
|
||||
public int available() throws IOException {
|
||||
return this.bin.available();
|
||||
}
|
||||
}
|
||||
35
rus/WEB-INF/lib/javax.mail_src/com/sun/mail/imap/ACL.java
Normal file
35
rus/WEB-INF/lib/javax.mail_src/com/sun/mail/imap/ACL.java
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
package com.sun.mail.imap;
|
||||
|
||||
public class ACL implements Cloneable {
|
||||
private String name;
|
||||
|
||||
private Rights rights;
|
||||
|
||||
public ACL(String name) {
|
||||
this.name = name;
|
||||
this.rights = new Rights();
|
||||
}
|
||||
|
||||
public ACL(String name, Rights rights) {
|
||||
this.name = name;
|
||||
this.rights = rights;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setRights(Rights rights) {
|
||||
this.rights = rights;
|
||||
}
|
||||
|
||||
public Rights getRights() {
|
||||
return this.rights;
|
||||
}
|
||||
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
ACL acl = (ACL)super.clone();
|
||||
acl.rights = (Rights)this.rights.clone();
|
||||
return acl;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.sun.mail.imap;
|
||||
|
||||
public class AppendUID {
|
||||
public long uidvalidity = -1L;
|
||||
|
||||
public long uid = -1L;
|
||||
|
||||
public AppendUID(long uidvalidity, long uid) {
|
||||
this.uidvalidity = uidvalidity;
|
||||
this.uid = uid;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package com.sun.mail.imap;
|
||||
|
||||
import com.sun.mail.imap.protocol.UIDSet;
|
||||
|
||||
public class CopyUID {
|
||||
public long uidvalidity = -1L;
|
||||
|
||||
public UIDSet[] src;
|
||||
|
||||
public UIDSet[] dst;
|
||||
|
||||
public CopyUID(long uidvalidity, UIDSet[] src, UIDSet[] dst) {
|
||||
this.uidvalidity = uidvalidity;
|
||||
this.src = src;
|
||||
this.dst = dst;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
package com.sun.mail.imap;
|
||||
|
||||
import com.sun.mail.iap.ProtocolException;
|
||||
import com.sun.mail.imap.protocol.IMAPProtocol;
|
||||
import com.sun.mail.imap.protocol.ListInfo;
|
||||
import javax.mail.Folder;
|
||||
import javax.mail.Message;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.MethodNotSupportedException;
|
||||
|
||||
public class DefaultFolder extends IMAPFolder {
|
||||
protected DefaultFolder(IMAPStore store) {
|
||||
super("", Character.MAX_VALUE, store, null);
|
||||
this.exists = true;
|
||||
this.type = 2;
|
||||
}
|
||||
|
||||
public synchronized String getName() {
|
||||
return this.fullName;
|
||||
}
|
||||
|
||||
public Folder getParent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public synchronized Folder[] list(final String pattern) throws MessagingException {
|
||||
ListInfo[] li = null;
|
||||
li = (ListInfo[])doCommand(new IMAPFolder.ProtocolCommand() {
|
||||
public Object doCommand(IMAPProtocol p) throws ProtocolException {
|
||||
return p.list("", pattern);
|
||||
}
|
||||
});
|
||||
if (li == null)
|
||||
return new Folder[0];
|
||||
IMAPFolder[] folders = new IMAPFolder[li.length];
|
||||
for (int i = 0; i < folders.length; i++)
|
||||
folders[i] = ((IMAPStore)this.store).newIMAPFolder(li[i]);
|
||||
return folders;
|
||||
}
|
||||
|
||||
public synchronized Folder[] listSubscribed(final String pattern) throws MessagingException {
|
||||
ListInfo[] li = null;
|
||||
li = (ListInfo[])doCommand(new IMAPFolder.ProtocolCommand() {
|
||||
public Object doCommand(IMAPProtocol p) throws ProtocolException {
|
||||
return p.lsub("", pattern);
|
||||
}
|
||||
});
|
||||
if (li == null)
|
||||
return new Folder[0];
|
||||
IMAPFolder[] folders = new IMAPFolder[li.length];
|
||||
for (int i = 0; i < folders.length; i++)
|
||||
folders[i] = ((IMAPStore)this.store).newIMAPFolder(li[i]);
|
||||
return folders;
|
||||
}
|
||||
|
||||
public boolean hasNewMessages() throws MessagingException {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Folder getFolder(String name) throws MessagingException {
|
||||
return ((IMAPStore)this.store).newIMAPFolder(name, Character.MAX_VALUE);
|
||||
}
|
||||
|
||||
public boolean delete(boolean recurse) throws MessagingException {
|
||||
throw new MethodNotSupportedException("Cannot delete Default Folder");
|
||||
}
|
||||
|
||||
public boolean renameTo(Folder f) throws MessagingException {
|
||||
throw new MethodNotSupportedException("Cannot rename Default Folder");
|
||||
}
|
||||
|
||||
public void appendMessages(Message[] msgs) throws MessagingException {
|
||||
throw new MethodNotSupportedException("Cannot append to Default Folder");
|
||||
}
|
||||
|
||||
public Message[] expunge() throws MessagingException {
|
||||
throw new MethodNotSupportedException("Cannot expunge Default Folder");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,304 @@
|
|||
package com.sun.mail.imap;
|
||||
|
||||
import com.sun.mail.iap.ConnectionException;
|
||||
import com.sun.mail.iap.ProtocolException;
|
||||
import com.sun.mail.imap.protocol.BODY;
|
||||
import com.sun.mail.imap.protocol.BODYSTRUCTURE;
|
||||
import com.sun.mail.imap.protocol.IMAPProtocol;
|
||||
import com.sun.mail.util.LineOutputStream;
|
||||
import com.sun.mail.util.PropUtil;
|
||||
import com.sun.mail.util.ReadableMime;
|
||||
import com.sun.mail.util.SharedByteArrayOutputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.SequenceInputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Enumeration;
|
||||
import javax.activation.DataHandler;
|
||||
import javax.mail.FolderClosedException;
|
||||
import javax.mail.IllegalWriteException;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.Multipart;
|
||||
import javax.mail.internet.ContentType;
|
||||
import javax.mail.internet.InternetHeaders;
|
||||
import javax.mail.internet.MimeBodyPart;
|
||||
import javax.mail.internet.MimeUtility;
|
||||
|
||||
public class IMAPBodyPart extends MimeBodyPart implements ReadableMime {
|
||||
private IMAPMessage message;
|
||||
|
||||
private BODYSTRUCTURE bs;
|
||||
|
||||
private String sectionId;
|
||||
|
||||
private String type;
|
||||
|
||||
private String description;
|
||||
|
||||
private boolean headersLoaded = false;
|
||||
|
||||
private static final boolean decodeFileName = PropUtil.getBooleanSystemProperty("mail.mime.decodefilename", false);
|
||||
|
||||
protected IMAPBodyPart(BODYSTRUCTURE bs, String sid, IMAPMessage message) {
|
||||
this.bs = bs;
|
||||
this.sectionId = sid;
|
||||
this.message = message;
|
||||
ContentType ct = new ContentType(bs.type, bs.subtype, bs.cParams);
|
||||
this.type = ct.toString();
|
||||
}
|
||||
|
||||
protected void updateHeaders() {}
|
||||
|
||||
public int getSize() throws MessagingException {
|
||||
return this.bs.size;
|
||||
}
|
||||
|
||||
public int getLineCount() throws MessagingException {
|
||||
return this.bs.lines;
|
||||
}
|
||||
|
||||
public String getContentType() throws MessagingException {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public String getDisposition() throws MessagingException {
|
||||
return this.bs.disposition;
|
||||
}
|
||||
|
||||
public void setDisposition(String disposition) throws MessagingException {
|
||||
throw new IllegalWriteException("IMAPBodyPart is read-only");
|
||||
}
|
||||
|
||||
public String getEncoding() throws MessagingException {
|
||||
return this.bs.encoding;
|
||||
}
|
||||
|
||||
public String getContentID() throws MessagingException {
|
||||
return this.bs.id;
|
||||
}
|
||||
|
||||
public String getContentMD5() throws MessagingException {
|
||||
return this.bs.md5;
|
||||
}
|
||||
|
||||
public void setContentMD5(String md5) throws MessagingException {
|
||||
throw new IllegalWriteException("IMAPBodyPart is read-only");
|
||||
}
|
||||
|
||||
public String getDescription() throws MessagingException {
|
||||
if (this.description != null)
|
||||
return this.description;
|
||||
if (this.bs.description == null)
|
||||
return null;
|
||||
try {
|
||||
this.description = MimeUtility.decodeText(this.bs.description);
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
this.description = this.bs.description;
|
||||
}
|
||||
return this.description;
|
||||
}
|
||||
|
||||
public void setDescription(String description, String charset) throws MessagingException {
|
||||
throw new IllegalWriteException("IMAPBodyPart is read-only");
|
||||
}
|
||||
|
||||
public String getFileName() throws MessagingException {
|
||||
String filename = null;
|
||||
if (this.bs.dParams != null)
|
||||
filename = this.bs.dParams.get("filename");
|
||||
if (filename == null && this.bs.cParams != null)
|
||||
filename = this.bs.cParams.get("name");
|
||||
if (decodeFileName && filename != null)
|
||||
try {
|
||||
filename = MimeUtility.decodeText(filename);
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
throw new MessagingException("Can't decode filename", ex);
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
public void setFileName(String filename) throws MessagingException {
|
||||
throw new IllegalWriteException("IMAPBodyPart is read-only");
|
||||
}
|
||||
|
||||
protected InputStream getContentStream() throws MessagingException {
|
||||
InputStream is = null;
|
||||
boolean pk = this.message.getPeek();
|
||||
synchronized (this.message.getMessageCacheLock()) {
|
||||
try {
|
||||
BODY b;
|
||||
IMAPProtocol p = this.message.getProtocol();
|
||||
this.message.checkExpunged();
|
||||
if (p.isREV1() && this.message.getFetchBlockSize() != -1)
|
||||
return new IMAPInputStream(this.message, this.sectionId,
|
||||
this.message.ignoreBodyStructureSize() ? -1 : this.bs.size, pk);
|
||||
int seqnum = this.message.getSequenceNumber();
|
||||
if (pk) {
|
||||
b = p.peekBody(seqnum, this.sectionId);
|
||||
} else {
|
||||
b = p.fetchBody(seqnum, this.sectionId);
|
||||
}
|
||||
if (b != null)
|
||||
is = b.getByteArrayInputStream();
|
||||
} catch (ConnectionException cex) {
|
||||
throw new FolderClosedException(
|
||||
this.message.getFolder(), cex.getMessage());
|
||||
} catch (ProtocolException pex) {
|
||||
throw new MessagingException(pex.getMessage(), pex);
|
||||
}
|
||||
}
|
||||
if (is == null)
|
||||
throw new MessagingException("No content");
|
||||
return is;
|
||||
}
|
||||
|
||||
private InputStream getHeaderStream() throws MessagingException {
|
||||
if (!this.message.isREV1())
|
||||
loadHeaders();
|
||||
synchronized (this.message.getMessageCacheLock()) {
|
||||
IMAPProtocol p = this.message.getProtocol();
|
||||
this.message.checkExpunged();
|
||||
if (p.isREV1()) {
|
||||
int seqnum = this.message.getSequenceNumber();
|
||||
BODY b = p.peekBody(seqnum, this.sectionId + ".MIME");
|
||||
if (b == null)
|
||||
throw new MessagingException("Failed to fetch headers");
|
||||
ByteArrayInputStream bis = b.getByteArrayInputStream();
|
||||
if (bis == null)
|
||||
throw new MessagingException("Failed to fetch headers");
|
||||
return bis;
|
||||
}
|
||||
SharedByteArrayOutputStream bos = new SharedByteArrayOutputStream(0);
|
||||
LineOutputStream los = new LineOutputStream(bos);
|
||||
try {
|
||||
Enumeration<String> hdrLines = super.getAllHeaderLines();
|
||||
while (hdrLines.hasMoreElements())
|
||||
los.writeln(hdrLines.nextElement());
|
||||
los.writeln();
|
||||
} catch (IOException e) {
|
||||
|
||||
} finally {
|
||||
try {
|
||||
los.close();
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
return bos.toStream();
|
||||
}
|
||||
}
|
||||
|
||||
public InputStream getMimeStream() throws MessagingException {
|
||||
return new SequenceInputStream(getHeaderStream(), getContentStream());
|
||||
}
|
||||
|
||||
public synchronized DataHandler getDataHandler() throws MessagingException {
|
||||
if (this.dh == null)
|
||||
if (this.bs.isMulti()) {
|
||||
this.dh = new DataHandler(new IMAPMultipartDataSource(this, this.bs.bodies, this.sectionId, this.message));
|
||||
} else if (this.bs.isNested() && this.message.isREV1() && this.bs.envelope != null) {
|
||||
this.dh = new DataHandler(new IMAPNestedMessage(this.message, this.bs.bodies[0], this.bs.envelope, this.sectionId), this.type);
|
||||
}
|
||||
return super.getDataHandler();
|
||||
}
|
||||
|
||||
public void setDataHandler(DataHandler content) throws MessagingException {
|
||||
throw new IllegalWriteException("IMAPBodyPart is read-only");
|
||||
}
|
||||
|
||||
public void setContent(Object o, String type) throws MessagingException {
|
||||
throw new IllegalWriteException("IMAPBodyPart is read-only");
|
||||
}
|
||||
|
||||
public void setContent(Multipart mp) throws MessagingException {
|
||||
throw new IllegalWriteException("IMAPBodyPart is read-only");
|
||||
}
|
||||
|
||||
public String[] getHeader(String name) throws MessagingException {
|
||||
loadHeaders();
|
||||
return super.getHeader(name);
|
||||
}
|
||||
|
||||
public void setHeader(String name, String value) throws MessagingException {
|
||||
throw new IllegalWriteException("IMAPBodyPart is read-only");
|
||||
}
|
||||
|
||||
public void addHeader(String name, String value) throws MessagingException {
|
||||
throw new IllegalWriteException("IMAPBodyPart is read-only");
|
||||
}
|
||||
|
||||
public void removeHeader(String name) throws MessagingException {
|
||||
throw new IllegalWriteException("IMAPBodyPart is read-only");
|
||||
}
|
||||
|
||||
public Enumeration getAllHeaders() throws MessagingException {
|
||||
loadHeaders();
|
||||
return super.getAllHeaders();
|
||||
}
|
||||
|
||||
public Enumeration getMatchingHeaders(String[] names) throws MessagingException {
|
||||
loadHeaders();
|
||||
return super.getMatchingHeaders(names);
|
||||
}
|
||||
|
||||
public Enumeration getNonMatchingHeaders(String[] names) throws MessagingException {
|
||||
loadHeaders();
|
||||
return super.getNonMatchingHeaders(names);
|
||||
}
|
||||
|
||||
public void addHeaderLine(String line) throws MessagingException {
|
||||
throw new IllegalWriteException("IMAPBodyPart is read-only");
|
||||
}
|
||||
|
||||
public Enumeration getAllHeaderLines() throws MessagingException {
|
||||
loadHeaders();
|
||||
return super.getAllHeaderLines();
|
||||
}
|
||||
|
||||
public Enumeration getMatchingHeaderLines(String[] names) throws MessagingException {
|
||||
loadHeaders();
|
||||
return super.getMatchingHeaderLines(names);
|
||||
}
|
||||
|
||||
public Enumeration getNonMatchingHeaderLines(String[] names) throws MessagingException {
|
||||
loadHeaders();
|
||||
return super.getNonMatchingHeaderLines(names);
|
||||
}
|
||||
|
||||
private synchronized void loadHeaders() throws MessagingException {
|
||||
if (this.headersLoaded)
|
||||
return;
|
||||
if (this.headers == null)
|
||||
this.headers = new InternetHeaders();
|
||||
synchronized (this.message.getMessageCacheLock()) {
|
||||
try {
|
||||
IMAPProtocol p = this.message.getProtocol();
|
||||
this.message.checkExpunged();
|
||||
if (p.isREV1()) {
|
||||
int seqnum = this.message.getSequenceNumber();
|
||||
BODY b = p.peekBody(seqnum, this.sectionId + ".MIME");
|
||||
if (b == null)
|
||||
throw new MessagingException("Failed to fetch headers");
|
||||
ByteArrayInputStream bis = b.getByteArrayInputStream();
|
||||
if (bis == null)
|
||||
throw new MessagingException("Failed to fetch headers");
|
||||
this.headers.load(bis);
|
||||
} else {
|
||||
this.headers.addHeader("Content-Type", this.type);
|
||||
this.headers.addHeader("Content-Transfer-Encoding", this.bs.encoding);
|
||||
if (this.bs.description != null)
|
||||
this.headers.addHeader("Content-Description", this.bs.description);
|
||||
if (this.bs.id != null)
|
||||
this.headers.addHeader("Content-ID", this.bs.id);
|
||||
if (this.bs.md5 != null)
|
||||
this.headers.addHeader("Content-MD5", this.bs.md5);
|
||||
}
|
||||
} catch (ConnectionException cex) {
|
||||
throw new FolderClosedException(
|
||||
this.message.getFolder(), cex.getMessage());
|
||||
} catch (ProtocolException pex) {
|
||||
throw new MessagingException(pex.getMessage(), pex);
|
||||
}
|
||||
}
|
||||
this.headersLoaded = true;
|
||||
}
|
||||
}
|
||||
2049
rus/WEB-INF/lib/javax.mail_src/com/sun/mail/imap/IMAPFolder.java
Normal file
2049
rus/WEB-INF/lib/javax.mail_src/com/sun/mail/imap/IMAPFolder.java
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,156 @@
|
|||
package com.sun.mail.imap;
|
||||
|
||||
import com.sun.mail.iap.ByteArray;
|
||||
import com.sun.mail.iap.ConnectionException;
|
||||
import com.sun.mail.iap.ProtocolException;
|
||||
import com.sun.mail.imap.protocol.BODY;
|
||||
import com.sun.mail.imap.protocol.IMAPProtocol;
|
||||
import com.sun.mail.util.FolderClosedIOException;
|
||||
import com.sun.mail.util.MessageRemovedIOException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import javax.mail.Flags;
|
||||
import javax.mail.Folder;
|
||||
import javax.mail.FolderClosedException;
|
||||
import javax.mail.MessagingException;
|
||||
|
||||
public class IMAPInputStream extends InputStream {
|
||||
private IMAPMessage msg;
|
||||
|
||||
private String section;
|
||||
|
||||
private int pos;
|
||||
|
||||
private int blksize;
|
||||
|
||||
private int max;
|
||||
|
||||
private byte[] buf;
|
||||
|
||||
private int bufcount;
|
||||
|
||||
private int bufpos;
|
||||
|
||||
private boolean lastBuffer;
|
||||
|
||||
private boolean peek;
|
||||
|
||||
private ByteArray readbuf;
|
||||
|
||||
private static final int slop = 64;
|
||||
|
||||
public IMAPInputStream(IMAPMessage msg, String section, int max, boolean peek) {
|
||||
this.msg = msg;
|
||||
this.section = section;
|
||||
this.max = max;
|
||||
this.peek = peek;
|
||||
this.pos = 0;
|
||||
this.blksize = msg.getFetchBlockSize();
|
||||
}
|
||||
|
||||
private void forceCheckExpunged() throws MessageRemovedIOException, FolderClosedIOException {
|
||||
synchronized (this.msg.getMessageCacheLock()) {
|
||||
try {
|
||||
this.msg.getProtocol().noop();
|
||||
} catch (ConnectionException cex) {
|
||||
throw new FolderClosedIOException(this.msg.getFolder(),
|
||||
cex.getMessage());
|
||||
} catch (FolderClosedException fex) {
|
||||
throw new FolderClosedIOException(fex.getFolder(),
|
||||
fex.getMessage());
|
||||
} catch (ProtocolException e) {}
|
||||
}
|
||||
if (this.msg.isExpunged())
|
||||
throw new MessageRemovedIOException();
|
||||
}
|
||||
|
||||
private void fill() throws IOException {
|
||||
ByteArray ba;
|
||||
int cnt;
|
||||
if (this.lastBuffer || (this.max != -1 && this.pos >= this.max)) {
|
||||
if (this.pos == 0)
|
||||
checkSeen();
|
||||
this.readbuf = null;
|
||||
return;
|
||||
}
|
||||
BODY b = null;
|
||||
if (this.readbuf == null)
|
||||
this.readbuf = new ByteArray(this.blksize + 64);
|
||||
synchronized (this.msg.getMessageCacheLock()) {
|
||||
try {
|
||||
IMAPProtocol p = this.msg.getProtocol();
|
||||
if (this.msg.isExpunged())
|
||||
throw new MessageRemovedIOException("No content for expunged message");
|
||||
int seqnum = this.msg.getSequenceNumber();
|
||||
cnt = this.blksize;
|
||||
if (this.max != -1 && this.pos + this.blksize > this.max)
|
||||
cnt = this.max - this.pos;
|
||||
if (this.peek) {
|
||||
b = p.peekBody(seqnum, this.section, this.pos, cnt, this.readbuf);
|
||||
} else {
|
||||
b = p.fetchBody(seqnum, this.section, this.pos, cnt, this.readbuf);
|
||||
}
|
||||
} catch (ProtocolException pex) {
|
||||
forceCheckExpunged();
|
||||
throw new IOException(pex.getMessage());
|
||||
} catch (FolderClosedException fex) {
|
||||
throw new FolderClosedIOException(fex.getFolder(),
|
||||
fex.getMessage());
|
||||
}
|
||||
if (b == null || (ba = b.getByteArray()) == null) {
|
||||
forceCheckExpunged();
|
||||
throw new IOException("No content");
|
||||
}
|
||||
}
|
||||
if (this.pos == 0)
|
||||
checkSeen();
|
||||
this.buf = ba.getBytes();
|
||||
this.bufpos = ba.getStart();
|
||||
int n = ba.getCount();
|
||||
this.lastBuffer = (n < cnt);
|
||||
this.bufcount = this.bufpos + n;
|
||||
this.pos += n;
|
||||
}
|
||||
|
||||
public synchronized int read() throws IOException {
|
||||
if (this.bufpos >= this.bufcount) {
|
||||
fill();
|
||||
if (this.bufpos >= this.bufcount)
|
||||
return -1;
|
||||
}
|
||||
return this.buf[this.bufpos++] & 0xFF;
|
||||
}
|
||||
|
||||
public synchronized int read(byte[] b, int off, int len) throws IOException {
|
||||
int avail = this.bufcount - this.bufpos;
|
||||
if (avail <= 0) {
|
||||
fill();
|
||||
avail = this.bufcount - this.bufpos;
|
||||
if (avail <= 0)
|
||||
return -1;
|
||||
}
|
||||
int cnt = (avail < len) ? avail : len;
|
||||
System.arraycopy(this.buf, this.bufpos, b, off, cnt);
|
||||
this.bufpos += cnt;
|
||||
return cnt;
|
||||
}
|
||||
|
||||
public int read(byte[] b) throws IOException {
|
||||
return read(b, 0, b.length);
|
||||
}
|
||||
|
||||
public synchronized int available() throws IOException {
|
||||
return this.bufcount - this.bufpos;
|
||||
}
|
||||
|
||||
private void checkSeen() {
|
||||
if (this.peek)
|
||||
return;
|
||||
try {
|
||||
Folder f = this.msg.getFolder();
|
||||
if (f != null && f.getMode() != 1 &&
|
||||
!this.msg.isSet(Flags.Flag.SEEN))
|
||||
this.msg.setFlag(Flags.Flag.SEEN, true);
|
||||
} catch (MessagingException e) {}
|
||||
}
|
||||
}
|
||||
1036
rus/WEB-INF/lib/javax.mail_src/com/sun/mail/imap/IMAPMessage.java
Normal file
1036
rus/WEB-INF/lib/javax.mail_src/com/sun/mail/imap/IMAPMessage.java
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,32 @@
|
|||
package com.sun.mail.imap;
|
||||
|
||||
import com.sun.mail.imap.protocol.BODYSTRUCTURE;
|
||||
import java.util.Vector;
|
||||
import javax.mail.BodyPart;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.MultipartDataSource;
|
||||
import javax.mail.internet.MimePart;
|
||||
import javax.mail.internet.MimePartDataSource;
|
||||
|
||||
public class IMAPMultipartDataSource extends MimePartDataSource implements MultipartDataSource {
|
||||
private Vector parts;
|
||||
|
||||
protected IMAPMultipartDataSource(MimePart part, BODYSTRUCTURE[] bs, String sectionId, IMAPMessage msg) {
|
||||
super(part);
|
||||
this.parts = new Vector(bs.length);
|
||||
for (int i = 0; i < bs.length; i++)
|
||||
this.parts.addElement(new IMAPBodyPart(bs[i], (sectionId == null) ?
|
||||
|
||||
|
||||
Integer.toString(i + 1) : (sectionId + "." +
|
||||
Integer.toString(i + 1)), msg));
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return this.parts.size();
|
||||
}
|
||||
|
||||
public BodyPart getBodyPart(int index) throws MessagingException {
|
||||
return this.parts.elementAt(index);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
package com.sun.mail.imap;
|
||||
|
||||
import com.sun.mail.iap.ProtocolException;
|
||||
import com.sun.mail.imap.protocol.BODYSTRUCTURE;
|
||||
import com.sun.mail.imap.protocol.ENVELOPE;
|
||||
import com.sun.mail.imap.protocol.IMAPProtocol;
|
||||
import javax.mail.Flags;
|
||||
import javax.mail.FolderClosedException;
|
||||
import javax.mail.MessageRemovedException;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.MethodNotSupportedException;
|
||||
|
||||
public class IMAPNestedMessage extends IMAPMessage {
|
||||
private IMAPMessage msg;
|
||||
|
||||
IMAPNestedMessage(IMAPMessage m, BODYSTRUCTURE b, ENVELOPE e, String sid) {
|
||||
super(m._getSession());
|
||||
this.msg = m;
|
||||
this.bs = b;
|
||||
this.envelope = e;
|
||||
this.sectionId = sid;
|
||||
setPeek(m.getPeek());
|
||||
}
|
||||
|
||||
protected IMAPProtocol getProtocol() throws ProtocolException, FolderClosedException {
|
||||
return this.msg.getProtocol();
|
||||
}
|
||||
|
||||
protected boolean isREV1() throws FolderClosedException {
|
||||
return this.msg.isREV1();
|
||||
}
|
||||
|
||||
protected Object getMessageCacheLock() {
|
||||
return this.msg.getMessageCacheLock();
|
||||
}
|
||||
|
||||
protected int getSequenceNumber() {
|
||||
return this.msg.getSequenceNumber();
|
||||
}
|
||||
|
||||
protected void checkExpunged() throws MessageRemovedException {
|
||||
this.msg.checkExpunged();
|
||||
}
|
||||
|
||||
public boolean isExpunged() {
|
||||
return this.msg.isExpunged();
|
||||
}
|
||||
|
||||
protected int getFetchBlockSize() {
|
||||
return this.msg.getFetchBlockSize();
|
||||
}
|
||||
|
||||
protected boolean ignoreBodyStructureSize() {
|
||||
return this.msg.ignoreBodyStructureSize();
|
||||
}
|
||||
|
||||
public int getSize() throws MessagingException {
|
||||
return this.bs.size;
|
||||
}
|
||||
|
||||
public synchronized void setFlags(Flags flag, boolean set) throws MessagingException {
|
||||
throw new MethodNotSupportedException("Cannot set flags on this nested message");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.sun.mail.imap;
|
||||
|
||||
import javax.mail.Session;
|
||||
import javax.mail.URLName;
|
||||
|
||||
public class IMAPSSLStore extends IMAPStore {
|
||||
public IMAPSSLStore(Session session, URLName url) {
|
||||
super(session, url, "imaps", true);
|
||||
}
|
||||
}
|
||||
1222
rus/WEB-INF/lib/javax.mail_src/com/sun/mail/imap/IMAPStore.java
Normal file
1222
rus/WEB-INF/lib/javax.mail_src/com/sun/mail/imap/IMAPStore.java
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,207 @@
|
|||
package com.sun.mail.imap;
|
||||
|
||||
import com.sun.mail.util.MailLogger;
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.net.Socket;
|
||||
import java.nio.channels.SelectableChannel;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.Iterator;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.logging.Level;
|
||||
import javax.mail.Folder;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.Session;
|
||||
|
||||
public class IdleManager {
|
||||
private Executor es;
|
||||
|
||||
private Selector selector;
|
||||
|
||||
private MailLogger logger;
|
||||
|
||||
private volatile boolean die = false;
|
||||
|
||||
private Queue<IMAPFolder> toWatch = new ConcurrentLinkedQueue<IMAPFolder>();
|
||||
|
||||
private Queue<IMAPFolder> toAbort = new ConcurrentLinkedQueue<IMAPFolder>();
|
||||
|
||||
public IdleManager(Session session, Executor es) throws IOException {
|
||||
this.es = es;
|
||||
this.logger = new MailLogger(getClass(), "DEBUG IMAP", session);
|
||||
this.selector = Selector.open();
|
||||
es.execute(new Runnable() {
|
||||
public void run() {
|
||||
IdleManager.this.logger.fine("IdleManager select starting");
|
||||
try {
|
||||
IdleManager.this.select();
|
||||
} finally {
|
||||
IdleManager.this.logger.fine("IdleManager select terminating");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public synchronized void watch(Folder folder) throws MessagingException {
|
||||
if (!(folder instanceof IMAPFolder))
|
||||
throw new MessagingException("Can only watch IMAP folders");
|
||||
IMAPFolder ifolder = (IMAPFolder)folder;
|
||||
SocketChannel sc = ifolder.getChannel();
|
||||
if (sc == null)
|
||||
throw new MessagingException("Folder is not using SocketChannels");
|
||||
this.logger.log(Level.FINEST, "IdleManager watching {0}", ifolder);
|
||||
while (!ifolder.startIdle(this));
|
||||
this.toWatch.add(ifolder);
|
||||
this.selector.wakeup();
|
||||
}
|
||||
|
||||
void requestAbort(IMAPFolder folder) {
|
||||
this.toAbort.add(folder);
|
||||
this.selector.wakeup();
|
||||
}
|
||||
|
||||
private void select() {
|
||||
this.die = false;
|
||||
try {
|
||||
while (true) {
|
||||
try {
|
||||
if (!this.die) {
|
||||
watchAll();
|
||||
this.logger.finest("IdleManager waiting...");
|
||||
int ns = this.selector.select();
|
||||
if (this.logger.isLoggable(Level.FINEST))
|
||||
this.logger.log(Level.FINEST, "IdleManager selected {0} channels",
|
||||
Integer.valueOf(ns));
|
||||
if (!this.die && !Thread.currentThread().isInterrupted()) {
|
||||
while (processKeys() && this.selector.selectNow() > 0);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} catch (InterruptedIOException ex) {
|
||||
this.logger.log(Level.FINE, "IdleManager interrupted", (Throwable)ex);
|
||||
} catch (IOException ex) {
|
||||
this.logger.log(Level.FINE, "IdleManager got exception", (Throwable)ex);
|
||||
}
|
||||
return;
|
||||
}
|
||||
} finally {
|
||||
this.logger.fine("IdleManager unwatchAll");
|
||||
try {
|
||||
unwatchAll();
|
||||
this.selector.close();
|
||||
} catch (IOException ex2) {
|
||||
this.logger.log(Level.FINE, "IdleManager unwatch exception", (Throwable)ex2);
|
||||
}
|
||||
this.logger.fine("IdleManager exiting");
|
||||
}
|
||||
}
|
||||
|
||||
private void watchAll() {
|
||||
IMAPFolder folder;
|
||||
while ((folder = this.toWatch.poll()) != null) {
|
||||
this.logger.log(Level.FINEST, "IdleManager adding {0} to selector", folder);
|
||||
try {
|
||||
SocketChannel sc = folder.getChannel();
|
||||
if (sc == null)
|
||||
continue;
|
||||
sc.configureBlocking(false);
|
||||
sc.register(this.selector, 1, folder);
|
||||
} catch (IOException ex) {
|
||||
this.logger.log(Level.FINEST, "IdleManager can't register folder", (Throwable)ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean processKeys() throws IOException {
|
||||
boolean more = false;
|
||||
Set<SelectionKey> selectedKeys = this.selector.selectedKeys();
|
||||
Iterator<SelectionKey> it = selectedKeys.iterator();
|
||||
while (it.hasNext()) {
|
||||
SelectionKey sk = it.next();
|
||||
it.remove();
|
||||
sk.cancel();
|
||||
IMAPFolder iMAPFolder = (IMAPFolder)sk.attachment();
|
||||
this.logger.log(Level.FINE, "IdleManager selected folder: {0}", iMAPFolder);
|
||||
SelectableChannel sc = sk.channel();
|
||||
sc.configureBlocking(true);
|
||||
try {
|
||||
if (iMAPFolder.handleIdle(false)) {
|
||||
this.logger.log(Level.FINE, "IdleManager continue watching folder {0}", iMAPFolder);
|
||||
this.toWatch.add(iMAPFolder);
|
||||
more = true;
|
||||
continue;
|
||||
}
|
||||
this.logger.log(Level.FINE, "IdleManager done watching folder {0}", iMAPFolder);
|
||||
} catch (MessagingException ex) {
|
||||
this.logger.log(Level.FINE, "IdleManager got exception for folder: " + iMAPFolder, (Throwable)ex);
|
||||
}
|
||||
}
|
||||
IMAPFolder folder;
|
||||
while ((folder = this.toAbort.poll()) != null) {
|
||||
this.logger.log(Level.FINE, "IdleManager aborting IDLE for folder: {0}", folder);
|
||||
SocketChannel sc = folder.getChannel();
|
||||
if (sc == null)
|
||||
continue;
|
||||
SelectionKey sk = sc.keyFor(this.selector);
|
||||
if (sk != null)
|
||||
sk.cancel();
|
||||
sc.configureBlocking(true);
|
||||
Socket sock = sc.socket();
|
||||
if (sock != null && sock.getSoTimeout() > 0) {
|
||||
this.logger.fine("IdleManager requesting DONE with timeout");
|
||||
this.toWatch.remove(folder);
|
||||
final IMAPFolder folder0 = folder;
|
||||
this.es.execute(new Runnable() {
|
||||
public void run() {
|
||||
folder0.idleAbortWait();
|
||||
}
|
||||
});
|
||||
continue;
|
||||
}
|
||||
folder.idleAbort();
|
||||
this.toWatch.add(folder);
|
||||
more = true;
|
||||
}
|
||||
return more;
|
||||
}
|
||||
|
||||
private void unwatchAll() {
|
||||
Set<SelectionKey> keys = this.selector.keys();
|
||||
for (SelectionKey sk : keys) {
|
||||
sk.cancel();
|
||||
IMAPFolder iMAPFolder = (IMAPFolder)sk.attachment();
|
||||
this.logger.log(Level.FINE, "IdleManager no longer watching folder: {0}", iMAPFolder);
|
||||
SelectableChannel sc = sk.channel();
|
||||
try {
|
||||
sc.configureBlocking(true);
|
||||
iMAPFolder.idleAbortWait();
|
||||
} catch (IOException ex) {
|
||||
this.logger.log(Level.FINE, "IdleManager exception while aborting idle for folder: " + iMAPFolder, (Throwable)ex);
|
||||
}
|
||||
}
|
||||
IMAPFolder folder;
|
||||
while ((folder = this.toWatch.poll()) != null) {
|
||||
this.logger.log(Level.FINE, "IdleManager aborting IDLE for unwatched folder: {0}", folder);
|
||||
SocketChannel sc = folder.getChannel();
|
||||
if (sc == null)
|
||||
continue;
|
||||
try {
|
||||
sc.configureBlocking(true);
|
||||
folder.idleAbortWait();
|
||||
} catch (IOException ex) {
|
||||
this.logger.log(Level.FINE, "IdleManager exception while aborting idle for folder: " + folder, (Throwable)ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void stop() {
|
||||
this.die = true;
|
||||
this.logger.finest("IdleManager stopping");
|
||||
this.selector.wakeup();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
package com.sun.mail.imap;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
class LengthCounter extends OutputStream {
|
||||
private int size = 0;
|
||||
|
||||
private byte[] buf;
|
||||
|
||||
private int maxsize;
|
||||
|
||||
public LengthCounter(int maxsize) {
|
||||
this.buf = new byte[8192];
|
||||
this.maxsize = maxsize;
|
||||
}
|
||||
|
||||
public void write(int b) {
|
||||
int newsize = this.size + 1;
|
||||
if (this.buf != null)
|
||||
if (newsize > this.maxsize && this.maxsize >= 0) {
|
||||
this.buf = null;
|
||||
} else if (newsize > this.buf.length) {
|
||||
byte[] newbuf = new byte[Math.max(this.buf.length << 1, newsize)];
|
||||
System.arraycopy(this.buf, 0, newbuf, 0, this.size);
|
||||
this.buf = newbuf;
|
||||
this.buf[this.size] = (byte)b;
|
||||
} else {
|
||||
this.buf[this.size] = (byte)b;
|
||||
}
|
||||
this.size = newsize;
|
||||
}
|
||||
|
||||
public void write(byte[] b, int off, int len) {
|
||||
if (off < 0 || off > b.length || len < 0 || off + len > b.length || off + len < 0)
|
||||
throw new IndexOutOfBoundsException();
|
||||
if (len == 0)
|
||||
return;
|
||||
int newsize = this.size + len;
|
||||
if (this.buf != null)
|
||||
if (newsize > this.maxsize && this.maxsize >= 0) {
|
||||
this.buf = null;
|
||||
} else if (newsize > this.buf.length) {
|
||||
byte[] newbuf = new byte[Math.max(this.buf.length << 1, newsize)];
|
||||
System.arraycopy(this.buf, 0, newbuf, 0, this.size);
|
||||
this.buf = newbuf;
|
||||
System.arraycopy(b, off, this.buf, this.size, len);
|
||||
} else {
|
||||
System.arraycopy(b, off, this.buf, this.size, len);
|
||||
}
|
||||
this.size = newsize;
|
||||
}
|
||||
|
||||
public void write(byte[] b) throws IOException {
|
||||
write(b, 0, b.length);
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return this.size;
|
||||
}
|
||||
|
||||
public byte[] getBytes() {
|
||||
return this.buf;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,262 @@
|
|||
package com.sun.mail.imap;
|
||||
|
||||
import com.sun.mail.util.MailLogger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import javax.mail.Message;
|
||||
|
||||
public class MessageCache {
|
||||
private IMAPMessage[] messages;
|
||||
|
||||
private int[] seqnums;
|
||||
|
||||
private int size;
|
||||
|
||||
private IMAPFolder folder;
|
||||
|
||||
private MailLogger logger;
|
||||
|
||||
private static final int SLOP = 64;
|
||||
|
||||
MessageCache(IMAPFolder folder, IMAPStore store, int size) {
|
||||
this.folder = folder;
|
||||
this.logger = folder.logger.getSubLogger("messagecache", "DEBUG IMAP MC",
|
||||
store.getMessageCacheDebug());
|
||||
if (this.logger.isLoggable(Level.CONFIG))
|
||||
this.logger.config("create cache of size " + size);
|
||||
ensureCapacity(size, 1);
|
||||
}
|
||||
|
||||
MessageCache(int size, boolean debug) {
|
||||
this.folder = null;
|
||||
this
|
||||
.logger = new MailLogger(getClass(), "messagecache", "DEBUG IMAP MC", debug, System.out);
|
||||
if (this.logger.isLoggable(Level.CONFIG))
|
||||
this.logger.config("create DEBUG cache of size " + size);
|
||||
ensureCapacity(size, 1);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return this.size;
|
||||
}
|
||||
|
||||
public IMAPMessage getMessage(int msgnum) {
|
||||
if (msgnum < 1 || msgnum > this.size)
|
||||
throw new ArrayIndexOutOfBoundsException("message number (" + msgnum + ") out of bounds (" + this.size + ")");
|
||||
IMAPMessage msg = this.messages[msgnum - 1];
|
||||
if (msg == null) {
|
||||
if (this.logger.isLoggable(Level.FINE))
|
||||
this.logger.fine("create message number " + msgnum);
|
||||
msg = this.folder.newIMAPMessage(msgnum);
|
||||
this.messages[msgnum - 1] = msg;
|
||||
if (seqnumOf(msgnum) <= 0) {
|
||||
this.logger.fine("it's expunged!");
|
||||
msg.setExpunged(true);
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
public IMAPMessage getMessageBySeqnum(int seqnum) {
|
||||
int msgnum = msgnumOf(seqnum);
|
||||
if (msgnum < 0) {
|
||||
if (this.logger.isLoggable(Level.FINE))
|
||||
this.logger.fine("no message seqnum " + seqnum);
|
||||
return null;
|
||||
}
|
||||
return getMessage(msgnum);
|
||||
}
|
||||
|
||||
public void expungeMessage(int seqnum) {
|
||||
int msgnum = msgnumOf(seqnum);
|
||||
if (msgnum < 0) {
|
||||
if (this.logger.isLoggable(Level.FINE))
|
||||
this.logger.fine("expunge no seqnum " + seqnum);
|
||||
return;
|
||||
}
|
||||
IMAPMessage msg = this.messages[msgnum - 1];
|
||||
if (msg != null) {
|
||||
if (this.logger.isLoggable(Level.FINE))
|
||||
this.logger.fine("expunge existing " + msgnum);
|
||||
msg.setExpunged(true);
|
||||
}
|
||||
if (this.seqnums == null) {
|
||||
this.logger.fine("create seqnums array");
|
||||
this.seqnums = new int[this.messages.length];
|
||||
for (int j = 1; j < msgnum; j++)
|
||||
this.seqnums[j - 1] = j;
|
||||
this.seqnums[msgnum - 1] = 0;
|
||||
for (int i = msgnum + 1; i <= this.seqnums.length; i++)
|
||||
this.seqnums[i - 1] = i - 1;
|
||||
} else {
|
||||
this.seqnums[msgnum - 1] = 0;
|
||||
for (int i = msgnum + 1; i <= this.seqnums.length; i++) {
|
||||
assert this.seqnums[i - 1] != 1;
|
||||
if (this.seqnums[i - 1] > 0)
|
||||
this.seqnums[i - 1] = this.seqnums[i - 1] - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IMAPMessage[] removeExpungedMessages() {
|
||||
this.logger.fine("remove expunged messages");
|
||||
List<IMAPMessage> mlist = new ArrayList();
|
||||
int oldnum = 1;
|
||||
int newnum = 1;
|
||||
while (oldnum <= this.size) {
|
||||
if (seqnumOf(oldnum) <= 0) {
|
||||
IMAPMessage m = getMessage(oldnum);
|
||||
mlist.add(m);
|
||||
} else {
|
||||
if (newnum != oldnum) {
|
||||
this.messages[newnum - 1] = this.messages[oldnum - 1];
|
||||
if (this.messages[newnum - 1] != null)
|
||||
this.messages[newnum - 1].setMessageNumber(newnum);
|
||||
}
|
||||
newnum++;
|
||||
}
|
||||
oldnum++;
|
||||
}
|
||||
this.seqnums = null;
|
||||
shrink(newnum, oldnum);
|
||||
IMAPMessage[] rmsgs = new IMAPMessage[mlist.size()];
|
||||
if (this.logger.isLoggable(Level.FINE))
|
||||
this.logger.fine("return " + rmsgs.length);
|
||||
mlist.<IMAPMessage>toArray(rmsgs);
|
||||
return rmsgs;
|
||||
}
|
||||
|
||||
public IMAPMessage[] removeExpungedMessages(Message[] msgs) {
|
||||
this.logger.fine("remove expunged messages");
|
||||
List<IMAPMessage> mlist = new ArrayList();
|
||||
int[] mnum = new int[msgs.length];
|
||||
for (int i = 0; i < msgs.length; i++)
|
||||
mnum[i] = msgs[i].getMessageNumber();
|
||||
Arrays.sort(mnum);
|
||||
int oldnum = 1;
|
||||
int newnum = 1;
|
||||
int mnumi = 0;
|
||||
boolean keepSeqnums = false;
|
||||
while (oldnum <= this.size) {
|
||||
if (mnumi < mnum.length && oldnum == mnum[mnumi] &&
|
||||
|
||||
seqnumOf(oldnum) <= 0) {
|
||||
IMAPMessage m = getMessage(oldnum);
|
||||
mlist.add(m);
|
||||
while (mnumi < mnum.length && mnum[mnumi] <= oldnum)
|
||||
mnumi++;
|
||||
} else {
|
||||
if (newnum != oldnum) {
|
||||
this.messages[newnum - 1] = this.messages[oldnum - 1];
|
||||
if (this.messages[newnum - 1] != null)
|
||||
this.messages[newnum - 1].setMessageNumber(newnum);
|
||||
if (this.seqnums != null)
|
||||
this.seqnums[newnum - 1] = this.seqnums[oldnum - 1];
|
||||
}
|
||||
if (this.seqnums != null && this.seqnums[newnum - 1] != newnum)
|
||||
keepSeqnums = true;
|
||||
newnum++;
|
||||
}
|
||||
oldnum++;
|
||||
}
|
||||
if (!keepSeqnums)
|
||||
this.seqnums = null;
|
||||
shrink(newnum, oldnum);
|
||||
IMAPMessage[] rmsgs = new IMAPMessage[mlist.size()];
|
||||
if (this.logger.isLoggable(Level.FINE))
|
||||
this.logger.fine("return " + rmsgs.length);
|
||||
mlist.<IMAPMessage>toArray(rmsgs);
|
||||
return rmsgs;
|
||||
}
|
||||
|
||||
private void shrink(int newend, int oldend) {
|
||||
this.size = newend - 1;
|
||||
if (this.logger.isLoggable(Level.FINE))
|
||||
this.logger.fine("size now " + this.size);
|
||||
if (this.size == 0) {
|
||||
this.messages = null;
|
||||
this.seqnums = null;
|
||||
} else if (this.size > 64 && this.size < this.messages.length / 2) {
|
||||
this.logger.fine("reallocate array");
|
||||
IMAPMessage[] newm = new IMAPMessage[this.size + 64];
|
||||
System.arraycopy(this.messages, 0, newm, 0, this.size);
|
||||
this.messages = newm;
|
||||
if (this.seqnums != null) {
|
||||
int[] news = new int[this.size + 64];
|
||||
System.arraycopy(this.seqnums, 0, news, 0, this.size);
|
||||
this.seqnums = news;
|
||||
}
|
||||
} else {
|
||||
if (this.logger.isLoggable(Level.FINE))
|
||||
this.logger.fine("clean " + newend + " to " + oldend);
|
||||
for (int msgnum = newend; msgnum < oldend; msgnum++) {
|
||||
this.messages[msgnum - 1] = null;
|
||||
if (this.seqnums != null)
|
||||
this.seqnums[msgnum - 1] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addMessages(int count, int newSeqNum) {
|
||||
if (this.logger.isLoggable(Level.FINE))
|
||||
this.logger.fine("add " + count + " messages");
|
||||
ensureCapacity(this.size + count, newSeqNum);
|
||||
}
|
||||
|
||||
private void ensureCapacity(int newsize, int newSeqNum) {
|
||||
if (this.messages == null) {
|
||||
this.messages = new IMAPMessage[newsize + 64];
|
||||
} else if (this.messages.length < newsize) {
|
||||
if (this.logger.isLoggable(Level.FINE))
|
||||
this.logger.fine("expand capacity to " + newsize);
|
||||
IMAPMessage[] newm = new IMAPMessage[newsize + 64];
|
||||
System.arraycopy(this.messages, 0, newm, 0, this.messages.length);
|
||||
this.messages = newm;
|
||||
if (this.seqnums != null) {
|
||||
int[] news = new int[newsize + 64];
|
||||
System.arraycopy(this.seqnums, 0, news, 0, this.seqnums.length);
|
||||
for (int i = this.size; i < news.length; i++)
|
||||
news[i] = newSeqNum++;
|
||||
this.seqnums = news;
|
||||
if (this.logger.isLoggable(Level.FINE))
|
||||
this.logger.fine("message " + newsize + " has sequence number " + this.seqnums[newsize - 1]);
|
||||
}
|
||||
} else if (newsize < this.size) {
|
||||
if (this.logger.isLoggable(Level.FINE))
|
||||
this.logger.fine("shrink capacity to " + newsize);
|
||||
for (int msgnum = newsize + 1; msgnum <= this.size; msgnum++) {
|
||||
this.messages[msgnum - 1] = null;
|
||||
if (this.seqnums != null)
|
||||
this.seqnums[msgnum - 1] = -1;
|
||||
}
|
||||
}
|
||||
this.size = newsize;
|
||||
}
|
||||
|
||||
public int seqnumOf(int msgnum) {
|
||||
if (this.seqnums == null)
|
||||
return msgnum;
|
||||
if (this.logger.isLoggable(Level.FINE))
|
||||
this.logger.fine("msgnum " + msgnum + " is seqnum " + this.seqnums[msgnum - 1]);
|
||||
return this.seqnums[msgnum - 1];
|
||||
}
|
||||
|
||||
private int msgnumOf(int seqnum) {
|
||||
if (this.seqnums == null)
|
||||
return seqnum;
|
||||
if (seqnum < 1) {
|
||||
if (this.logger.isLoggable(Level.FINE))
|
||||
this.logger.fine("bad seqnum " + seqnum);
|
||||
return -1;
|
||||
}
|
||||
for (int msgnum = seqnum; msgnum <= this.size; msgnum++) {
|
||||
if (this.seqnums[msgnum - 1] == seqnum)
|
||||
return msgnum;
|
||||
if (this.seqnums[msgnum - 1] > seqnum)
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package com.sun.mail.imap;
|
||||
|
||||
import com.sun.mail.iap.Literal;
|
||||
import com.sun.mail.util.CRLFOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import javax.mail.Message;
|
||||
import javax.mail.MessagingException;
|
||||
|
||||
class MessageLiteral implements Literal {
|
||||
private Message msg;
|
||||
|
||||
private int msgSize = -1;
|
||||
|
||||
private byte[] buf;
|
||||
|
||||
public MessageLiteral(Message msg, int maxsize) throws MessagingException, IOException {
|
||||
this.msg = msg;
|
||||
LengthCounter lc = new LengthCounter(maxsize);
|
||||
OutputStream os = new CRLFOutputStream(lc);
|
||||
msg.writeTo(os);
|
||||
os.flush();
|
||||
this.msgSize = lc.getSize();
|
||||
this.buf = lc.getBytes();
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return this.msgSize;
|
||||
}
|
||||
|
||||
public void writeTo(OutputStream os) throws IOException {
|
||||
try {
|
||||
if (this.buf != null) {
|
||||
os.write(this.buf, 0, this.msgSize);
|
||||
} else {
|
||||
os = new CRLFOutputStream(os);
|
||||
this.msg.writeTo(os);
|
||||
}
|
||||
} catch (MessagingException mex) {
|
||||
throw new IOException("MessagingException while appending message: " + mex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.sun.mail.imap;
|
||||
|
||||
import javax.mail.Folder;
|
||||
import javax.mail.Message;
|
||||
import javax.mail.event.MessageCountEvent;
|
||||
|
||||
public class MessageVanishedEvent extends MessageCountEvent {
|
||||
private long[] uids;
|
||||
|
||||
private static final Message[] noMessages = new Message[0];
|
||||
|
||||
private static final long serialVersionUID = 2142028010250024922L;
|
||||
|
||||
public MessageVanishedEvent(Folder folder, long[] uids) {
|
||||
super(folder, 2, true, noMessages);
|
||||
this.uids = uids;
|
||||
}
|
||||
|
||||
public long[] getUIDs() {
|
||||
return this.uids;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package com.sun.mail.imap;
|
||||
|
||||
import javax.mail.Message;
|
||||
import javax.mail.search.SearchTerm;
|
||||
|
||||
public final class ModifiedSinceTerm extends SearchTerm {
|
||||
private long modseq;
|
||||
|
||||
private static final long serialVersionUID = 5151457469634727992L;
|
||||
|
||||
public ModifiedSinceTerm(long modseq) {
|
||||
this.modseq = modseq;
|
||||
}
|
||||
|
||||
public long getModSeq() {
|
||||
return this.modseq;
|
||||
}
|
||||
|
||||
public boolean match(Message msg) {
|
||||
long m;
|
||||
try {
|
||||
if (msg instanceof IMAPMessage) {
|
||||
m = ((IMAPMessage)msg).getModSeq();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
return (m >= this.modseq);
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof ModifiedSinceTerm))
|
||||
return false;
|
||||
return (this.modseq == ((ModifiedSinceTerm)obj).modseq);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return (int)this.modseq;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package com.sun.mail.imap;
|
||||
|
||||
import java.util.Date;
|
||||
import javax.mail.Message;
|
||||
import javax.mail.search.SearchTerm;
|
||||
|
||||
public final class OlderTerm extends SearchTerm {
|
||||
private int interval;
|
||||
|
||||
private static final long serialVersionUID = 3951078948727995682L;
|
||||
|
||||
public OlderTerm(int interval) {
|
||||
this.interval = interval;
|
||||
}
|
||||
|
||||
public int getInterval() {
|
||||
return this.interval;
|
||||
}
|
||||
|
||||
public boolean match(Message msg) {
|
||||
Date d;
|
||||
try {
|
||||
d = msg.getReceivedDate();
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
if (d == null)
|
||||
return false;
|
||||
return
|
||||
(d.getTime() <= System.currentTimeMillis() - (long)this.interval * 1000L);
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof OlderTerm))
|
||||
return false;
|
||||
return (this.interval == ((OlderTerm)obj).interval);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.interval;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package com.sun.mail.imap;
|
||||
|
||||
import com.sun.mail.imap.protocol.UIDSet;
|
||||
|
||||
public class ResyncData {
|
||||
private long uidvalidity = -1L;
|
||||
|
||||
private long modseq = -1L;
|
||||
|
||||
private UIDSet[] uids = null;
|
||||
|
||||
public static final ResyncData CONDSTORE = new ResyncData(-1L, -1L);
|
||||
|
||||
public ResyncData(long uidvalidity, long modseq) {
|
||||
this.uidvalidity = uidvalidity;
|
||||
this.modseq = modseq;
|
||||
this.uids = null;
|
||||
}
|
||||
|
||||
public ResyncData(long uidvalidity, long modseq, long uidFirst, long uidLast) {
|
||||
this.uidvalidity = uidvalidity;
|
||||
this.modseq = modseq;
|
||||
this.uids = new UIDSet[] { new UIDSet(uidFirst, uidLast) };
|
||||
}
|
||||
|
||||
public ResyncData(long uidvalidity, long modseq, long[] uids) {
|
||||
this.uidvalidity = uidvalidity;
|
||||
this.modseq = modseq;
|
||||
this.uids = UIDSet.createUIDSets(uids);
|
||||
}
|
||||
|
||||
public long getUIDValidity() {
|
||||
return this.uidvalidity;
|
||||
}
|
||||
|
||||
public long getModSeq() {
|
||||
return this.modseq;
|
||||
}
|
||||
|
||||
UIDSet[] getUIDSet() {
|
||||
return this.uids;
|
||||
}
|
||||
}
|
||||
148
rus/WEB-INF/lib/javax.mail_src/com/sun/mail/imap/Rights.java
Normal file
148
rus/WEB-INF/lib/javax.mail_src/com/sun/mail/imap/Rights.java
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
package com.sun.mail.imap;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
public class Rights implements Cloneable {
|
||||
private boolean[] rights = new boolean[128];
|
||||
|
||||
public Rights() {}
|
||||
|
||||
public static final class Right {
|
||||
private static Right[] cache = new Right[128];
|
||||
|
||||
public static final Right LOOKUP = getInstance('l');
|
||||
|
||||
public static final Right READ = getInstance('r');
|
||||
|
||||
public static final Right KEEP_SEEN = getInstance('s');
|
||||
|
||||
public static final Right WRITE = getInstance('w');
|
||||
|
||||
public static final Right INSERT = getInstance('i');
|
||||
|
||||
public static final Right POST = getInstance('p');
|
||||
|
||||
public static final Right CREATE = getInstance('c');
|
||||
|
||||
public static final Right DELETE = getInstance('d');
|
||||
|
||||
public static final Right ADMINISTER = getInstance('a');
|
||||
|
||||
char right;
|
||||
|
||||
private Right(char right) {
|
||||
if (right >= '\u0080')
|
||||
throw new IllegalArgumentException("Right must be ASCII");
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
public static synchronized Right getInstance(char right) {
|
||||
if (right >= '\u0080')
|
||||
throw new IllegalArgumentException("Right must be ASCII");
|
||||
if (cache[right] == null)
|
||||
cache[right] = new Right(right);
|
||||
return cache[right];
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return String.valueOf(this.right);
|
||||
}
|
||||
}
|
||||
|
||||
public Rights(Rights rights) {
|
||||
System.arraycopy(rights.rights, 0, this.rights, 0, this.rights.length);
|
||||
}
|
||||
|
||||
public Rights(String rights) {
|
||||
for (int i = 0; i < rights.length(); i++)
|
||||
add(Right.getInstance(rights.charAt(i)));
|
||||
}
|
||||
|
||||
public Rights(Right right) {
|
||||
this.rights[right.right] = true;
|
||||
}
|
||||
|
||||
public void add(Right right) {
|
||||
this.rights[right.right] = true;
|
||||
}
|
||||
|
||||
public void add(Rights rights) {
|
||||
for (int i = 0; i < rights.rights.length; i++) {
|
||||
if (rights.rights[i])
|
||||
this.rights[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void remove(Right right) {
|
||||
this.rights[right.right] = false;
|
||||
}
|
||||
|
||||
public void remove(Rights rights) {
|
||||
for (int i = 0; i < rights.rights.length; i++) {
|
||||
if (rights.rights[i])
|
||||
this.rights[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean contains(Right right) {
|
||||
return this.rights[right.right];
|
||||
}
|
||||
|
||||
public boolean contains(Rights rights) {
|
||||
for (int i = 0; i < rights.rights.length; i++) {
|
||||
if (rights.rights[i] && !this.rights[i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof Rights))
|
||||
return false;
|
||||
Rights rights = (Rights)obj;
|
||||
for (int i = 0; i < rights.rights.length; i++) {
|
||||
if (rights.rights[i] != this.rights[i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int hash = 0;
|
||||
for (int i = 0; i < this.rights.length; i++) {
|
||||
if (this.rights[i])
|
||||
hash++;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
public Right[] getRights() {
|
||||
Vector<Right> v = new Vector();
|
||||
for (int i = 0; i < this.rights.length; i++) {
|
||||
if (this.rights[i])
|
||||
v.addElement(Right.getInstance((char)i));
|
||||
}
|
||||
Right[] rights = new Right[v.size()];
|
||||
v.copyInto(rights);
|
||||
return rights;
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
Rights r = null;
|
||||
try {
|
||||
r = (Rights)super.clone();
|
||||
r.rights = new boolean[128];
|
||||
System.arraycopy(this.rights, 0, r.rights, 0, this.rights.length);
|
||||
} catch (CloneNotSupportedException e) {}
|
||||
return r;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (int i = 0; i < this.rights.length; i++) {
|
||||
if (this.rights[i])
|
||||
sb.append((char)i);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package com.sun.mail.imap;
|
||||
|
||||
public final class SortTerm {
|
||||
public static final SortTerm ARRIVAL = new SortTerm("ARRIVAL");
|
||||
|
||||
public static final SortTerm CC = new SortTerm("CC");
|
||||
|
||||
public static final SortTerm DATE = new SortTerm("DATE");
|
||||
|
||||
public static final SortTerm FROM = new SortTerm("FROM");
|
||||
|
||||
public static final SortTerm REVERSE = new SortTerm("REVERSE");
|
||||
|
||||
public static final SortTerm SIZE = new SortTerm("SIZE");
|
||||
|
||||
public static final SortTerm SUBJECT = new SortTerm("SUBJECT");
|
||||
|
||||
public static final SortTerm TO = new SortTerm("TO");
|
||||
|
||||
private String term;
|
||||
|
||||
private SortTerm(String term) {
|
||||
this.term = term;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return this.term;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
package com.sun.mail.imap;
|
||||
|
||||
import com.sun.mail.imap.protocol.MessageSet;
|
||||
import com.sun.mail.imap.protocol.UIDSet;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.Vector;
|
||||
import javax.mail.Message;
|
||||
|
||||
public final class Utility {
|
||||
public static MessageSet[] toMessageSet(Message[] msgs, Condition cond) {
|
||||
Vector<MessageSet> v = new Vector(1);
|
||||
for (int i = 0; i < msgs.length; i++) {
|
||||
IMAPMessage msg = (IMAPMessage)msgs[i];
|
||||
if (!msg.isExpunged()) {
|
||||
int current = msg.getSequenceNumber();
|
||||
if (cond == null || cond.test(msg)) {
|
||||
MessageSet set = new MessageSet();
|
||||
set.start = current;
|
||||
for (; ++i < msgs.length; i++) {
|
||||
msg = (IMAPMessage)msgs[i];
|
||||
if (!msg.isExpunged()) {
|
||||
int next = msg.getSequenceNumber();
|
||||
if (cond == null || cond.test(msg))
|
||||
if (next == current + 1) {
|
||||
current = next;
|
||||
} else {
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
set.end = current;
|
||||
v.addElement(set);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (v.isEmpty())
|
||||
return null;
|
||||
MessageSet[] sets = new MessageSet[v.size()];
|
||||
v.copyInto(sets);
|
||||
return sets;
|
||||
}
|
||||
|
||||
public static MessageSet[] toMessageSetSorted(Message[] msgs, Condition cond) {
|
||||
msgs = (Message[])msgs.clone();
|
||||
Arrays.<Message>sort(msgs, new Comparator<Message>() {
|
||||
public int compare(Message msg1, Message msg2) {
|
||||
return msg1.getMessageNumber() - msg2.getMessageNumber();
|
||||
}
|
||||
});
|
||||
return toMessageSet(msgs, cond);
|
||||
}
|
||||
|
||||
public static interface Condition {
|
||||
boolean test(IMAPMessage param1IMAPMessage);
|
||||
}
|
||||
|
||||
public static UIDSet[] toUIDSet(Message[] msgs) {
|
||||
Vector<UIDSet> v = new Vector(1);
|
||||
for (int i = 0; i < msgs.length; i++) {
|
||||
IMAPMessage msg = (IMAPMessage)msgs[i];
|
||||
if (!msg.isExpunged()) {
|
||||
long current = msg.getUID();
|
||||
UIDSet set = new UIDSet();
|
||||
set.start = current;
|
||||
for (; ++i < msgs.length; i++) {
|
||||
msg = (IMAPMessage)msgs[i];
|
||||
if (!msg.isExpunged()) {
|
||||
long next = msg.getUID();
|
||||
if (next == current + 1L) {
|
||||
current = next;
|
||||
} else {
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
set.end = current;
|
||||
v.addElement(set);
|
||||
}
|
||||
}
|
||||
if (v.isEmpty())
|
||||
return null;
|
||||
UIDSet[] sets = new UIDSet[v.size()];
|
||||
v.copyInto(sets);
|
||||
return sets;
|
||||
}
|
||||
|
||||
public static UIDSet[] getResyncUIDSet(ResyncData rd) {
|
||||
return rd.getUIDSet();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package com.sun.mail.imap;
|
||||
|
||||
import java.util.Date;
|
||||
import javax.mail.Message;
|
||||
import javax.mail.search.SearchTerm;
|
||||
|
||||
public final class YoungerTerm extends SearchTerm {
|
||||
private int interval;
|
||||
|
||||
private static final long serialVersionUID = 1592714210688163496L;
|
||||
|
||||
public YoungerTerm(int interval) {
|
||||
this.interval = interval;
|
||||
}
|
||||
|
||||
public int getInterval() {
|
||||
return this.interval;
|
||||
}
|
||||
|
||||
public boolean match(Message msg) {
|
||||
Date d;
|
||||
try {
|
||||
d = msg.getReceivedDate();
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
if (d == null)
|
||||
return false;
|
||||
return
|
||||
(d.getTime() >= System.currentTimeMillis() - (long)this.interval * 1000L);
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof YoungerTerm))
|
||||
return false;
|
||||
return (this.interval == ((YoungerTerm)obj).interval);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.interval;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
package com.sun.mail.imap.protocol;
|
||||
|
||||
import java.text.CharacterIterator;
|
||||
import java.text.StringCharacterIterator;
|
||||
|
||||
public class BASE64MailboxDecoder {
|
||||
public static String decode(String original) {
|
||||
if (original == null || original.length() == 0)
|
||||
return original;
|
||||
boolean changedString = false;
|
||||
int copyTo = 0;
|
||||
char[] chars = new char[original.length()];
|
||||
StringCharacterIterator iter = new StringCharacterIterator(original);
|
||||
for (char c = iter.first(); c != Character.MAX_VALUE;
|
||||
c = iter.next()) {
|
||||
if (c == '&') {
|
||||
changedString = true;
|
||||
copyTo = base64decode(chars, copyTo, iter);
|
||||
} else {
|
||||
chars[copyTo++] = c;
|
||||
}
|
||||
}
|
||||
if (changedString)
|
||||
return new String(chars, 0, copyTo);
|
||||
return original;
|
||||
}
|
||||
|
||||
protected static int base64decode(char[] buffer, int offset, CharacterIterator iter) {
|
||||
boolean firsttime = true;
|
||||
int leftover = -1;
|
||||
while (true) {
|
||||
byte orig_0 = (byte)iter.next();
|
||||
if (orig_0 == -1)
|
||||
break;
|
||||
if (orig_0 == 45) {
|
||||
if (firsttime) {
|
||||
buffer[offset++] = '&';
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
firsttime = false;
|
||||
byte orig_1 = (byte)iter.next();
|
||||
if (orig_1 == -1 || orig_1 == 45)
|
||||
break;
|
||||
byte a = pem_convert_array[orig_0 & 0xFF];
|
||||
byte b = pem_convert_array[orig_1 & 0xFF];
|
||||
byte current = (byte)(a << 2 & 0xFC | b >>> 4 & 0x3);
|
||||
if (leftover != -1) {
|
||||
buffer[offset++] = (char)(leftover << 8 | current & 0xFF);
|
||||
leftover = -1;
|
||||
} else {
|
||||
leftover = current & 0xFF;
|
||||
}
|
||||
byte orig_2 = (byte)iter.next();
|
||||
if (orig_2 == 61)
|
||||
continue;
|
||||
if (orig_2 == -1 || orig_2 == 45)
|
||||
break;
|
||||
a = b;
|
||||
b = pem_convert_array[orig_2 & 0xFF];
|
||||
current = (byte)(a << 4 & 0xF0 | b >>> 2 & 0xF);
|
||||
if (leftover != -1) {
|
||||
buffer[offset++] = (char)(leftover << 8 | current & 0xFF);
|
||||
leftover = -1;
|
||||
} else {
|
||||
leftover = current & 0xFF;
|
||||
}
|
||||
byte orig_3 = (byte)iter.next();
|
||||
if (orig_3 == 61)
|
||||
continue;
|
||||
if (orig_3 == -1 || orig_3 == 45)
|
||||
break;
|
||||
a = b;
|
||||
b = pem_convert_array[orig_3 & 0xFF];
|
||||
current = (byte)(a << 6 & 0xC0 | b & 0x3F);
|
||||
if (leftover != -1) {
|
||||
buffer[offset++] = (char)(leftover << 8 | current & 0xFF);
|
||||
leftover = -1;
|
||||
continue;
|
||||
}
|
||||
leftover = current & 0xFF;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
static final char[] pem_array = new char[] {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
|
||||
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
|
||||
'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
|
||||
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
||||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
|
||||
'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', '+', ',' };
|
||||
|
||||
private static final byte[] pem_convert_array = new byte[256];
|
||||
|
||||
static {
|
||||
for (int j = 0; j < 255; j++)
|
||||
pem_convert_array[j] = -1;
|
||||
for (int i = 0; i < pem_array.length; i++)
|
||||
pem_convert_array[pem_array[i]] = (byte)i;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
package com.sun.mail.imap.protocol;
|
||||
|
||||
import java.io.CharArrayWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
|
||||
public class BASE64MailboxEncoder {
|
||||
protected byte[] buffer = new byte[4];
|
||||
|
||||
protected int bufsize = 0;
|
||||
|
||||
protected boolean started = false;
|
||||
|
||||
protected Writer out = null;
|
||||
|
||||
public static String encode(String original) {
|
||||
BASE64MailboxEncoder base64stream = null;
|
||||
char[] origchars = original.toCharArray();
|
||||
int length = origchars.length;
|
||||
boolean changedString = false;
|
||||
CharArrayWriter writer = new CharArrayWriter(length);
|
||||
for (int index = 0; index < length; index++) {
|
||||
char current = origchars[index];
|
||||
if (current >= ' ' && current <= '~') {
|
||||
if (base64stream != null)
|
||||
base64stream.flush();
|
||||
if (current == '&') {
|
||||
changedString = true;
|
||||
writer.write(38);
|
||||
writer.write(45);
|
||||
} else {
|
||||
writer.write(current);
|
||||
}
|
||||
} else {
|
||||
if (base64stream == null) {
|
||||
base64stream = new BASE64MailboxEncoder(writer);
|
||||
changedString = true;
|
||||
}
|
||||
base64stream.write(current);
|
||||
}
|
||||
}
|
||||
if (base64stream != null)
|
||||
base64stream.flush();
|
||||
if (changedString)
|
||||
return writer.toString();
|
||||
return original;
|
||||
}
|
||||
|
||||
public BASE64MailboxEncoder(Writer what) {
|
||||
this.out = what;
|
||||
}
|
||||
|
||||
public void write(int c) {
|
||||
try {
|
||||
if (!this.started) {
|
||||
this.started = true;
|
||||
this.out.write(38);
|
||||
}
|
||||
this.buffer[this.bufsize++] = (byte)(c >> 8);
|
||||
this.buffer[this.bufsize++] = (byte)(c & 0xFF);
|
||||
if (this.bufsize >= 3) {
|
||||
encode();
|
||||
this.bufsize -= 3;
|
||||
}
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
try {
|
||||
if (this.bufsize > 0) {
|
||||
encode();
|
||||
this.bufsize = 0;
|
||||
}
|
||||
if (this.started) {
|
||||
this.out.write(45);
|
||||
this.started = false;
|
||||
}
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
|
||||
protected void encode() throws IOException {
|
||||
if (this.bufsize == 1) {
|
||||
byte a = this.buffer[0];
|
||||
byte b = 0;
|
||||
byte c = 0;
|
||||
this.out.write(pem_array[a >>> 2 & 0x3F]);
|
||||
this.out.write(pem_array[(a << 4 & 0x30) + (b >>> 4 & 0xF)]);
|
||||
} else if (this.bufsize == 2) {
|
||||
byte a = this.buffer[0];
|
||||
byte b = this.buffer[1];
|
||||
byte c = 0;
|
||||
this.out.write(pem_array[a >>> 2 & 0x3F]);
|
||||
this.out.write(pem_array[(a << 4 & 0x30) + (b >>> 4 & 0xF)]);
|
||||
this.out.write(pem_array[(b << 2 & 0x3C) + (c >>> 6 & 0x3)]);
|
||||
} else {
|
||||
byte a = this.buffer[0];
|
||||
byte b = this.buffer[1];
|
||||
byte c = this.buffer[2];
|
||||
this.out.write(pem_array[a >>> 2 & 0x3F]);
|
||||
this.out.write(pem_array[(a << 4 & 0x30) + (b >>> 4 & 0xF)]);
|
||||
this.out.write(pem_array[(b << 2 & 0x3C) + (c >>> 6 & 0x3)]);
|
||||
this.out.write(pem_array[c & 0x3F]);
|
||||
if (this.bufsize == 4)
|
||||
this.buffer[0] = this.buffer[3];
|
||||
}
|
||||
}
|
||||
|
||||
private static final char[] pem_array = new char[] {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
|
||||
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
|
||||
'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
|
||||
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
||||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
|
||||
'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', '+', ',' };
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package com.sun.mail.imap.protocol;
|
||||
|
||||
import com.sun.mail.iap.ByteArray;
|
||||
import com.sun.mail.iap.ParsingException;
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
public class BODY implements Item {
|
||||
static final char[] name = new char[] { 'B', 'O', 'D', 'Y' };
|
||||
|
||||
private final int msgno;
|
||||
|
||||
private final ByteArray data;
|
||||
|
||||
private final String section;
|
||||
|
||||
private final int origin;
|
||||
|
||||
private final boolean isHeader;
|
||||
|
||||
public BODY(FetchResponse r) throws ParsingException {
|
||||
this.msgno = r.getNumber();
|
||||
r.skipSpaces();
|
||||
if (r.readByte() != 91)
|
||||
throw new ParsingException("BODY parse error: missing ``['' at section start");
|
||||
this.section = r.readString(']');
|
||||
if (r.readByte() != 93)
|
||||
throw new ParsingException("BODY parse error: missing ``]'' at section end");
|
||||
this.isHeader = this.section.regionMatches(true, 0, "HEADER", 0, 6);
|
||||
if (r.readByte() == 60) {
|
||||
this.origin = r.readNumber();
|
||||
r.skip(1);
|
||||
} else {
|
||||
this.origin = 0;
|
||||
}
|
||||
this.data = r.readByteArray();
|
||||
}
|
||||
|
||||
public ByteArray getByteArray() {
|
||||
return this.data;
|
||||
}
|
||||
|
||||
public ByteArrayInputStream getByteArrayInputStream() {
|
||||
if (this.data != null)
|
||||
return this.data.toByteArrayInputStream();
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isHeader() {
|
||||
return this.isHeader;
|
||||
}
|
||||
|
||||
public String getSection() {
|
||||
return this.section;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,312 @@
|
|||
package com.sun.mail.imap.protocol;
|
||||
|
||||
import com.sun.mail.iap.ParsingException;
|
||||
import com.sun.mail.iap.Response;
|
||||
import com.sun.mail.util.PropUtil;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.mail.internet.ParameterList;
|
||||
|
||||
public class BODYSTRUCTURE implements Item {
|
||||
static final char[] name = new char[] {
|
||||
'B', 'O', 'D', 'Y', 'S', 'T', 'R', 'U', 'C', 'T',
|
||||
'U', 'R', 'E' };
|
||||
|
||||
public int msgno;
|
||||
|
||||
public String type;
|
||||
|
||||
public String subtype;
|
||||
|
||||
public String encoding;
|
||||
|
||||
public int lines = -1;
|
||||
|
||||
public int size = -1;
|
||||
|
||||
public String disposition;
|
||||
|
||||
public String id;
|
||||
|
||||
public String description;
|
||||
|
||||
public String md5;
|
||||
|
||||
public String attachment;
|
||||
|
||||
public ParameterList cParams;
|
||||
|
||||
public ParameterList dParams;
|
||||
|
||||
public String[] language;
|
||||
|
||||
public BODYSTRUCTURE[] bodies;
|
||||
|
||||
public ENVELOPE envelope;
|
||||
|
||||
private static int SINGLE = 1;
|
||||
|
||||
private static int MULTI = 2;
|
||||
|
||||
private static int NESTED = 3;
|
||||
|
||||
private int processedType;
|
||||
|
||||
private static final boolean parseDebug = PropUtil.getBooleanSystemProperty("mail.imap.parse.debug", false);
|
||||
|
||||
public BODYSTRUCTURE(FetchResponse r) throws ParsingException {
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: parsing BODYSTRUCTURE");
|
||||
this.msgno = r.getNumber();
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: msgno " + this.msgno);
|
||||
r.skipSpaces();
|
||||
if (r.readByte() != 40)
|
||||
throw new ParsingException("BODYSTRUCTURE parse error: missing ``('' at start");
|
||||
if (r.peekByte() == 40) {
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: parsing multipart");
|
||||
this.type = "multipart";
|
||||
this.processedType = MULTI;
|
||||
List<BODYSTRUCTURE> v = new ArrayList<BODYSTRUCTURE>(1);
|
||||
int i = 1;
|
||||
do {
|
||||
v.add(new BODYSTRUCTURE(r));
|
||||
r.skipSpaces();
|
||||
} while (r.peekByte() == 40);
|
||||
this.bodies = v.<BODYSTRUCTURE>toArray(new BODYSTRUCTURE[v.size()]);
|
||||
this.subtype = r.readString();
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: subtype " + this.subtype);
|
||||
if (r.readByte() == 41) {
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: parse DONE");
|
||||
return;
|
||||
}
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: parsing extension data");
|
||||
this.cParams = parseParameters(r);
|
||||
if (r.readByte() == 41) {
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: body parameters DONE");
|
||||
return;
|
||||
}
|
||||
byte b = r.readByte();
|
||||
if (b == 40) {
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: parse disposition");
|
||||
this.disposition = r.readString();
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: disposition " + this.disposition);
|
||||
this.dParams = parseParameters(r);
|
||||
if (r.readByte() != 41)
|
||||
throw new ParsingException("BODYSTRUCTURE parse error: missing ``)'' at end of disposition in multipart");
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: disposition DONE");
|
||||
} else if (b == 78 || b == 110) {
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: disposition NIL");
|
||||
r.skip(2);
|
||||
} else {
|
||||
throw new ParsingException("BODYSTRUCTURE parse error: " + this.type + "/" + this.subtype + ": " + "bad multipart disposition, b " + b);
|
||||
}
|
||||
if ((b = r.readByte()) == 41) {
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: no body-fld-lang");
|
||||
return;
|
||||
}
|
||||
if (b != 32)
|
||||
throw new ParsingException("BODYSTRUCTURE parse error: missing space after disposition");
|
||||
if (r.peekByte() == 40) {
|
||||
this.language = r.readStringList();
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: language len " + this.language.length);
|
||||
} else {
|
||||
String l = r.readString();
|
||||
if (l != null) {
|
||||
String[] la = { l };
|
||||
this.language = la;
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: language " + l);
|
||||
}
|
||||
}
|
||||
while (r.readByte() == 32)
|
||||
parseBodyExtension(r);
|
||||
} else {
|
||||
if (r.peekByte() == 41)
|
||||
throw new ParsingException("BODYSTRUCTURE parse error: missing body content");
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: single part");
|
||||
this.type = r.readString();
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: type " + this.type);
|
||||
this.processedType = SINGLE;
|
||||
this.subtype = r.readString();
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: subtype " + this.subtype);
|
||||
if (this.type == null) {
|
||||
this.type = "application";
|
||||
this.subtype = "octet-stream";
|
||||
}
|
||||
this.cParams = parseParameters(r);
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: cParams " + this.cParams);
|
||||
this.id = r.readString();
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: id " + this.id);
|
||||
this.description = r.readString();
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: description " + this.description);
|
||||
this.encoding = r.readAtomString();
|
||||
if (this.encoding != null && this.encoding.equalsIgnoreCase("NIL"))
|
||||
this.encoding = null;
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: encoding " + this.encoding);
|
||||
this.size = r.readNumber();
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: size " + this.size);
|
||||
if (this.size < 0)
|
||||
throw new ParsingException("BODYSTRUCTURE parse error: bad ``size'' element");
|
||||
if (this.type.equalsIgnoreCase("text")) {
|
||||
this.lines = r.readNumber();
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: lines " + this.lines);
|
||||
if (this.lines < 0)
|
||||
throw new ParsingException("BODYSTRUCTURE parse error: bad ``lines'' element");
|
||||
} else if (this.type.equalsIgnoreCase("message") &&
|
||||
this.subtype.equalsIgnoreCase("rfc822")) {
|
||||
this.processedType = NESTED;
|
||||
r.skipSpaces();
|
||||
if (r.peekByte() == 40) {
|
||||
this.envelope = new ENVELOPE(r);
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: got envelope of nested message");
|
||||
BODYSTRUCTURE[] bs = { new BODYSTRUCTURE(r) };
|
||||
this.bodies = bs;
|
||||
this.lines = r.readNumber();
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: lines " + this.lines);
|
||||
if (this.lines < 0)
|
||||
throw new ParsingException("BODYSTRUCTURE parse error: bad ``lines'' element");
|
||||
} else if (parseDebug) {
|
||||
System.out.println("DEBUG IMAP: missing envelope and body of nested message");
|
||||
}
|
||||
} else {
|
||||
r.skipSpaces();
|
||||
byte bn = r.peekByte();
|
||||
if (Character.isDigit((char)bn))
|
||||
throw new ParsingException("BODYSTRUCTURE parse error: server erroneously included ``lines'' element with type " + this.type + "/" + this.subtype);
|
||||
}
|
||||
if (r.peekByte() == 41) {
|
||||
r.readByte();
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: parse DONE");
|
||||
return;
|
||||
}
|
||||
this.md5 = r.readString();
|
||||
if (r.readByte() == 41) {
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: no MD5 DONE");
|
||||
return;
|
||||
}
|
||||
byte b = r.readByte();
|
||||
if (b == 40) {
|
||||
this.disposition = r.readString();
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: disposition " + this.disposition);
|
||||
this.dParams = parseParameters(r);
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: dParams " + this.dParams);
|
||||
if (r.readByte() != 41)
|
||||
throw new ParsingException("BODYSTRUCTURE parse error: missing ``)'' at end of disposition");
|
||||
} else if (b == 78 || b == 110) {
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: disposition NIL");
|
||||
r.skip(2);
|
||||
} else {
|
||||
throw new ParsingException("BODYSTRUCTURE parse error: " + this.type + "/" + this.subtype + ": " + "bad single part disposition, b " + b);
|
||||
}
|
||||
if (r.readByte() == 41) {
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: disposition DONE");
|
||||
return;
|
||||
}
|
||||
if (r.peekByte() == 40) {
|
||||
this.language = r.readStringList();
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: language len " + this.language.length);
|
||||
} else {
|
||||
String l = r.readString();
|
||||
if (l != null) {
|
||||
String[] la = { l };
|
||||
this.language = la;
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: language " + l);
|
||||
}
|
||||
}
|
||||
while (r.readByte() == 32)
|
||||
parseBodyExtension(r);
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: all DONE");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isMulti() {
|
||||
return (this.processedType == MULTI);
|
||||
}
|
||||
|
||||
public boolean isSingle() {
|
||||
return (this.processedType == SINGLE);
|
||||
}
|
||||
|
||||
public boolean isNested() {
|
||||
return (this.processedType == NESTED);
|
||||
}
|
||||
|
||||
private ParameterList parseParameters(Response r) throws ParsingException {
|
||||
r.skipSpaces();
|
||||
ParameterList list = null;
|
||||
byte b = r.readByte();
|
||||
if (b == 40) {
|
||||
list = new ParameterList();
|
||||
while (true) {
|
||||
String name = r.readString();
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: parameter name " + name);
|
||||
if (name == null)
|
||||
throw new ParsingException("BODYSTRUCTURE parse error: " + this.type + "/" + this.subtype + ": " + "null name in parameter list");
|
||||
String value = r.readString();
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: parameter value " + value);
|
||||
list.set(name, value);
|
||||
if (r.readByte() == 41) {
|
||||
list.combineSegments();
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (b == 78 || b == 110) {
|
||||
if (parseDebug)
|
||||
System.out.println("DEBUG IMAP: parameter list NIL");
|
||||
r.skip(2);
|
||||
} else {
|
||||
throw new ParsingException("Parameter list parse error");
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private void parseBodyExtension(Response r) throws ParsingException {
|
||||
r.skipSpaces();
|
||||
byte b = r.peekByte();
|
||||
if (b == 40) {
|
||||
r.skip(1);
|
||||
do {
|
||||
parseBodyExtension(r);
|
||||
} while (r.readByte() != 41);
|
||||
} else if (Character.isDigit((char)b)) {
|
||||
r.readNumber();
|
||||
} else {
|
||||
r.readString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
package com.sun.mail.imap.protocol;
|
||||
|
||||
import com.sun.mail.iap.ParsingException;
|
||||
import com.sun.mail.iap.Response;
|
||||
import com.sun.mail.util.PropUtil;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.MailDateFormat;
|
||||
|
||||
public class ENVELOPE implements Item {
|
||||
static final char[] name = new char[] { 'E', 'N', 'V', 'E', 'L', 'O', 'P', 'E' };
|
||||
|
||||
public int msgno;
|
||||
|
||||
public Date date = null;
|
||||
|
||||
public String subject;
|
||||
|
||||
public InternetAddress[] from;
|
||||
|
||||
public InternetAddress[] sender;
|
||||
|
||||
public InternetAddress[] replyTo;
|
||||
|
||||
public InternetAddress[] to;
|
||||
|
||||
public InternetAddress[] cc;
|
||||
|
||||
public InternetAddress[] bcc;
|
||||
|
||||
public String inReplyTo;
|
||||
|
||||
public String messageId;
|
||||
|
||||
private static MailDateFormat mailDateFormat = new MailDateFormat();
|
||||
|
||||
private static final boolean parseDebug = PropUtil.getBooleanSystemProperty("mail.imap.parse.debug", false);
|
||||
|
||||
public ENVELOPE(FetchResponse r) throws ParsingException {
|
||||
if (parseDebug)
|
||||
System.out.println("parse ENVELOPE");
|
||||
this.msgno = r.getNumber();
|
||||
r.skipSpaces();
|
||||
if (r.readByte() != 40)
|
||||
throw new ParsingException("ENVELOPE parse error");
|
||||
String s = r.readString();
|
||||
if (s != null)
|
||||
try {
|
||||
this.date = mailDateFormat.parse(s);
|
||||
} catch (ParseException e) {
|
||||
|
||||
} catch (RuntimeException e) {}
|
||||
if (parseDebug)
|
||||
System.out.println(" Date: " + this.date);
|
||||
this.subject = r.readString();
|
||||
if (parseDebug)
|
||||
System.out.println(" Subject: " + this.subject);
|
||||
if (parseDebug)
|
||||
System.out.println(" From addresses:");
|
||||
this.from = parseAddressList(r);
|
||||
if (parseDebug)
|
||||
System.out.println(" Sender addresses:");
|
||||
this.sender = parseAddressList(r);
|
||||
if (parseDebug)
|
||||
System.out.println(" Reply-To addresses:");
|
||||
this.replyTo = parseAddressList(r);
|
||||
if (parseDebug)
|
||||
System.out.println(" To addresses:");
|
||||
this.to = parseAddressList(r);
|
||||
if (parseDebug)
|
||||
System.out.println(" Cc addresses:");
|
||||
this.cc = parseAddressList(r);
|
||||
if (parseDebug)
|
||||
System.out.println(" Bcc addresses:");
|
||||
this.bcc = parseAddressList(r);
|
||||
this.inReplyTo = r.readString();
|
||||
if (parseDebug)
|
||||
System.out.println(" In-Reply-To: " + this.inReplyTo);
|
||||
this.messageId = r.readString();
|
||||
if (parseDebug)
|
||||
System.out.println(" Message-ID: " + this.messageId);
|
||||
if (r.readByte() != 41)
|
||||
throw new ParsingException("ENVELOPE parse error");
|
||||
}
|
||||
|
||||
private InternetAddress[] parseAddressList(Response r) throws ParsingException {
|
||||
r.skipSpaces();
|
||||
byte b = r.readByte();
|
||||
if (b == 40) {
|
||||
if (r.peekByte() == 41) {
|
||||
r.skip(1);
|
||||
return null;
|
||||
}
|
||||
List<InternetAddress> v = new ArrayList<InternetAddress>();
|
||||
do {
|
||||
IMAPAddress a = new IMAPAddress(r);
|
||||
if (parseDebug)
|
||||
System.out.println(" Address: " + a);
|
||||
if (a.isEndOfGroup())
|
||||
continue;
|
||||
v.add(a);
|
||||
} while (r.peekByte() != 41);
|
||||
r.skip(1);
|
||||
return v.<InternetAddress>toArray(new InternetAddress[v.size()]);
|
||||
}
|
||||
if (b == 78 || b == 110) {
|
||||
r.skip(2);
|
||||
return null;
|
||||
}
|
||||
throw new ParsingException("ADDRESS parse error");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
package com.sun.mail.imap.protocol;
|
||||
|
||||
import com.sun.mail.iap.ParsingException;
|
||||
import javax.mail.Flags;
|
||||
|
||||
public class FLAGS extends Flags implements Item {
|
||||
static final char[] name = new char[] { 'F', 'L', 'A', 'G', 'S' };
|
||||
|
||||
public int msgno;
|
||||
|
||||
private static final long serialVersionUID = 439049847053756670L;
|
||||
|
||||
public FLAGS(IMAPResponse r) throws ParsingException {
|
||||
this.msgno = r.getNumber();
|
||||
r.skipSpaces();
|
||||
String[] flags = r.readSimpleList();
|
||||
if (flags != null)
|
||||
for (int i = 0; i < flags.length; i++) {
|
||||
String s = flags[i];
|
||||
if (s.length() >= 2 && s.charAt(0) == '\\') {
|
||||
switch (Character.toUpperCase(s.charAt(1))) {
|
||||
case 'S':
|
||||
add(Flags.Flag.SEEN);
|
||||
break;
|
||||
case 'R':
|
||||
add(Flags.Flag.RECENT);
|
||||
break;
|
||||
case 'D':
|
||||
if (s.length() >= 3) {
|
||||
char c = s.charAt(2);
|
||||
if (c == 'e' || c == 'E') {
|
||||
add(Flags.Flag.DELETED);
|
||||
break;
|
||||
}
|
||||
if (c == 'r' || c == 'R')
|
||||
add(Flags.Flag.DRAFT);
|
||||
} else {
|
||||
add(s);
|
||||
}
|
||||
break;
|
||||
case 'A':
|
||||
add(Flags.Flag.ANSWERED);
|
||||
break;
|
||||
case 'F':
|
||||
add(Flags.Flag.FLAGGED);
|
||||
break;
|
||||
case '*':
|
||||
add(Flags.Flag.USER);
|
||||
break;
|
||||
default:
|
||||
add(s);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
add(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.sun.mail.imap.protocol;
|
||||
|
||||
import com.sun.mail.iap.ParsingException;
|
||||
import javax.mail.FetchProfile;
|
||||
|
||||
public abstract class FetchItem {
|
||||
private String name;
|
||||
|
||||
private FetchProfile.Item fetchProfileItem;
|
||||
|
||||
public FetchItem(String name, FetchProfile.Item fetchProfileItem) {
|
||||
this.name = name;
|
||||
this.fetchProfileItem = fetchProfileItem;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public FetchProfile.Item getFetchProfileItem() {
|
||||
return this.fetchProfileItem;
|
||||
}
|
||||
|
||||
public abstract Object parseItem(FetchResponse paramFetchResponse) throws ParsingException;
|
||||
}
|
||||
|
|
@ -0,0 +1,215 @@
|
|||
package com.sun.mail.imap.protocol;
|
||||
|
||||
import com.sun.mail.iap.ParsingException;
|
||||
import com.sun.mail.iap.Protocol;
|
||||
import com.sun.mail.iap.ProtocolException;
|
||||
import com.sun.mail.iap.Response;
|
||||
import com.sun.mail.util.ASCIIUtility;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class FetchResponse extends IMAPResponse {
|
||||
private Item[] items;
|
||||
|
||||
private Map extensionItems;
|
||||
|
||||
private final FetchItem[] fitems;
|
||||
|
||||
public FetchResponse(Protocol p) throws IOException, ProtocolException {
|
||||
super(p);
|
||||
this.fitems = null;
|
||||
parse();
|
||||
}
|
||||
|
||||
public FetchResponse(IMAPResponse r) throws IOException, ProtocolException {
|
||||
this(r, null);
|
||||
}
|
||||
|
||||
public FetchResponse(IMAPResponse r, FetchItem[] fitems) throws IOException, ProtocolException {
|
||||
super(r);
|
||||
this.fitems = fitems;
|
||||
parse();
|
||||
}
|
||||
|
||||
public int getItemCount() {
|
||||
return this.items.length;
|
||||
}
|
||||
|
||||
public Item getItem(int index) {
|
||||
return this.items[index];
|
||||
}
|
||||
|
||||
public <T extends Item> T getItem(Class<T> c) {
|
||||
for (int i = 0; i < this.items.length; i++) {
|
||||
if (c.isInstance(this.items[i]))
|
||||
return c.cast(this.items[i]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static <T extends Item> T getItem(Response[] r, int msgno, Class<T> c) {
|
||||
if (r == null)
|
||||
return null;
|
||||
for (int i = 0; i < r.length; i++) {
|
||||
if (r[i] != null && r[i] instanceof FetchResponse && ((FetchResponse)r[i])
|
||||
|
||||
.getNumber() == msgno) {
|
||||
FetchResponse f = (FetchResponse)r[i];
|
||||
for (int j = 0; j < f.items.length; j++) {
|
||||
if (c.isInstance(f.items[j]))
|
||||
return c.cast(f.items[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static <T extends Item> List<T> getItems(Response[] r, int msgno, Class<T> c) {
|
||||
List<T> items = new ArrayList<T>();
|
||||
if (r == null)
|
||||
return items;
|
||||
for (int i = 0; i < r.length; i++) {
|
||||
if (r[i] != null && r[i] instanceof FetchResponse && ((FetchResponse)r[i])
|
||||
|
||||
.getNumber() == msgno) {
|
||||
FetchResponse f = (FetchResponse)r[i];
|
||||
for (int j = 0; j < f.items.length; j++) {
|
||||
if (c.isInstance(f.items[j]))
|
||||
items.add(c.cast(f.items[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
public Map getExtensionItems() {
|
||||
if (this.extensionItems == null)
|
||||
this.extensionItems = new HashMap();
|
||||
return this.extensionItems;
|
||||
}
|
||||
|
||||
private static final char[] HEADER = new char[] { '.', 'H', 'E', 'A', 'D', 'E', 'R' };
|
||||
|
||||
private static final char[] TEXT = new char[] { '.', 'T', 'E', 'X', 'T' };
|
||||
|
||||
private void parse() throws ParsingException {
|
||||
skipSpaces();
|
||||
if (this.buffer[this.index] != 40)
|
||||
throw new ParsingException("error in FETCH parsing, missing '(' at index " + this.index);
|
||||
List<Item> v = new ArrayList<Item>();
|
||||
Item i = null;
|
||||
do {
|
||||
this.index++;
|
||||
if (this.index >= this.size)
|
||||
throw new ParsingException("error in FETCH parsing, ran off end of buffer, size " + this.size);
|
||||
i = parseItem();
|
||||
if (i != null) {
|
||||
v.add(i);
|
||||
} else if (!parseExtensionItem()) {
|
||||
throw new ParsingException("error in FETCH parsing, unrecognized item at index " + this.index + ", starts with \"" +
|
||||
|
||||
next20() + "\"");
|
||||
}
|
||||
} while (this.buffer[this.index] != 41);
|
||||
this.index++;
|
||||
this.items = v.<Item>toArray(new Item[v.size()]);
|
||||
}
|
||||
|
||||
private String next20() {
|
||||
if (this.index + 20 > this.size)
|
||||
return ASCIIUtility.toString(this.buffer, this.index, this.index + this.size);
|
||||
return ASCIIUtility.toString(this.buffer, this.index, this.index + 20) + "...";
|
||||
}
|
||||
|
||||
private Item parseItem() throws ParsingException {
|
||||
switch (this.buffer[this.index]) {
|
||||
case 69:
|
||||
case 101:
|
||||
if (match(ENVELOPE.name))
|
||||
return new ENVELOPE(this);
|
||||
break;
|
||||
case 70:
|
||||
case 102:
|
||||
if (match(FLAGS.name))
|
||||
return new FLAGS(this);
|
||||
break;
|
||||
case 73:
|
||||
case 105:
|
||||
if (match(INTERNALDATE.name))
|
||||
return new INTERNALDATE(this);
|
||||
break;
|
||||
case 66:
|
||||
case 98:
|
||||
if (match(BODYSTRUCTURE.name))
|
||||
return new BODYSTRUCTURE(this);
|
||||
if (match(BODY.name)) {
|
||||
if (this.buffer[this.index] == 91)
|
||||
return new BODY(this);
|
||||
return new BODYSTRUCTURE(this);
|
||||
}
|
||||
break;
|
||||
case 82:
|
||||
case 114:
|
||||
if (match(RFC822SIZE.name))
|
||||
return new RFC822SIZE(this);
|
||||
if (match(RFC822DATA.name)) {
|
||||
boolean isHeader = false;
|
||||
if (match(HEADER)) {
|
||||
isHeader = true;
|
||||
} else if (match(TEXT)) {
|
||||
|
||||
}
|
||||
return new RFC822DATA(this, isHeader);
|
||||
}
|
||||
break;
|
||||
case 85:
|
||||
case 117:
|
||||
if (match(UID.name))
|
||||
return new UID(this);
|
||||
break;
|
||||
case 77:
|
||||
case 109:
|
||||
if (match(MODSEQ.name))
|
||||
return new MODSEQ(this);
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean parseExtensionItem() throws ParsingException {
|
||||
if (this.fitems == null)
|
||||
return false;
|
||||
for (int i = 0; i < this.fitems.length; i++) {
|
||||
if (match(this.fitems[i].getName())) {
|
||||
getExtensionItems().put(this.fitems[i].getName(), this.fitems[i]
|
||||
.parseItem(this));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean match(char[] itemName) {
|
||||
int len = itemName.length;
|
||||
for (int i = 0, j = this.index; i < len;) {
|
||||
if (Character.toUpperCase((char)this.buffer[j++]) != itemName[i++])
|
||||
return false;
|
||||
}
|
||||
this.index += len;
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean match(String itemName) {
|
||||
int len = itemName.length();
|
||||
for (int i = 0, j = this.index; i < len;) {
|
||||
if (Character.toUpperCase((char)this.buffer[j++]) !=
|
||||
itemName.charAt(i++))
|
||||
return false;
|
||||
}
|
||||
this.index += len;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
package com.sun.mail.imap.protocol;
|
||||
|
||||
import com.sun.mail.iap.Argument;
|
||||
import com.sun.mail.iap.ProtocolException;
|
||||
import com.sun.mail.iap.Response;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class ID {
|
||||
private Map<String, String> serverParams = null;
|
||||
|
||||
public ID(Response r) throws ProtocolException {
|
||||
r.skipSpaces();
|
||||
int c = r.peekByte();
|
||||
if (c == 78 || c == 110)
|
||||
return;
|
||||
if (c != 40)
|
||||
throw new ProtocolException("Missing '(' at start of ID");
|
||||
this.serverParams = new HashMap<String, String>();
|
||||
String[] v = r.readStringList();
|
||||
if (v != null)
|
||||
for (int i = 0; i < v.length; i += 2) {
|
||||
String name = v[i];
|
||||
if (name == null)
|
||||
throw new ProtocolException("ID field name null");
|
||||
if (i + 1 >= v.length)
|
||||
throw new ProtocolException("ID field without value: " + name);
|
||||
String value = v[i + 1];
|
||||
this.serverParams.put(name, value);
|
||||
}
|
||||
this.serverParams = Collections.<String, String>unmodifiableMap(this.serverParams);
|
||||
}
|
||||
|
||||
Map<String, String> getServerParams() {
|
||||
return this.serverParams;
|
||||
}
|
||||
|
||||
static Argument getArgumentList(Map<String, String> clientParams) {
|
||||
Argument arg = new Argument();
|
||||
if (clientParams == null) {
|
||||
arg.writeAtom("NIL");
|
||||
return arg;
|
||||
}
|
||||
Argument list = new Argument();
|
||||
for (Map.Entry<String, String> e : clientParams.entrySet()) {
|
||||
list.writeNString(e.getKey());
|
||||
list.writeNString(e.getValue());
|
||||
}
|
||||
arg.writeArgument(list);
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
package com.sun.mail.imap.protocol;
|
||||
|
||||
import com.sun.mail.iap.ParsingException;
|
||||
import com.sun.mail.iap.Response;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.mail.internet.AddressException;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
|
||||
class IMAPAddress extends InternetAddress {
|
||||
private boolean group = false;
|
||||
|
||||
private InternetAddress[] grouplist;
|
||||
|
||||
private String groupname;
|
||||
|
||||
private static final long serialVersionUID = -3835822029483122232L;
|
||||
|
||||
IMAPAddress(Response r) throws ParsingException {
|
||||
r.skipSpaces();
|
||||
if (r.readByte() != 40)
|
||||
throw new ParsingException("ADDRESS parse error");
|
||||
this.encodedPersonal = r.readString();
|
||||
r.readString();
|
||||
String mb = r.readString();
|
||||
String host = r.readString();
|
||||
r.skipSpaces();
|
||||
if (r.readByte() != 41)
|
||||
throw new ParsingException("ADDRESS parse error");
|
||||
if (host == null) {
|
||||
this.group = true;
|
||||
this.groupname = mb;
|
||||
if (this.groupname == null)
|
||||
return;
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(this.groupname).append(':');
|
||||
List<InternetAddress> v = new ArrayList<InternetAddress>();
|
||||
while (r.peekByte() != 41) {
|
||||
IMAPAddress a = new IMAPAddress(r);
|
||||
if (a.isEndOfGroup())
|
||||
break;
|
||||
if (v.size() != 0)
|
||||
sb.append(',');
|
||||
sb.append(a.toString());
|
||||
v.add(a);
|
||||
}
|
||||
sb.append(';');
|
||||
this.address = sb.toString();
|
||||
this.grouplist = v.<InternetAddress>toArray(new IMAPAddress[v.size()]);
|
||||
} else if (mb == null || mb.length() == 0) {
|
||||
this.address = host;
|
||||
} else if (host.length() == 0) {
|
||||
this.address = mb;
|
||||
} else {
|
||||
this.address = mb + "@" + host;
|
||||
}
|
||||
}
|
||||
|
||||
boolean isEndOfGroup() {
|
||||
return (this.group && this.groupname == null);
|
||||
}
|
||||
|
||||
public boolean isGroup() {
|
||||
return this.group;
|
||||
}
|
||||
|
||||
public InternetAddress[] getGroup(boolean strict) throws AddressException {
|
||||
if (this.grouplist == null)
|
||||
return null;
|
||||
return (InternetAddress[])this.grouplist.clone();
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,77 @@
|
|||
package com.sun.mail.imap.protocol;
|
||||
|
||||
import com.sun.mail.iap.Protocol;
|
||||
import com.sun.mail.iap.ProtocolException;
|
||||
import com.sun.mail.iap.Response;
|
||||
import com.sun.mail.util.ASCIIUtility;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class IMAPResponse extends Response {
|
||||
private String key;
|
||||
|
||||
private int number;
|
||||
|
||||
public IMAPResponse(Protocol c) throws IOException, ProtocolException {
|
||||
super(c);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() throws IOException, ProtocolException {
|
||||
if (isUnTagged() && !isOK() && !isNO() && !isBAD() && !isBYE()) {
|
||||
this.key = readAtom();
|
||||
try {
|
||||
this.number = Integer.parseInt(this.key);
|
||||
this.key = readAtom();
|
||||
} catch (NumberFormatException e) {}
|
||||
}
|
||||
}
|
||||
|
||||
public IMAPResponse(IMAPResponse r) {
|
||||
super(r);
|
||||
this.key = r.key;
|
||||
this.number = r.number;
|
||||
}
|
||||
|
||||
public IMAPResponse(String r) throws IOException, ProtocolException {
|
||||
super(r);
|
||||
init();
|
||||
}
|
||||
|
||||
public String[] readSimpleList() {
|
||||
skipSpaces();
|
||||
if (this.buffer[this.index] != 40)
|
||||
return null;
|
||||
this.index++;
|
||||
List<String> v = new ArrayList<String>();
|
||||
int start;
|
||||
for (start = this.index; this.buffer[this.index] != 41; this.index++) {
|
||||
if (this.buffer[this.index] == 32) {
|
||||
v.add(ASCIIUtility.toString(this.buffer, start, this.index));
|
||||
start = this.index + 1;
|
||||
}
|
||||
}
|
||||
if (this.index > start)
|
||||
v.add(ASCIIUtility.toString(this.buffer, start, this.index));
|
||||
this.index++;
|
||||
int size = v.size();
|
||||
if (size > 0)
|
||||
return v.<String>toArray(new String[size]);
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return this.key;
|
||||
}
|
||||
|
||||
public boolean keyEquals(String k) {
|
||||
if (this.key != null && this.key.equalsIgnoreCase(k))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getNumber() {
|
||||
return this.number;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,210 @@
|
|||
package com.sun.mail.imap.protocol;
|
||||
|
||||
import com.sun.mail.auth.OAuth2SaslClientFactory;
|
||||
import com.sun.mail.iap.Argument;
|
||||
import com.sun.mail.iap.ProtocolException;
|
||||
import com.sun.mail.iap.Response;
|
||||
import com.sun.mail.util.ASCIIUtility;
|
||||
import com.sun.mail.util.BASE64DecoderStream;
|
||||
import com.sun.mail.util.BASE64EncoderStream;
|
||||
import com.sun.mail.util.MailLogger;
|
||||
import com.sun.mail.util.PropUtil;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.logging.Level;
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
import javax.security.auth.callback.NameCallback;
|
||||
import javax.security.auth.callback.PasswordCallback;
|
||||
import javax.security.sasl.RealmCallback;
|
||||
import javax.security.sasl.RealmChoiceCallback;
|
||||
import javax.security.sasl.Sasl;
|
||||
import javax.security.sasl.SaslClient;
|
||||
import javax.security.sasl.SaslException;
|
||||
|
||||
public class IMAPSaslAuthenticator implements SaslAuthenticator {
|
||||
private IMAPProtocol pr;
|
||||
|
||||
private String name;
|
||||
|
||||
private Properties props;
|
||||
|
||||
private MailLogger logger;
|
||||
|
||||
private String host;
|
||||
|
||||
static {
|
||||
try {
|
||||
OAuth2SaslClientFactory.init();
|
||||
} catch (Throwable e) {}
|
||||
}
|
||||
|
||||
public IMAPSaslAuthenticator(IMAPProtocol pr, String name, Properties props, MailLogger logger, String host) {
|
||||
this.pr = pr;
|
||||
this.name = name;
|
||||
this.props = props;
|
||||
this.logger = logger;
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
public boolean authenticate(String[] mechs, final String realm, String authzid, final String u, final String p) throws ProtocolException {
|
||||
synchronized (this.pr) {
|
||||
SaslClient sc;
|
||||
List<Response> v = new ArrayList<Response>();
|
||||
String tag = null;
|
||||
Response r = null;
|
||||
boolean done = false;
|
||||
if (this.logger.isLoggable(Level.FINE)) {
|
||||
this.logger.fine("SASL Mechanisms:");
|
||||
for (int i = 0; i < mechs.length; i++)
|
||||
this.logger.fine(" " + mechs[i]);
|
||||
this.logger.fine("");
|
||||
}
|
||||
CallbackHandler cbh = new CallbackHandler() {
|
||||
public void handle(Callback[] callbacks) {
|
||||
if (IMAPSaslAuthenticator.this.logger.isLoggable(Level.FINE))
|
||||
IMAPSaslAuthenticator.this.logger.fine("SASL callback length: " + callbacks.length);
|
||||
for (int i = 0; i < callbacks.length; i++) {
|
||||
if (IMAPSaslAuthenticator.this.logger.isLoggable(Level.FINE))
|
||||
IMAPSaslAuthenticator.this.logger.fine("SASL callback " + i + ": " + callbacks[i]);
|
||||
if (callbacks[i] instanceof NameCallback) {
|
||||
NameCallback ncb = (NameCallback)callbacks[i];
|
||||
ncb.setName(u);
|
||||
} else if (callbacks[i] instanceof PasswordCallback) {
|
||||
PasswordCallback pcb = (PasswordCallback)callbacks[i];
|
||||
pcb.setPassword(p.toCharArray());
|
||||
} else if (callbacks[i] instanceof RealmCallback) {
|
||||
RealmCallback rcb = (RealmCallback)callbacks[i];
|
||||
rcb.setText((realm != null) ? realm :
|
||||
rcb.getDefaultText());
|
||||
} else if (callbacks[i] instanceof RealmChoiceCallback) {
|
||||
RealmChoiceCallback rcb = (RealmChoiceCallback)callbacks[i];
|
||||
if (realm == null) {
|
||||
rcb.setSelectedIndex(rcb.getDefaultChoice());
|
||||
} else {
|
||||
String[] choices = rcb.getChoices();
|
||||
for (int k = 0; k < choices.length; k++) {
|
||||
if (choices[k].equals(realm)) {
|
||||
rcb.setSelectedIndex(k);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
try {
|
||||
sc = Sasl.createSaslClient(mechs, authzid, this.name, this.host, (Map<String, ?>)this.props, cbh);
|
||||
} catch (SaslException sex) {
|
||||
this.logger.log(Level.FINE, "Failed to create SASL client", (Throwable)sex);
|
||||
throw new UnsupportedOperationException(sex.getMessage(), sex);
|
||||
}
|
||||
if (sc == null) {
|
||||
this.logger.fine("No SASL support");
|
||||
throw new UnsupportedOperationException("No SASL support");
|
||||
}
|
||||
if (this.logger.isLoggable(Level.FINE))
|
||||
this.logger.fine("SASL client " + sc.getMechanismName());
|
||||
try {
|
||||
Argument args = new Argument();
|
||||
args.writeAtom(sc.getMechanismName());
|
||||
if (this.pr.hasCapability("SASL-IR") && sc.hasInitialResponse()) {
|
||||
String irs;
|
||||
byte[] ba = sc.evaluateChallenge(new byte[0]);
|
||||
if (ba.length > 0) {
|
||||
ba = BASE64EncoderStream.encode(ba);
|
||||
irs = ASCIIUtility.toString(ba, 0, ba.length);
|
||||
} else {
|
||||
irs = "=";
|
||||
}
|
||||
args.writeAtom(irs);
|
||||
}
|
||||
tag = this.pr.writeCommand("AUTHENTICATE", args);
|
||||
} catch (Exception ex) {
|
||||
this.logger.log(Level.FINE, "SASL AUTHENTICATE Exception", (Throwable)ex);
|
||||
return false;
|
||||
}
|
||||
OutputStream os = this.pr.getIMAPOutputStream();
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
byte[] CRLF = { 13, 10 };
|
||||
boolean isXGWTRUSTEDAPP = (
|
||||
sc.getMechanismName().equals("XGWTRUSTEDAPP") &&
|
||||
PropUtil.getBooleanProperty(this.props, "mail." + this.name + ".sasl.xgwtrustedapphack.enable", true));
|
||||
while (!done) {
|
||||
try {
|
||||
r = this.pr.readResponse();
|
||||
if (r.isContinuation()) {
|
||||
byte[] ba = null;
|
||||
if (!sc.isComplete()) {
|
||||
ba = r.readByteArray().getNewBytes();
|
||||
if (ba.length > 0)
|
||||
ba = BASE64DecoderStream.decode(ba);
|
||||
if (this.logger.isLoggable(Level.FINE))
|
||||
this.logger.fine("SASL challenge: " +
|
||||
ASCIIUtility.toString(ba, 0, ba.length) + " :");
|
||||
ba = sc.evaluateChallenge(ba);
|
||||
}
|
||||
if (ba == null) {
|
||||
this.logger.fine("SASL no response");
|
||||
os.write(CRLF);
|
||||
os.flush();
|
||||
bos.reset();
|
||||
continue;
|
||||
}
|
||||
if (this.logger.isLoggable(Level.FINE))
|
||||
this.logger.fine("SASL response: " +
|
||||
ASCIIUtility.toString(ba, 0, ba.length) + " :");
|
||||
ba = BASE64EncoderStream.encode(ba);
|
||||
if (isXGWTRUSTEDAPP)
|
||||
bos.write(ASCIIUtility.getBytes("XGWTRUSTEDAPP "));
|
||||
bos.write(ba);
|
||||
bos.write(CRLF);
|
||||
os.write(bos.toByteArray());
|
||||
os.flush();
|
||||
bos.reset();
|
||||
continue;
|
||||
}
|
||||
if (r.isTagged() && r.getTag().equals(tag)) {
|
||||
done = true;
|
||||
continue;
|
||||
}
|
||||
if (r.isBYE()) {
|
||||
done = true;
|
||||
continue;
|
||||
}
|
||||
v.add(r);
|
||||
} catch (Exception ioex) {
|
||||
this.logger.log(Level.FINE, "SASL Exception", (Throwable)ioex);
|
||||
r = Response.byeResponse(ioex);
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
if (sc.isComplete()) {
|
||||
String qop = (String)sc.getNegotiatedProperty("javax.security.sasl.qop");
|
||||
if (qop != null && (qop.equalsIgnoreCase("auth-int") ||
|
||||
qop.equalsIgnoreCase("auth-conf"))) {
|
||||
this.logger.fine("SASL Mechanism requires integrity or confidentiality");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Response[] responses = v.<Response>toArray(new Response[v.size()]);
|
||||
this.pr.notifyResponseHandlers(responses);
|
||||
this.pr.handleResult(r);
|
||||
this.pr.setCapabilities(r);
|
||||
if (isXGWTRUSTEDAPP && authzid != null) {
|
||||
Argument args = new Argument();
|
||||
args.writeString(authzid);
|
||||
responses = this.pr.command("LOGIN", args);
|
||||
this.pr.notifyResponseHandlers(responses);
|
||||
this.pr.handleResult(responses[responses.length - 1]);
|
||||
this.pr.setCapabilities(responses[responses.length - 1]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
package com.sun.mail.imap.protocol;
|
||||
|
||||
import com.sun.mail.iap.ParsingException;
|
||||
import java.text.FieldPosition;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
import javax.mail.internet.MailDateFormat;
|
||||
|
||||
public class INTERNALDATE implements Item {
|
||||
static final char[] name = new char[] {
|
||||
'I', 'N', 'T', 'E', 'R', 'N', 'A', 'L', 'D', 'A',
|
||||
'T', 'E' };
|
||||
|
||||
public int msgno;
|
||||
|
||||
protected Date date;
|
||||
|
||||
private static MailDateFormat mailDateFormat = new MailDateFormat();
|
||||
|
||||
public INTERNALDATE(FetchResponse r) throws ParsingException {
|
||||
this.msgno = r.getNumber();
|
||||
r.skipSpaces();
|
||||
String s = r.readString();
|
||||
if (s == null)
|
||||
throw new ParsingException("INTERNALDATE is NIL");
|
||||
try {
|
||||
this.date = mailDateFormat.parse(s);
|
||||
} catch (ParseException pex) {
|
||||
throw new ParsingException("INTERNALDATE parse error");
|
||||
}
|
||||
}
|
||||
|
||||
public Date getDate() {
|
||||
return this.date;
|
||||
}
|
||||
|
||||
private static SimpleDateFormat df = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss ", Locale.US);
|
||||
|
||||
public static String format(Date d) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
synchronized (df) {
|
||||
df.format(d, sb, new FieldPosition(0));
|
||||
}
|
||||
TimeZone tz = TimeZone.getDefault();
|
||||
int offset = tz.getOffset(d.getTime());
|
||||
int rawOffsetInMins = offset / 60 / 1000;
|
||||
if (rawOffsetInMins < 0) {
|
||||
sb.append('-');
|
||||
rawOffsetInMins = -rawOffsetInMins;
|
||||
} else {
|
||||
sb.append('+');
|
||||
}
|
||||
int offsetInHrs = rawOffsetInMins / 60;
|
||||
int offsetInMins = rawOffsetInMins % 60;
|
||||
sb.append(Character.forDigit(offsetInHrs / 10, 10));
|
||||
sb.append(Character.forDigit(offsetInHrs % 10, 10));
|
||||
sb.append(Character.forDigit(offsetInMins / 10, 10));
|
||||
sb.append(Character.forDigit(offsetInMins % 10, 10));
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
package com.sun.mail.imap.protocol;
|
||||
|
||||
public interface Item {}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package com.sun.mail.imap.protocol;
|
||||
|
||||
import com.sun.mail.iap.ParsingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ListInfo {
|
||||
public String name = null;
|
||||
|
||||
public char separator = '/';
|
||||
|
||||
public boolean hasInferiors = true;
|
||||
|
||||
public boolean canOpen = true;
|
||||
|
||||
public int changeState = 3;
|
||||
|
||||
public String[] attrs;
|
||||
|
||||
public static final int CHANGED = 1;
|
||||
|
||||
public static final int UNCHANGED = 2;
|
||||
|
||||
public static final int INDETERMINATE = 3;
|
||||
|
||||
public ListInfo(IMAPResponse r) throws ParsingException {
|
||||
String[] s = r.readSimpleList();
|
||||
List<String> v = new ArrayList<String>();
|
||||
if (s != null)
|
||||
for (int i = 0; i < s.length; i++) {
|
||||
if (s[i].equalsIgnoreCase("\\Marked")) {
|
||||
this.changeState = 1;
|
||||
} else if (s[i].equalsIgnoreCase("\\Unmarked")) {
|
||||
this.changeState = 2;
|
||||
} else if (s[i].equalsIgnoreCase("\\Noselect")) {
|
||||
this.canOpen = false;
|
||||
} else if (s[i].equalsIgnoreCase("\\Noinferiors")) {
|
||||
this.hasInferiors = false;
|
||||
}
|
||||
v.add(s[i]);
|
||||
}
|
||||
this.attrs = v.<String>toArray(new String[v.size()]);
|
||||
r.skipSpaces();
|
||||
if (r.readByte() == 34) {
|
||||
if ((this.separator = (char)r.readByte()) == '\\')
|
||||
this.separator = (char)r.readByte();
|
||||
r.skip(1);
|
||||
} else {
|
||||
r.skip(2);
|
||||
}
|
||||
r.skipSpaces();
|
||||
this.name = r.readAtomString();
|
||||
this.name = BASE64MailboxDecoder.decode(this.name);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package com.sun.mail.imap.protocol;
|
||||
|
||||
import com.sun.mail.iap.ParsingException;
|
||||
|
||||
public class MODSEQ implements Item {
|
||||
static final char[] name = new char[] { 'M', 'O', 'D', 'S', 'E', 'Q' };
|
||||
|
||||
public int seqnum;
|
||||
|
||||
public long modseq;
|
||||
|
||||
public MODSEQ(FetchResponse r) throws ParsingException {
|
||||
this.seqnum = r.getNumber();
|
||||
r.skipSpaces();
|
||||
if (r.readByte() != 40)
|
||||
throw new ParsingException("MODSEQ parse error");
|
||||
this.modseq = r.readLong();
|
||||
if (r.readByte() != 41)
|
||||
throw new ParsingException("MODSEQ parse error");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
package com.sun.mail.imap.protocol;
|
||||
|
||||
import com.sun.mail.iap.ParsingException;
|
||||
import com.sun.mail.iap.Response;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.mail.Flags;
|
||||
|
||||
public class MailboxInfo {
|
||||
public Flags availableFlags = null;
|
||||
|
||||
public Flags permanentFlags = null;
|
||||
|
||||
public int total = -1;
|
||||
|
||||
public int recent = -1;
|
||||
|
||||
public int first = -1;
|
||||
|
||||
public long uidvalidity = -1L;
|
||||
|
||||
public long uidnext = -1L;
|
||||
|
||||
public long highestmodseq = -1L;
|
||||
|
||||
public int mode;
|
||||
|
||||
public List<IMAPResponse> responses;
|
||||
|
||||
public MailboxInfo(Response[] r) throws ParsingException {
|
||||
for (int i = 0; i < r.length; i++) {
|
||||
if (r[i] != null && r[i] instanceof IMAPResponse) {
|
||||
IMAPResponse ir = (IMAPResponse)r[i];
|
||||
if (ir.keyEquals("EXISTS")) {
|
||||
this.total = ir.getNumber();
|
||||
r[i] = null;
|
||||
} else if (ir.keyEquals("RECENT")) {
|
||||
this.recent = ir.getNumber();
|
||||
r[i] = null;
|
||||
} else if (ir.keyEquals("FLAGS")) {
|
||||
this.availableFlags = new FLAGS(ir);
|
||||
r[i] = null;
|
||||
} else if (ir.keyEquals("VANISHED")) {
|
||||
if (this.responses == null)
|
||||
this.responses = new ArrayList<IMAPResponse>();
|
||||
this.responses.add(ir);
|
||||
r[i] = null;
|
||||
} else if (ir.keyEquals("FETCH")) {
|
||||
if (this.responses == null)
|
||||
this.responses = new ArrayList<IMAPResponse>();
|
||||
this.responses.add(ir);
|
||||
r[i] = null;
|
||||
} else if (ir.isUnTagged() && ir.isOK()) {
|
||||
ir.skipSpaces();
|
||||
if (ir.readByte() != 91) {
|
||||
ir.reset();
|
||||
} else {
|
||||
boolean handled = true;
|
||||
String s = ir.readAtom();
|
||||
if (s.equalsIgnoreCase("UNSEEN")) {
|
||||
this.first = ir.readNumber();
|
||||
} else if (s.equalsIgnoreCase("UIDVALIDITY")) {
|
||||
this.uidvalidity = ir.readLong();
|
||||
} else if (s.equalsIgnoreCase("PERMANENTFLAGS")) {
|
||||
this.permanentFlags = new FLAGS(ir);
|
||||
} else if (s.equalsIgnoreCase("UIDNEXT")) {
|
||||
this.uidnext = ir.readLong();
|
||||
} else if (s.equalsIgnoreCase("HIGHESTMODSEQ")) {
|
||||
this.highestmodseq = ir.readLong();
|
||||
} else {
|
||||
handled = false;
|
||||
}
|
||||
if (handled) {
|
||||
r[i] = null;
|
||||
} else {
|
||||
ir.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.permanentFlags == null)
|
||||
if (this.availableFlags != null) {
|
||||
this.permanentFlags = new Flags(this.availableFlags);
|
||||
} else {
|
||||
this.permanentFlags = new Flags();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
package com.sun.mail.imap.protocol;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class MessageSet {
|
||||
public int start;
|
||||
|
||||
public int end;
|
||||
|
||||
public MessageSet() {}
|
||||
|
||||
public MessageSet(int start, int end) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return this.end - this.start + 1;
|
||||
}
|
||||
|
||||
public static MessageSet[] createMessageSets(int[] msgs) {
|
||||
List<MessageSet> v = new ArrayList<MessageSet>();
|
||||
for (int i = 0; i < msgs.length; i++) {
|
||||
MessageSet ms = new MessageSet();
|
||||
ms.start = msgs[i];
|
||||
int j;
|
||||
for (j = i + 1; j < msgs.length &&
|
||||
msgs[j] == msgs[j - 1] + 1; j++);
|
||||
ms.end = msgs[j - 1];
|
||||
v.add(ms);
|
||||
i = j - 1;
|
||||
}
|
||||
return v.<MessageSet>toArray(new MessageSet[v.size()]);
|
||||
}
|
||||
|
||||
public static String toString(MessageSet[] msgsets) {
|
||||
if (msgsets == null || msgsets.length == 0)
|
||||
return null;
|
||||
int i = 0;
|
||||
StringBuffer s = new StringBuffer();
|
||||
int size = msgsets.length;
|
||||
while (true) {
|
||||
int start = (msgsets[i]).start;
|
||||
int end = (msgsets[i]).end;
|
||||
if (end > start) {
|
||||
s.append(start).append(':').append(end);
|
||||
} else {
|
||||
s.append(start);
|
||||
}
|
||||
i++;
|
||||
if (i >= size)
|
||||
break;
|
||||
s.append(',');
|
||||
}
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
public static int size(MessageSet[] msgsets) {
|
||||
int count = 0;
|
||||
if (msgsets == null)
|
||||
return 0;
|
||||
for (int i = 0; i < msgsets.length; i++)
|
||||
count += msgsets[i].size();
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
package com.sun.mail.imap.protocol;
|
||||
|
||||
import com.sun.mail.iap.ProtocolException;
|
||||
import com.sun.mail.iap.Response;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Namespaces {
|
||||
public Namespace[] personal;
|
||||
|
||||
public Namespace[] otherUsers;
|
||||
|
||||
public Namespace[] shared;
|
||||
|
||||
public static class Namespace {
|
||||
public String prefix;
|
||||
|
||||
public char delimiter;
|
||||
|
||||
public Namespace(Response r) throws ProtocolException {
|
||||
if (r.readByte() != 40)
|
||||
throw new ProtocolException("Missing '(' at start of Namespace");
|
||||
this.prefix = BASE64MailboxDecoder.decode(r.readString());
|
||||
r.skipSpaces();
|
||||
if (r.peekByte() == 34) {
|
||||
r.readByte();
|
||||
this.delimiter = (char)r.readByte();
|
||||
if (this.delimiter == '\\')
|
||||
this.delimiter = (char)r.readByte();
|
||||
if (r.readByte() != 34)
|
||||
throw new ProtocolException("Missing '\"' at end of QUOTED_CHAR");
|
||||
} else {
|
||||
String s = r.readAtom();
|
||||
if (s == null)
|
||||
throw new ProtocolException("Expected NIL, got null");
|
||||
if (!s.equalsIgnoreCase("NIL"))
|
||||
throw new ProtocolException("Expected NIL, got " + s);
|
||||
this.delimiter = '\000';
|
||||
}
|
||||
if (r.peekByte() != 41) {
|
||||
r.skipSpaces();
|
||||
r.readString();
|
||||
r.skipSpaces();
|
||||
r.readStringList();
|
||||
}
|
||||
if (r.readByte() != 41)
|
||||
throw new ProtocolException("Missing ')' at end of Namespace");
|
||||
}
|
||||
}
|
||||
|
||||
public Namespaces(Response r) throws ProtocolException {
|
||||
this.personal = getNamespaces(r);
|
||||
this.otherUsers = getNamespaces(r);
|
||||
this.shared = getNamespaces(r);
|
||||
}
|
||||
|
||||
private Namespace[] getNamespaces(Response r) throws ProtocolException {
|
||||
r.skipSpaces();
|
||||
if (r.peekByte() == 40) {
|
||||
List<Namespace> v = new ArrayList<Namespace>();
|
||||
r.readByte();
|
||||
while (true) {
|
||||
Namespace ns = new Namespace(r);
|
||||
v.add(ns);
|
||||
if (r.peekByte() == 41) {
|
||||
r.readByte();
|
||||
return v.<Namespace>toArray(new Namespace[v.size()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
String s = r.readAtom();
|
||||
if (s == null)
|
||||
throw new ProtocolException("Expected NIL, got null");
|
||||
if (!s.equalsIgnoreCase("NIL"))
|
||||
throw new ProtocolException("Expected NIL, got " + s);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package com.sun.mail.imap.protocol;
|
||||
|
||||
import com.sun.mail.iap.ByteArray;
|
||||
import com.sun.mail.iap.ParsingException;
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
public class RFC822DATA implements Item {
|
||||
static final char[] name = new char[] { 'R', 'F', 'C', '8', '2', '2' };
|
||||
|
||||
private final int msgno;
|
||||
|
||||
private final ByteArray data;
|
||||
|
||||
private final boolean isHeader;
|
||||
|
||||
public RFC822DATA(FetchResponse r) throws ParsingException {
|
||||
this(r, false);
|
||||
}
|
||||
|
||||
public RFC822DATA(FetchResponse r, boolean isHeader) throws ParsingException {
|
||||
this.isHeader = isHeader;
|
||||
this.msgno = r.getNumber();
|
||||
r.skipSpaces();
|
||||
this.data = r.readByteArray();
|
||||
}
|
||||
|
||||
public ByteArray getByteArray() {
|
||||
return this.data;
|
||||
}
|
||||
|
||||
public ByteArrayInputStream getByteArrayInputStream() {
|
||||
if (this.data != null)
|
||||
return this.data.toByteArrayInputStream();
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isHeader() {
|
||||
return this.isHeader;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.sun.mail.imap.protocol;
|
||||
|
||||
import com.sun.mail.iap.ParsingException;
|
||||
|
||||
public class RFC822SIZE implements Item {
|
||||
static final char[] name = new char[] {
|
||||
'R', 'F', 'C', '8', '2', '2', '.', 'S', 'I', 'Z',
|
||||
'E' };
|
||||
|
||||
public int msgno;
|
||||
|
||||
public int size;
|
||||
|
||||
public RFC822SIZE(FetchResponse r) throws ParsingException {
|
||||
this.msgno = r.getNumber();
|
||||
r.skipSpaces();
|
||||
this.size = r.readNumber();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package com.sun.mail.imap.protocol;
|
||||
|
||||
import com.sun.mail.iap.ProtocolException;
|
||||
|
||||
public interface SaslAuthenticator {
|
||||
boolean authenticate(String[] paramArrayOfString, String paramString1, String paramString2, String paramString3, String paramString4) throws ProtocolException;
|
||||
}
|
||||
|
|
@ -0,0 +1,351 @@
|
|||
package com.sun.mail.imap.protocol;
|
||||
|
||||
import com.sun.mail.iap.Argument;
|
||||
import com.sun.mail.imap.ModifiedSinceTerm;
|
||||
import com.sun.mail.imap.OlderTerm;
|
||||
import com.sun.mail.imap.YoungerTerm;
|
||||
import java.io.IOException;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import javax.mail.Flags;
|
||||
import javax.mail.Message;
|
||||
import javax.mail.search.AddressTerm;
|
||||
import javax.mail.search.AndTerm;
|
||||
import javax.mail.search.BodyTerm;
|
||||
import javax.mail.search.DateTerm;
|
||||
import javax.mail.search.FlagTerm;
|
||||
import javax.mail.search.FromStringTerm;
|
||||
import javax.mail.search.FromTerm;
|
||||
import javax.mail.search.HeaderTerm;
|
||||
import javax.mail.search.MessageIDTerm;
|
||||
import javax.mail.search.NotTerm;
|
||||
import javax.mail.search.OrTerm;
|
||||
import javax.mail.search.ReceivedDateTerm;
|
||||
import javax.mail.search.RecipientStringTerm;
|
||||
import javax.mail.search.RecipientTerm;
|
||||
import javax.mail.search.SearchException;
|
||||
import javax.mail.search.SearchTerm;
|
||||
import javax.mail.search.SentDateTerm;
|
||||
import javax.mail.search.SizeTerm;
|
||||
import javax.mail.search.StringTerm;
|
||||
import javax.mail.search.SubjectTerm;
|
||||
|
||||
public class SearchSequence {
|
||||
public Argument generateSequence(SearchTerm term, String charset) throws SearchException, IOException {
|
||||
if (term instanceof AndTerm)
|
||||
return and((AndTerm)term, charset);
|
||||
if (term instanceof OrTerm)
|
||||
return or((OrTerm)term, charset);
|
||||
if (term instanceof NotTerm)
|
||||
return not((NotTerm)term, charset);
|
||||
if (term instanceof HeaderTerm)
|
||||
return header((HeaderTerm)term, charset);
|
||||
if (term instanceof FlagTerm)
|
||||
return flag((FlagTerm)term);
|
||||
if (term instanceof FromTerm) {
|
||||
FromTerm fterm = (FromTerm)term;
|
||||
return from(fterm.getAddress().toString(), charset);
|
||||
}
|
||||
if (term instanceof FromStringTerm) {
|
||||
FromStringTerm fterm = (FromStringTerm)term;
|
||||
return from(fterm.getPattern(), charset);
|
||||
}
|
||||
if (term instanceof RecipientTerm) {
|
||||
RecipientTerm rterm = (RecipientTerm)term;
|
||||
return recipient(rterm.getRecipientType(),
|
||||
rterm.getAddress().toString(), charset);
|
||||
}
|
||||
if (term instanceof RecipientStringTerm) {
|
||||
RecipientStringTerm rterm = (RecipientStringTerm)term;
|
||||
return recipient(rterm.getRecipientType(),
|
||||
rterm.getPattern(), charset);
|
||||
}
|
||||
if (term instanceof SubjectTerm)
|
||||
return subject((SubjectTerm)term, charset);
|
||||
if (term instanceof BodyTerm)
|
||||
return body((BodyTerm)term, charset);
|
||||
if (term instanceof SizeTerm)
|
||||
return size((SizeTerm)term);
|
||||
if (term instanceof SentDateTerm)
|
||||
return sentdate((SentDateTerm)term);
|
||||
if (term instanceof ReceivedDateTerm)
|
||||
return receiveddate((ReceivedDateTerm)term);
|
||||
if (term instanceof OlderTerm)
|
||||
return older((OlderTerm)term);
|
||||
if (term instanceof YoungerTerm)
|
||||
return younger((YoungerTerm)term);
|
||||
if (term instanceof MessageIDTerm)
|
||||
return messageid((MessageIDTerm)term, charset);
|
||||
if (term instanceof ModifiedSinceTerm)
|
||||
return modifiedSince((ModifiedSinceTerm)term);
|
||||
throw new SearchException("Search too complex");
|
||||
}
|
||||
|
||||
public static boolean isAscii(SearchTerm term) {
|
||||
if (term instanceof AndTerm)
|
||||
return isAscii(((AndTerm)term).getTerms());
|
||||
if (term instanceof OrTerm)
|
||||
return isAscii(((OrTerm)term).getTerms());
|
||||
if (term instanceof NotTerm)
|
||||
return isAscii(((NotTerm)term).getTerm());
|
||||
if (term instanceof StringTerm)
|
||||
return isAscii(((StringTerm)term).getPattern());
|
||||
if (term instanceof AddressTerm)
|
||||
return isAscii(((AddressTerm)term).getAddress().toString());
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean isAscii(SearchTerm[] terms) {
|
||||
for (int i = 0; i < terms.length; i++) {
|
||||
if (!isAscii(terms[i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean isAscii(String s) {
|
||||
int l = s.length();
|
||||
for (int i = 0; i < l; i++) {
|
||||
if (s.charAt(i) > '\u007F')
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected Argument and(AndTerm term, String charset) throws SearchException, IOException {
|
||||
SearchTerm[] terms = term.getTerms();
|
||||
Argument result = generateSequence(terms[0], charset);
|
||||
for (int i = 1; i < terms.length; i++)
|
||||
result.append(generateSequence(terms[i], charset));
|
||||
return result;
|
||||
}
|
||||
|
||||
protected Argument or(OrTerm term, String charset) throws SearchException, IOException {
|
||||
SearchTerm[] terms = term.getTerms();
|
||||
if (terms.length > 2) {
|
||||
SearchTerm t = terms[0];
|
||||
for (int i = 1; i < terms.length; i++)
|
||||
t = new OrTerm(t, terms[i]);
|
||||
term = (OrTerm)t;
|
||||
terms = term.getTerms();
|
||||
}
|
||||
Argument result = new Argument();
|
||||
if (terms.length > 1)
|
||||
result.writeAtom("OR");
|
||||
if (terms[0] instanceof AndTerm || terms[0] instanceof FlagTerm) {
|
||||
result.writeArgument(generateSequence(terms[0], charset));
|
||||
} else {
|
||||
result.append(generateSequence(terms[0], charset));
|
||||
}
|
||||
if (terms.length > 1)
|
||||
if (terms[1] instanceof AndTerm || terms[1] instanceof FlagTerm) {
|
||||
result.writeArgument(generateSequence(terms[1], charset));
|
||||
} else {
|
||||
result.append(generateSequence(terms[1], charset));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected Argument not(NotTerm term, String charset) throws SearchException, IOException {
|
||||
Argument result = new Argument();
|
||||
result.writeAtom("NOT");
|
||||
SearchTerm nterm = term.getTerm();
|
||||
if (nterm instanceof AndTerm || nterm instanceof FlagTerm) {
|
||||
result.writeArgument(generateSequence(nterm, charset));
|
||||
} else {
|
||||
result.append(generateSequence(nterm, charset));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected Argument header(HeaderTerm term, String charset) throws SearchException, IOException {
|
||||
Argument result = new Argument();
|
||||
result.writeAtom("HEADER");
|
||||
result.writeString(term.getHeaderName());
|
||||
result.writeString(term.getPattern(), charset);
|
||||
return result;
|
||||
}
|
||||
|
||||
protected Argument messageid(MessageIDTerm term, String charset) throws SearchException, IOException {
|
||||
Argument result = new Argument();
|
||||
result.writeAtom("HEADER");
|
||||
result.writeString("Message-ID");
|
||||
result.writeString(term.getPattern(), charset);
|
||||
return result;
|
||||
}
|
||||
|
||||
protected Argument flag(FlagTerm term) throws SearchException {
|
||||
boolean set = term.getTestSet();
|
||||
Argument result = new Argument();
|
||||
Flags flags = term.getFlags();
|
||||
Flags.Flag[] sf = flags.getSystemFlags();
|
||||
String[] uf = flags.getUserFlags();
|
||||
if (sf.length == 0 && uf.length == 0)
|
||||
throw new SearchException("Invalid FlagTerm");
|
||||
for (int j = 0; j < sf.length; j++) {
|
||||
if (sf[j] == Flags.Flag.DELETED) {
|
||||
result.writeAtom(set ? "DELETED" : "UNDELETED");
|
||||
} else if (sf[j] == Flags.Flag.ANSWERED) {
|
||||
result.writeAtom(set ? "ANSWERED" : "UNANSWERED");
|
||||
} else if (sf[j] == Flags.Flag.DRAFT) {
|
||||
result.writeAtom(set ? "DRAFT" : "UNDRAFT");
|
||||
} else if (sf[j] == Flags.Flag.FLAGGED) {
|
||||
result.writeAtom(set ? "FLAGGED" : "UNFLAGGED");
|
||||
} else if (sf[j] == Flags.Flag.RECENT) {
|
||||
result.writeAtom(set ? "RECENT" : "OLD");
|
||||
} else if (sf[j] == Flags.Flag.SEEN) {
|
||||
result.writeAtom(set ? "SEEN" : "UNSEEN");
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < uf.length; i++) {
|
||||
result.writeAtom(set ? "KEYWORD" : "UNKEYWORD");
|
||||
result.writeAtom(uf[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected Argument from(String address, String charset) throws SearchException, IOException {
|
||||
Argument result = new Argument();
|
||||
result.writeAtom("FROM");
|
||||
result.writeString(address, charset);
|
||||
return result;
|
||||
}
|
||||
|
||||
protected Argument recipient(Message.RecipientType type, String address, String charset) throws SearchException, IOException {
|
||||
Argument result = new Argument();
|
||||
if (type == Message.RecipientType.TO) {
|
||||
result.writeAtom("TO");
|
||||
} else if (type == Message.RecipientType.CC) {
|
||||
result.writeAtom("CC");
|
||||
} else if (type == Message.RecipientType.BCC) {
|
||||
result.writeAtom("BCC");
|
||||
} else {
|
||||
throw new SearchException("Illegal Recipient type");
|
||||
}
|
||||
result.writeString(address, charset);
|
||||
return result;
|
||||
}
|
||||
|
||||
protected Argument subject(SubjectTerm term, String charset) throws SearchException, IOException {
|
||||
Argument result = new Argument();
|
||||
result.writeAtom("SUBJECT");
|
||||
result.writeString(term.getPattern(), charset);
|
||||
return result;
|
||||
}
|
||||
|
||||
protected Argument body(BodyTerm term, String charset) throws SearchException, IOException {
|
||||
Argument result = new Argument();
|
||||
result.writeAtom("BODY");
|
||||
result.writeString(term.getPattern(), charset);
|
||||
return result;
|
||||
}
|
||||
|
||||
protected Argument size(SizeTerm term) throws SearchException {
|
||||
Argument result = new Argument();
|
||||
switch (term.getComparison()) {
|
||||
case 5:
|
||||
result.writeAtom("LARGER");
|
||||
break;
|
||||
case 2:
|
||||
result.writeAtom("SMALLER");
|
||||
break;
|
||||
default:
|
||||
throw new SearchException("Cannot handle Comparison");
|
||||
}
|
||||
result.writeNumber(term.getNumber());
|
||||
return result;
|
||||
}
|
||||
|
||||
private static String[] monthTable = new String[] {
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
|
||||
"Nov", "Dec" };
|
||||
|
||||
protected Calendar cal = new GregorianCalendar();
|
||||
|
||||
protected String toIMAPDate(Date date) {
|
||||
StringBuffer s = new StringBuffer();
|
||||
this.cal.setTime(date);
|
||||
s.append(this.cal.get(5)).append("-");
|
||||
s.append(monthTable[this.cal.get(2)]).append('-');
|
||||
s.append(this.cal.get(1));
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
protected Argument sentdate(DateTerm term) throws SearchException {
|
||||
Argument result = new Argument();
|
||||
String date = toIMAPDate(term.getDate());
|
||||
switch (term.getComparison()) {
|
||||
case 5:
|
||||
result.writeAtom("NOT SENTON " + date + " SENTSINCE " + date);
|
||||
break;
|
||||
case 3:
|
||||
result.writeAtom("SENTON " + date);
|
||||
break;
|
||||
case 2:
|
||||
result.writeAtom("SENTBEFORE " + date);
|
||||
break;
|
||||
case 6:
|
||||
result.writeAtom("SENTSINCE " + date);
|
||||
break;
|
||||
case 1:
|
||||
result.writeAtom("OR SENTBEFORE " + date + " SENTON " + date);
|
||||
break;
|
||||
case 4:
|
||||
result.writeAtom("NOT SENTON " + date);
|
||||
break;
|
||||
default:
|
||||
throw new SearchException("Cannot handle Date Comparison");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected Argument receiveddate(DateTerm term) throws SearchException {
|
||||
Argument result = new Argument();
|
||||
String date = toIMAPDate(term.getDate());
|
||||
switch (term.getComparison()) {
|
||||
case 5:
|
||||
result.writeAtom("NOT ON " + date + " SINCE " + date);
|
||||
break;
|
||||
case 3:
|
||||
result.writeAtom("ON " + date);
|
||||
break;
|
||||
case 2:
|
||||
result.writeAtom("BEFORE " + date);
|
||||
break;
|
||||
case 6:
|
||||
result.writeAtom("SINCE " + date);
|
||||
break;
|
||||
case 1:
|
||||
result.writeAtom("OR BEFORE " + date + " ON " + date);
|
||||
break;
|
||||
case 4:
|
||||
result.writeAtom("NOT ON " + date);
|
||||
break;
|
||||
default:
|
||||
throw new SearchException("Cannot handle Date Comparison");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected Argument older(OlderTerm term) throws SearchException {
|
||||
Argument result = new Argument();
|
||||
result.writeAtom("OLDER");
|
||||
result.writeNumber(term.getInterval());
|
||||
return result;
|
||||
}
|
||||
|
||||
protected Argument younger(YoungerTerm term) throws SearchException {
|
||||
Argument result = new Argument();
|
||||
result.writeAtom("YOUNGER");
|
||||
result.writeNumber(term.getInterval());
|
||||
return result;
|
||||
}
|
||||
|
||||
protected Argument modifiedSince(ModifiedSinceTerm term) throws SearchException {
|
||||
Argument result = new Argument();
|
||||
result.writeAtom("MODSEQ");
|
||||
result.writeNumber(term.getModSeq());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
package com.sun.mail.imap.protocol;
|
||||
|
||||
import com.sun.mail.iap.ParsingException;
|
||||
import com.sun.mail.iap.Response;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
public class Status {
|
||||
public String mbox = null;
|
||||
|
||||
public int total = -1;
|
||||
|
||||
public int recent = -1;
|
||||
|
||||
public long uidnext = -1L;
|
||||
|
||||
public long uidvalidity = -1L;
|
||||
|
||||
public int unseen = -1;
|
||||
|
||||
public long highestmodseq = -1L;
|
||||
|
||||
public Map<String, Long> items;
|
||||
|
||||
static final String[] standardItems = new String[] { "MESSAGES", "RECENT", "UNSEEN", "UIDNEXT", "UIDVALIDITY" };
|
||||
|
||||
public Status(Response r) throws ParsingException {
|
||||
this.mbox = r.readAtomString();
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
boolean onlySpaces = true;
|
||||
while (r.peekByte() != 40 && r.peekByte() != 0) {
|
||||
char next = (char)r.readByte();
|
||||
buffer.append(next);
|
||||
if (next != ' ')
|
||||
onlySpaces = false;
|
||||
}
|
||||
if (!onlySpaces)
|
||||
this.mbox = (this.mbox + buffer).trim();
|
||||
if (r.readByte() != 40)
|
||||
throw new ParsingException("parse error in STATUS");
|
||||
do {
|
||||
String attr = r.readAtom();
|
||||
if (attr.equalsIgnoreCase("MESSAGES")) {
|
||||
this.total = r.readNumber();
|
||||
} else if (attr.equalsIgnoreCase("RECENT")) {
|
||||
this.recent = r.readNumber();
|
||||
} else if (attr.equalsIgnoreCase("UIDNEXT")) {
|
||||
this.uidnext = r.readLong();
|
||||
} else if (attr.equalsIgnoreCase("UIDVALIDITY")) {
|
||||
this.uidvalidity = r.readLong();
|
||||
} else if (attr.equalsIgnoreCase("UNSEEN")) {
|
||||
this.unseen = r.readNumber();
|
||||
} else if (attr.equalsIgnoreCase("HIGHESTMODSEQ")) {
|
||||
this.highestmodseq = r.readLong();
|
||||
} else {
|
||||
if (this.items == null)
|
||||
this.items = new HashMap<String, Long>();
|
||||
this.items.put(attr.toUpperCase(Locale.ENGLISH),
|
||||
Long.valueOf(r.readLong()));
|
||||
}
|
||||
} while (r.readByte() != 41);
|
||||
}
|
||||
|
||||
public long getItem(String item) {
|
||||
item = item.toUpperCase(Locale.ENGLISH);
|
||||
long ret = -1L;
|
||||
Long v;
|
||||
if (this.items != null && (v = this.items.get(item)) != null) {
|
||||
ret = v;
|
||||
} else if (item.equals("MESSAGES")) {
|
||||
ret = (long)this.total;
|
||||
} else if (item.equals("RECENT")) {
|
||||
ret = (long)this.recent;
|
||||
} else if (item.equals("UIDNEXT")) {
|
||||
ret = this.uidnext;
|
||||
} else if (item.equals("UIDVALIDITY")) {
|
||||
ret = this.uidvalidity;
|
||||
} else if (item.equals("UNSEEN")) {
|
||||
ret = (long)this.unseen;
|
||||
} else if (item.equals("HIGHESTMODSEQ")) {
|
||||
ret = this.highestmodseq;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static void add(Status s1, Status s2) {
|
||||
if (s2.total != -1)
|
||||
s1.total = s2.total;
|
||||
if (s2.recent != -1)
|
||||
s1.recent = s2.recent;
|
||||
if (s2.uidnext != -1L)
|
||||
s1.uidnext = s2.uidnext;
|
||||
if (s2.uidvalidity != -1L)
|
||||
s1.uidvalidity = s2.uidvalidity;
|
||||
if (s2.unseen != -1)
|
||||
s1.unseen = s2.unseen;
|
||||
if (s2.highestmodseq != -1L)
|
||||
s1.highestmodseq = s2.highestmodseq;
|
||||
if (s1.items == null) {
|
||||
s1.items = s2.items;
|
||||
} else if (s2.items != null) {
|
||||
s1.items.putAll(s2.items);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package com.sun.mail.imap.protocol;
|
||||
|
||||
import com.sun.mail.iap.ParsingException;
|
||||
|
||||
public class UID implements Item {
|
||||
static final char[] name = new char[] { 'U', 'I', 'D' };
|
||||
|
||||
public int seqnum;
|
||||
|
||||
public long uid;
|
||||
|
||||
public UID(FetchResponse r) throws ParsingException {
|
||||
this.seqnum = r.getNumber();
|
||||
r.skipSpaces();
|
||||
this.uid = r.readLong();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
package com.sun.mail.imap.protocol;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
public class UIDSet {
|
||||
public long start;
|
||||
|
||||
public long end;
|
||||
|
||||
public UIDSet() {}
|
||||
|
||||
public UIDSet(long start, long end) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
public long size() {
|
||||
return this.end - this.start + 1L;
|
||||
}
|
||||
|
||||
public static UIDSet[] createUIDSets(long[] uids) {
|
||||
if (uids == null)
|
||||
return null;
|
||||
List<UIDSet> v = new ArrayList<UIDSet>();
|
||||
for (int i = 0; i < uids.length; i++) {
|
||||
UIDSet ms = new UIDSet();
|
||||
ms.start = uids[i];
|
||||
int j;
|
||||
for (j = i + 1; j < uids.length &&
|
||||
uids[j] == uids[j - 1] + 1L; j++);
|
||||
ms.end = uids[j - 1];
|
||||
v.add(ms);
|
||||
i = j - 1;
|
||||
}
|
||||
UIDSet[] uidset = new UIDSet[v.size()];
|
||||
return v.<UIDSet>toArray(uidset);
|
||||
}
|
||||
|
||||
public static UIDSet[] parseUIDSets(String uids) {
|
||||
if (uids == null)
|
||||
return null;
|
||||
List<UIDSet> v = new ArrayList<UIDSet>();
|
||||
StringTokenizer st = new StringTokenizer(uids, ",:", true);
|
||||
long start = -1L;
|
||||
UIDSet cur = null;
|
||||
try {
|
||||
while (st.hasMoreTokens()) {
|
||||
String s = st.nextToken();
|
||||
if (s.equals(",")) {
|
||||
if (cur != null)
|
||||
v.add(cur);
|
||||
cur = null;
|
||||
continue;
|
||||
}
|
||||
if (s.equals(":"))
|
||||
continue;
|
||||
long n = Long.parseLong(s);
|
||||
if (cur != null) {
|
||||
cur.end = n;
|
||||
continue;
|
||||
}
|
||||
cur = new UIDSet(n, n);
|
||||
}
|
||||
} catch (NumberFormatException e) {}
|
||||
if (cur != null)
|
||||
v.add(cur);
|
||||
UIDSet[] uidset = new UIDSet[v.size()];
|
||||
return v.<UIDSet>toArray(uidset);
|
||||
}
|
||||
|
||||
public static String toString(UIDSet[] uidset) {
|
||||
if (uidset == null)
|
||||
return null;
|
||||
if (uidset.length == 0)
|
||||
return "";
|
||||
int i = 0;
|
||||
StringBuilder s = new StringBuilder();
|
||||
int size = uidset.length;
|
||||
while (true) {
|
||||
long start = (uidset[i]).start;
|
||||
long end = (uidset[i]).end;
|
||||
if (end > start) {
|
||||
s.append(start).append(':').append(end);
|
||||
} else {
|
||||
s.append(start);
|
||||
}
|
||||
i++;
|
||||
if (i >= size)
|
||||
break;
|
||||
s.append(',');
|
||||
}
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
public static long[] toArray(UIDSet[] uidset) {
|
||||
if (uidset == null)
|
||||
return null;
|
||||
long[] uids = new long[(int)size(uidset)];
|
||||
int i = 0;
|
||||
for (UIDSet u : uidset) {
|
||||
for (long n = u.start; n <= u.end; n++)
|
||||
uids[i++] = n;
|
||||
}
|
||||
return uids;
|
||||
}
|
||||
|
||||
public static long[] toArray(UIDSet[] uidset, long uidmax) {
|
||||
if (uidset == null)
|
||||
return null;
|
||||
long[] uids = new long[(int)size(uidset, uidmax)];
|
||||
int i = 0;
|
||||
for (UIDSet u : uidset) {
|
||||
for (long n = u.start; n <= u.end && (
|
||||
uidmax < 0L || n <= uidmax); n++)
|
||||
uids[i++] = n;
|
||||
}
|
||||
return uids;
|
||||
}
|
||||
|
||||
public static long size(UIDSet[] uidset) {
|
||||
long count = 0L;
|
||||
if (uidset != null)
|
||||
for (UIDSet u : uidset)
|
||||
count += u.size();
|
||||
return count;
|
||||
}
|
||||
|
||||
private static long size(UIDSet[] uidset, long uidmax) {
|
||||
long count = 0L;
|
||||
if (uidset != null)
|
||||
for (UIDSet u : uidset) {
|
||||
if (uidmax < 0L) {
|
||||
count += u.size();
|
||||
} else if (u.start <= uidmax) {
|
||||
if (u.end < uidmax) {
|
||||
count += u.end - u.start + 1L;
|
||||
} else {
|
||||
count += uidmax - u.start + 1L;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package com.sun.mail.pop3;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
class AppendStream extends OutputStream {
|
||||
private final WritableSharedFile tf;
|
||||
|
||||
private RandomAccessFile raf;
|
||||
|
||||
private final long start;
|
||||
|
||||
private long end;
|
||||
|
||||
public AppendStream(WritableSharedFile tf) throws IOException {
|
||||
this.tf = tf;
|
||||
this.raf = tf.getWritableFile();
|
||||
this.start = this.raf.length();
|
||||
this.raf.seek(this.start);
|
||||
}
|
||||
|
||||
public void write(int b) throws IOException {
|
||||
this.raf.write(b);
|
||||
}
|
||||
|
||||
public void write(byte[] b) throws IOException {
|
||||
this.raf.write(b);
|
||||
}
|
||||
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
this.raf.write(b, off, len);
|
||||
}
|
||||
|
||||
public synchronized void close() throws IOException {
|
||||
this.end = this.tf.updateLength();
|
||||
this.raf = null;
|
||||
}
|
||||
|
||||
public synchronized InputStream getInputStream() throws IOException {
|
||||
return this.tf.newStream(this.start, this.end);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
package com.sun.mail.pop3;
|
||||
|
||||
import javax.mail.Flags;
|
||||
import javax.mail.Folder;
|
||||
import javax.mail.Message;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.MethodNotSupportedException;
|
||||
|
||||
public class DefaultFolder extends Folder {
|
||||
DefaultFolder(POP3Store store) {
|
||||
super(store);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return "";
|
||||
}
|
||||
|
||||
public String getFullName() {
|
||||
return "";
|
||||
}
|
||||
|
||||
public Folder getParent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean exists() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public Folder[] list(String pattern) throws MessagingException {
|
||||
Folder[] f = { getInbox() };
|
||||
return f;
|
||||
}
|
||||
|
||||
public char getSeparator() {
|
||||
return '/';
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
public boolean create(int type) throws MessagingException {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean hasNewMessages() throws MessagingException {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Folder getFolder(String name) throws MessagingException {
|
||||
if (!name.equalsIgnoreCase("INBOX"))
|
||||
throw new MessagingException("only INBOX supported");
|
||||
return getInbox();
|
||||
}
|
||||
|
||||
protected Folder getInbox() throws MessagingException {
|
||||
return getStore().getFolder("INBOX");
|
||||
}
|
||||
|
||||
public boolean delete(boolean recurse) throws MessagingException {
|
||||
throw new MethodNotSupportedException("delete");
|
||||
}
|
||||
|
||||
public boolean renameTo(Folder f) throws MessagingException {
|
||||
throw new MethodNotSupportedException("renameTo");
|
||||
}
|
||||
|
||||
public void open(int mode) throws MessagingException {
|
||||
throw new MethodNotSupportedException("open");
|
||||
}
|
||||
|
||||
public void close(boolean expunge) throws MessagingException {
|
||||
throw new MethodNotSupportedException("close");
|
||||
}
|
||||
|
||||
public boolean isOpen() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Flags getPermanentFlags() {
|
||||
return new Flags();
|
||||
}
|
||||
|
||||
public int getMessageCount() throws MessagingException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public Message getMessage(int msgno) throws MessagingException {
|
||||
throw new MethodNotSupportedException("getMessage");
|
||||
}
|
||||
|
||||
public void appendMessages(Message[] msgs) throws MessagingException {
|
||||
throw new MethodNotSupportedException("Append not supported");
|
||||
}
|
||||
|
||||
public Message[] expunge() throws MessagingException {
|
||||
throw new MethodNotSupportedException("expunge");
|
||||
}
|
||||
}
|
||||
364
rus/WEB-INF/lib/javax.mail_src/com/sun/mail/pop3/POP3Folder.java
Normal file
364
rus/WEB-INF/lib/javax.mail_src/com/sun/mail/pop3/POP3Folder.java
Normal file
|
|
@ -0,0 +1,364 @@
|
|||
package com.sun.mail.pop3;
|
||||
|
||||
import com.sun.mail.util.LineInputStream;
|
||||
import com.sun.mail.util.MailLogger;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.Vector;
|
||||
import java.util.logging.Level;
|
||||
import javax.mail.FetchProfile;
|
||||
import javax.mail.Flags;
|
||||
import javax.mail.Folder;
|
||||
import javax.mail.FolderClosedException;
|
||||
import javax.mail.FolderNotFoundException;
|
||||
import javax.mail.Message;
|
||||
import javax.mail.MessageRemovedException;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.MethodNotSupportedException;
|
||||
import javax.mail.UIDFolder;
|
||||
|
||||
public class POP3Folder extends Folder {
|
||||
private String name;
|
||||
|
||||
private POP3Store store;
|
||||
|
||||
private volatile Protocol port;
|
||||
|
||||
private int total;
|
||||
|
||||
private int size;
|
||||
|
||||
private boolean exists = false;
|
||||
|
||||
private volatile boolean opened = false;
|
||||
|
||||
private Vector message_cache;
|
||||
|
||||
private boolean doneUidl = false;
|
||||
|
||||
private volatile TempFile fileCache = null;
|
||||
|
||||
MailLogger logger;
|
||||
|
||||
protected POP3Folder(POP3Store store, String name) {
|
||||
super(store);
|
||||
this.name = name;
|
||||
this.store = store;
|
||||
if (name.equalsIgnoreCase("INBOX"))
|
||||
this.exists = true;
|
||||
this
|
||||
.logger = new MailLogger(getClass(), "DEBUG POP3", store.getSession());
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String getFullName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public Folder getParent() {
|
||||
return new DefaultFolder(this.store);
|
||||
}
|
||||
|
||||
public boolean exists() {
|
||||
return this.exists;
|
||||
}
|
||||
|
||||
public Folder[] list(String pattern) throws MessagingException {
|
||||
throw new MessagingException("not a directory");
|
||||
}
|
||||
|
||||
public char getSeparator() {
|
||||
return '\000';
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public boolean create(int type) throws MessagingException {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean hasNewMessages() throws MessagingException {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Folder getFolder(String name) throws MessagingException {
|
||||
throw new MessagingException("not a directory");
|
||||
}
|
||||
|
||||
public boolean delete(boolean recurse) throws MessagingException {
|
||||
throw new MethodNotSupportedException("delete");
|
||||
}
|
||||
|
||||
public boolean renameTo(Folder f) throws MessagingException {
|
||||
throw new MethodNotSupportedException("renameTo");
|
||||
}
|
||||
|
||||
public synchronized void open(int mode) throws MessagingException {
|
||||
checkClosed();
|
||||
if (!this.exists)
|
||||
throw new FolderNotFoundException(this, "folder is not INBOX");
|
||||
try {
|
||||
this.port = this.store.getPort(this);
|
||||
Status s = this.port.stat();
|
||||
this.total = s.total;
|
||||
this.size = s.size;
|
||||
this.mode = mode;
|
||||
if (this.store.useFileCache)
|
||||
try {
|
||||
this.fileCache = new TempFile(this.store.fileCacheDir);
|
||||
} catch (IOException ex) {
|
||||
this.logger.log(Level.FINE, "failed to create file cache", (Throwable)ex);
|
||||
throw ex;
|
||||
}
|
||||
this.opened = true;
|
||||
} catch (IOException ioex) {
|
||||
try {
|
||||
if (this.port != null)
|
||||
this.port.quit();
|
||||
} catch (IOException e) {
|
||||
|
||||
} finally {
|
||||
this.port = null;
|
||||
this.store.closePort(this);
|
||||
}
|
||||
throw new MessagingException("Open failed", ioex);
|
||||
}
|
||||
this.message_cache = new Vector(this.total);
|
||||
this.message_cache.setSize(this.total);
|
||||
this.doneUidl = false;
|
||||
notifyConnectionListeners(1);
|
||||
}
|
||||
|
||||
public synchronized void close(boolean expunge) throws MessagingException {
|
||||
checkOpen();
|
||||
try {
|
||||
if (this.store.rsetBeforeQuit)
|
||||
this.port.rset();
|
||||
if (expunge && this.mode == 2)
|
||||
for (int j = 0; j < this.message_cache.size(); j++) {
|
||||
POP3Message m;
|
||||
if ((m = this.message_cache.elementAt(j)) != null &&
|
||||
m.isSet(Flags.Flag.DELETED))
|
||||
try {
|
||||
this.port.dele(j + 1);
|
||||
} catch (IOException ioex) {
|
||||
throw new MessagingException("Exception deleting messages during close", ioex);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < this.message_cache.size(); i++) {
|
||||
POP3Message m;
|
||||
if ((m = this.message_cache.elementAt(i)) != null)
|
||||
m.invalidate(true);
|
||||
}
|
||||
this.port.quit();
|
||||
} catch (IOException e) {
|
||||
|
||||
} finally {
|
||||
this.port = null;
|
||||
this.store.closePort(this);
|
||||
this.message_cache = null;
|
||||
this.opened = false;
|
||||
notifyConnectionListeners(3);
|
||||
if (this.fileCache != null) {
|
||||
this.fileCache.close();
|
||||
this.fileCache = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized boolean isOpen() {
|
||||
if (!this.opened)
|
||||
return false;
|
||||
try {
|
||||
if (!this.port.noop())
|
||||
throw new IOException("NOOP failed");
|
||||
} catch (IOException ioex) {
|
||||
try {
|
||||
close(false);
|
||||
} catch (MessagingException e) {
|
||||
|
||||
} finally {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public Flags getPermanentFlags() {
|
||||
return new Flags();
|
||||
}
|
||||
|
||||
public synchronized int getMessageCount() throws MessagingException {
|
||||
if (!this.opened)
|
||||
return -1;
|
||||
checkReadable();
|
||||
return this.total;
|
||||
}
|
||||
|
||||
public synchronized Message getMessage(int msgno) throws MessagingException {
|
||||
checkOpen();
|
||||
POP3Message m;
|
||||
if ((m = this.message_cache.elementAt(msgno - 1)) == null) {
|
||||
m = createMessage(this, msgno);
|
||||
this.message_cache.setElementAt(m, msgno - 1);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
protected POP3Message createMessage(Folder f, int msgno) throws MessagingException {
|
||||
POP3Message m = null;
|
||||
Constructor<POP3Message> cons = this.store.messageConstructor;
|
||||
if (cons != null)
|
||||
try {
|
||||
Object[] o = { this, msgno };
|
||||
m = cons.newInstance(o);
|
||||
} catch (Exception e) {}
|
||||
if (m == null)
|
||||
m = new POP3Message(this, msgno);
|
||||
return m;
|
||||
}
|
||||
|
||||
public void appendMessages(Message[] msgs) throws MessagingException {
|
||||
throw new MethodNotSupportedException("Append not supported");
|
||||
}
|
||||
|
||||
public Message[] expunge() throws MessagingException {
|
||||
throw new MethodNotSupportedException("Expunge not supported");
|
||||
}
|
||||
|
||||
public synchronized void fetch(Message[] msgs, FetchProfile fp) throws MessagingException {
|
||||
checkReadable();
|
||||
if (!this.doneUidl && this.store.supportsUidl &&
|
||||
fp.contains(UIDFolder.FetchProfileItem.UID)) {
|
||||
String[] uids = new String[this.message_cache.size()];
|
||||
try {
|
||||
if (!this.port.uidl(uids))
|
||||
return;
|
||||
} catch (EOFException eex) {
|
||||
close(false);
|
||||
throw new FolderClosedException(this, eex.toString());
|
||||
} catch (IOException ex) {
|
||||
throw new MessagingException("error getting UIDL", ex);
|
||||
}
|
||||
for (int i = 0; i < uids.length; i++) {
|
||||
if (uids[i] != null) {
|
||||
POP3Message m = (POP3Message)getMessage(i + 1);
|
||||
m.uid = uids[i];
|
||||
}
|
||||
}
|
||||
this.doneUidl = true;
|
||||
}
|
||||
if (fp.contains(FetchProfile.Item.ENVELOPE))
|
||||
for (int i = 0; i < msgs.length; i++) {
|
||||
try {
|
||||
POP3Message msg = (POP3Message)msgs[i];
|
||||
msg.getHeader("");
|
||||
msg.getSize();
|
||||
} catch (MessageRemovedException e) {}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized String getUID(Message msg) throws MessagingException {
|
||||
checkOpen();
|
||||
if (!(msg instanceof POP3Message))
|
||||
throw new MessagingException("message is not a POP3Message");
|
||||
POP3Message m = (POP3Message)msg;
|
||||
try {
|
||||
if (!this.store.supportsUidl)
|
||||
return null;
|
||||
if (m.uid == "UNKNOWN")
|
||||
m.uid = this.port.uidl(m.getMessageNumber());
|
||||
return m.uid;
|
||||
} catch (EOFException eex) {
|
||||
close(false);
|
||||
throw new FolderClosedException(this, eex.toString());
|
||||
} catch (IOException ex) {
|
||||
throw new MessagingException("error getting UIDL", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized int getSize() throws MessagingException {
|
||||
checkOpen();
|
||||
return this.size;
|
||||
}
|
||||
|
||||
public synchronized int[] getSizes() throws MessagingException {
|
||||
checkOpen();
|
||||
int[] sizes = new int[this.total];
|
||||
InputStream is = null;
|
||||
LineInputStream lis = null;
|
||||
try {
|
||||
is = this.port.list();
|
||||
lis = new LineInputStream(is);
|
||||
String line;
|
||||
while ((line = lis.readLine()) != null) {
|
||||
try {
|
||||
StringTokenizer st = new StringTokenizer(line);
|
||||
int msgnum = Integer.parseInt(st.nextToken());
|
||||
int size = Integer.parseInt(st.nextToken());
|
||||
if (msgnum > 0 && msgnum <= this.total)
|
||||
sizes[msgnum - 1] = size;
|
||||
} catch (RuntimeException e) {}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
|
||||
} finally {
|
||||
try {
|
||||
if (lis != null)
|
||||
lis.close();
|
||||
} catch (IOException e) {}
|
||||
try {
|
||||
if (is != null)
|
||||
is.close();
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
return sizes;
|
||||
}
|
||||
|
||||
public synchronized InputStream listCommand() throws MessagingException, IOException {
|
||||
checkOpen();
|
||||
return this.port.list();
|
||||
}
|
||||
|
||||
protected void finalize() throws Throwable {
|
||||
super.finalize();
|
||||
close(false);
|
||||
}
|
||||
|
||||
private void checkOpen() throws IllegalStateException {
|
||||
if (!this.opened)
|
||||
throw new IllegalStateException("Folder is not Open");
|
||||
}
|
||||
|
||||
private void checkClosed() throws IllegalStateException {
|
||||
if (this.opened)
|
||||
throw new IllegalStateException("Folder is Open");
|
||||
}
|
||||
|
||||
private void checkReadable() throws IllegalStateException {
|
||||
if (!this.opened || (this.mode != 1 && this.mode != 2))
|
||||
throw new IllegalStateException("Folder is not Readable");
|
||||
}
|
||||
|
||||
Protocol getProtocol() throws MessagingException {
|
||||
Protocol p = this.port;
|
||||
checkOpen();
|
||||
return p;
|
||||
}
|
||||
|
||||
protected void notifyMessageChangedListeners(int type, Message m) {
|
||||
super.notifyMessageChangedListeners(type, m);
|
||||
}
|
||||
|
||||
TempFile getFileCache() {
|
||||
return this.fileCache;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,322 @@
|
|||
package com.sun.mail.pop3;
|
||||
|
||||
import com.sun.mail.util.ReadableMime;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.util.Enumeration;
|
||||
import java.util.logging.Level;
|
||||
import javax.mail.Flags;
|
||||
import javax.mail.Folder;
|
||||
import javax.mail.FolderClosedException;
|
||||
import javax.mail.IllegalWriteException;
|
||||
import javax.mail.MessageRemovedException;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.internet.InternetHeaders;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import javax.mail.internet.SharedInputStream;
|
||||
|
||||
public class POP3Message extends MimeMessage implements ReadableMime {
|
||||
static final String UNKNOWN = "UNKNOWN";
|
||||
|
||||
private POP3Folder folder;
|
||||
|
||||
private int hdrSize = -1;
|
||||
|
||||
private int msgSize = -1;
|
||||
|
||||
String uid = "UNKNOWN";
|
||||
|
||||
private SoftReference rawData = new SoftReference(null);
|
||||
|
||||
public POP3Message(Folder folder, int msgno) throws MessagingException {
|
||||
super(folder, msgno);
|
||||
assert folder instanceof POP3Folder;
|
||||
this.folder = (POP3Folder)folder;
|
||||
}
|
||||
|
||||
public synchronized void setFlags(Flags newFlags, boolean set) throws MessagingException {
|
||||
Flags oldFlags = (Flags)this.flags.clone();
|
||||
super.setFlags(newFlags, set);
|
||||
if (!this.flags.equals(oldFlags))
|
||||
this.folder.notifyMessageChangedListeners(1, this);
|
||||
}
|
||||
|
||||
public int getSize() throws MessagingException {
|
||||
try {
|
||||
synchronized (this) {
|
||||
if (this.msgSize > 0)
|
||||
return this.msgSize;
|
||||
}
|
||||
if (this.headers == null)
|
||||
loadHeaders();
|
||||
synchronized (this) {
|
||||
if (this.msgSize < 0)
|
||||
this.msgSize = this.folder.getProtocol().list(this.msgnum) - this.hdrSize;
|
||||
return this.msgSize;
|
||||
}
|
||||
} catch (EOFException eex) {
|
||||
this.folder.close(false);
|
||||
throw new FolderClosedException(this.folder, eex.toString());
|
||||
} catch (IOException ex) {
|
||||
throw new MessagingException("error getting size", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private InputStream getRawStream(boolean skipHeader) throws MessagingException {
|
||||
InputStream rawcontent = null;
|
||||
try {
|
||||
synchronized (this) {
|
||||
rawcontent = this.rawData.get();
|
||||
if (rawcontent == null) {
|
||||
TempFile cache = this.folder.getFileCache();
|
||||
if (cache != null) {
|
||||
if (this.folder.logger.isLoggable(Level.FINE))
|
||||
this.folder.logger.fine("caching message #" + this.msgnum + " in temp file");
|
||||
AppendStream os = cache.getAppendStream();
|
||||
BufferedOutputStream bos = new BufferedOutputStream(os);
|
||||
try {
|
||||
this.folder.getProtocol().retr(this.msgnum, bos);
|
||||
} finally {
|
||||
bos.close();
|
||||
}
|
||||
rawcontent = os.getInputStream();
|
||||
} else {
|
||||
rawcontent = this.folder.getProtocol().retr(this.msgnum, (this.msgSize > 0) ? (this.msgSize + this.hdrSize) : 0);
|
||||
}
|
||||
if (rawcontent == null) {
|
||||
this.expunged = true;
|
||||
throw new MessageRemovedException("can't retrieve message #" + this.msgnum + " in POP3Message.getContentStream");
|
||||
}
|
||||
if (this.headers == null || ((POP3Store)
|
||||
this.folder.getStore()).forgetTopHeaders) {
|
||||
this.headers = new InternetHeaders(rawcontent);
|
||||
this
|
||||
.hdrSize = (int)((SharedInputStream)rawcontent).getPosition();
|
||||
} else {
|
||||
int len;
|
||||
int offset = 0;
|
||||
do {
|
||||
len = 0;
|
||||
int c1;
|
||||
while ((c1 = rawcontent.read()) >= 0 &&
|
||||
c1 != 10) {
|
||||
if (c1 == 13) {
|
||||
if (rawcontent.available() > 0) {
|
||||
rawcontent.mark(1);
|
||||
if (rawcontent.read() != 10) {
|
||||
rawcontent.reset();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
len++;
|
||||
}
|
||||
if (rawcontent.available() == 0)
|
||||
break;
|
||||
} while (len != 0);
|
||||
this
|
||||
.hdrSize = (int)((SharedInputStream)rawcontent).getPosition();
|
||||
}
|
||||
this.msgSize = rawcontent.available();
|
||||
this.rawData = new SoftReference<InputStream>(rawcontent);
|
||||
}
|
||||
}
|
||||
} catch (EOFException eex) {
|
||||
this.folder.close(false);
|
||||
throw new FolderClosedException(this.folder, eex.toString());
|
||||
} catch (IOException ex) {
|
||||
throw new MessagingException("error fetching POP3 content", ex);
|
||||
}
|
||||
rawcontent = ((SharedInputStream)rawcontent).newStream(skipHeader ? (long)this.hdrSize : 0L, -1L);
|
||||
return rawcontent;
|
||||
}
|
||||
|
||||
protected synchronized InputStream getContentStream() throws MessagingException {
|
||||
if (this.contentStream != null)
|
||||
return ((SharedInputStream)this.contentStream).newStream(0L, -1L);
|
||||
InputStream cstream = getRawStream(true);
|
||||
TempFile cache = this.folder.getFileCache();
|
||||
if (cache != null || ((POP3Store)
|
||||
this.folder.getStore()).keepMessageContent)
|
||||
this.contentStream = ((SharedInputStream)cstream).newStream(0L, -1L);
|
||||
return cstream;
|
||||
}
|
||||
|
||||
public InputStream getMimeStream() throws MessagingException {
|
||||
return getRawStream(false);
|
||||
}
|
||||
|
||||
public synchronized void invalidate(boolean invalidateHeaders) {
|
||||
this.content = null;
|
||||
InputStream rstream = this.rawData.get();
|
||||
if (rstream != null) {
|
||||
try {
|
||||
rstream.close();
|
||||
} catch (IOException e) {}
|
||||
this.rawData = new SoftReference(null);
|
||||
}
|
||||
if (this.contentStream != null) {
|
||||
try {
|
||||
this.contentStream.close();
|
||||
} catch (IOException e) {}
|
||||
this.contentStream = null;
|
||||
}
|
||||
this.msgSize = -1;
|
||||
if (invalidateHeaders) {
|
||||
this.headers = null;
|
||||
this.hdrSize = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public InputStream top(int n) throws MessagingException {
|
||||
try {
|
||||
synchronized (this) {
|
||||
return this.folder.getProtocol().top(this.msgnum, n);
|
||||
}
|
||||
} catch (EOFException eex) {
|
||||
this.folder.close(false);
|
||||
throw new FolderClosedException(this.folder, eex.toString());
|
||||
} catch (IOException ex) {
|
||||
throw new MessagingException("error getting size", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public String[] getHeader(String name) throws MessagingException {
|
||||
if (this.headers == null)
|
||||
loadHeaders();
|
||||
return this.headers.getHeader(name);
|
||||
}
|
||||
|
||||
public String getHeader(String name, String delimiter) throws MessagingException {
|
||||
if (this.headers == null)
|
||||
loadHeaders();
|
||||
return this.headers.getHeader(name, delimiter);
|
||||
}
|
||||
|
||||
public void setHeader(String name, String value) throws MessagingException {
|
||||
throw new IllegalWriteException("POP3 messages are read-only");
|
||||
}
|
||||
|
||||
public void addHeader(String name, String value) throws MessagingException {
|
||||
throw new IllegalWriteException("POP3 messages are read-only");
|
||||
}
|
||||
|
||||
public void removeHeader(String name) throws MessagingException {
|
||||
throw new IllegalWriteException("POP3 messages are read-only");
|
||||
}
|
||||
|
||||
public Enumeration getAllHeaders() throws MessagingException {
|
||||
if (this.headers == null)
|
||||
loadHeaders();
|
||||
return this.headers.getAllHeaders();
|
||||
}
|
||||
|
||||
public Enumeration getMatchingHeaders(String[] names) throws MessagingException {
|
||||
if (this.headers == null)
|
||||
loadHeaders();
|
||||
return this.headers.getMatchingHeaders(names);
|
||||
}
|
||||
|
||||
public Enumeration getNonMatchingHeaders(String[] names) throws MessagingException {
|
||||
if (this.headers == null)
|
||||
loadHeaders();
|
||||
return this.headers.getNonMatchingHeaders(names);
|
||||
}
|
||||
|
||||
public void addHeaderLine(String line) throws MessagingException {
|
||||
throw new IllegalWriteException("POP3 messages are read-only");
|
||||
}
|
||||
|
||||
public Enumeration getAllHeaderLines() throws MessagingException {
|
||||
if (this.headers == null)
|
||||
loadHeaders();
|
||||
return this.headers.getAllHeaderLines();
|
||||
}
|
||||
|
||||
public Enumeration getMatchingHeaderLines(String[] names) throws MessagingException {
|
||||
if (this.headers == null)
|
||||
loadHeaders();
|
||||
return this.headers.getMatchingHeaderLines(names);
|
||||
}
|
||||
|
||||
public Enumeration getNonMatchingHeaderLines(String[] names) throws MessagingException {
|
||||
if (this.headers == null)
|
||||
loadHeaders();
|
||||
return this.headers.getNonMatchingHeaderLines(names);
|
||||
}
|
||||
|
||||
public void saveChanges() throws MessagingException {
|
||||
throw new IllegalWriteException("POP3 messages are read-only");
|
||||
}
|
||||
|
||||
public synchronized void writeTo(OutputStream os, String[] ignoreList) throws IOException, MessagingException {
|
||||
InputStream rawcontent = this.rawData.get();
|
||||
if (rawcontent == null && ignoreList == null &&
|
||||
!((POP3Store)this.folder.getStore()).cacheWriteTo) {
|
||||
if (this.folder.logger.isLoggable(Level.FINE))
|
||||
this.folder.logger.fine("streaming msg " + this.msgnum);
|
||||
if (!this.folder.getProtocol().retr(this.msgnum, os)) {
|
||||
this.expunged = true;
|
||||
throw new MessageRemovedException("can't retrieve message #" + this.msgnum + " in POP3Message.writeTo");
|
||||
}
|
||||
} else if (rawcontent != null && ignoreList == null) {
|
||||
InputStream in = ((SharedInputStream)rawcontent).newStream(0L, -1L);
|
||||
try {
|
||||
byte[] buf = new byte[16384];
|
||||
int len;
|
||||
while ((len = in.read(buf)) > 0)
|
||||
os.write(buf, 0, len);
|
||||
} finally {
|
||||
try {
|
||||
if (in != null)
|
||||
in.close();
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
} else {
|
||||
super.writeTo(os, ignoreList);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadHeaders() throws MessagingException {
|
||||
assert !Thread.holdsLock(this);
|
||||
try {
|
||||
boolean fetchContent = false;
|
||||
synchronized (this) {
|
||||
if (this.headers != null)
|
||||
return;
|
||||
InputStream hdrs = null;
|
||||
if (((POP3Store)this.folder.getStore()).disableTop || (
|
||||
hdrs = this.folder.getProtocol().top(this.msgnum, 0)) == null) {
|
||||
fetchContent = true;
|
||||
} else {
|
||||
try {
|
||||
this.hdrSize = hdrs.available();
|
||||
this.headers = new InternetHeaders(hdrs);
|
||||
} finally {
|
||||
hdrs.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fetchContent) {
|
||||
InputStream cs = null;
|
||||
try {
|
||||
cs = getContentStream();
|
||||
} finally {
|
||||
if (cs != null)
|
||||
cs.close();
|
||||
}
|
||||
}
|
||||
} catch (EOFException eex) {
|
||||
this.folder.close(false);
|
||||
throw new FolderClosedException(this.folder, eex.toString());
|
||||
} catch (IOException ex) {
|
||||
throw new MessagingException("error loading POP3 headers", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.sun.mail.pop3;
|
||||
|
||||
import javax.mail.Session;
|
||||
import javax.mail.URLName;
|
||||
|
||||
public class POP3SSLStore extends POP3Store {
|
||||
public POP3SSLStore(Session session, URLName url) {
|
||||
super(session, url, "pop3s", true);
|
||||
}
|
||||
}
|
||||
290
rus/WEB-INF/lib/javax.mail_src/com/sun/mail/pop3/POP3Store.java
Normal file
290
rus/WEB-INF/lib/javax.mail_src/com/sun/mail/pop3/POP3Store.java
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
package com.sun.mail.pop3;
|
||||
|
||||
import com.sun.mail.util.MailConnectException;
|
||||
import com.sun.mail.util.MailLogger;
|
||||
import com.sun.mail.util.PropUtil;
|
||||
import com.sun.mail.util.SocketConnectException;
|
||||
import java.io.EOFException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import javax.mail.AuthenticationFailedException;
|
||||
import javax.mail.Folder;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.Store;
|
||||
import javax.mail.URLName;
|
||||
|
||||
public class POP3Store extends Store {
|
||||
private String name = "pop3";
|
||||
|
||||
private int defaultPort = 110;
|
||||
|
||||
private boolean isSSL = false;
|
||||
|
||||
private Protocol port = null;
|
||||
|
||||
private POP3Folder portOwner = null;
|
||||
|
||||
private String host = null;
|
||||
|
||||
private int portNum = -1;
|
||||
|
||||
private String user = null;
|
||||
|
||||
private String passwd = null;
|
||||
|
||||
private boolean useStartTLS = false;
|
||||
|
||||
private boolean requireStartTLS = false;
|
||||
|
||||
private boolean usingSSL = false;
|
||||
|
||||
private Map capabilities;
|
||||
|
||||
private MailLogger logger;
|
||||
|
||||
volatile Constructor messageConstructor = null;
|
||||
|
||||
volatile boolean rsetBeforeQuit = false;
|
||||
|
||||
volatile boolean disableTop = false;
|
||||
|
||||
volatile boolean forgetTopHeaders = false;
|
||||
|
||||
volatile boolean supportsUidl = true;
|
||||
|
||||
volatile boolean cacheWriteTo = false;
|
||||
|
||||
volatile boolean useFileCache = false;
|
||||
|
||||
volatile File fileCacheDir = null;
|
||||
|
||||
volatile boolean keepMessageContent = false;
|
||||
|
||||
public POP3Store(Session session, URLName url) {
|
||||
this(session, url, "pop3", false);
|
||||
}
|
||||
|
||||
public POP3Store(Session session, URLName url, String name, boolean isSSL) {
|
||||
super(session, url);
|
||||
if (url != null)
|
||||
name = url.getProtocol();
|
||||
this.name = name;
|
||||
this.logger = new MailLogger(getClass(), "DEBUG POP3", session);
|
||||
if (!isSSL)
|
||||
isSSL = PropUtil.getBooleanSessionProperty(session, "mail." + name + ".ssl.enable", false);
|
||||
if (isSSL) {
|
||||
this.defaultPort = 995;
|
||||
} else {
|
||||
this.defaultPort = 110;
|
||||
}
|
||||
this.isSSL = isSSL;
|
||||
this.rsetBeforeQuit = getBoolProp("rsetbeforequit");
|
||||
this.disableTop = getBoolProp("disabletop");
|
||||
this.forgetTopHeaders = getBoolProp("forgettopheaders");
|
||||
this.cacheWriteTo = getBoolProp("cachewriteto");
|
||||
this.useFileCache = getBoolProp("filecache.enable");
|
||||
String dir = session.getProperty("mail." + name + ".filecache.dir");
|
||||
if (dir != null && this.logger.isLoggable(Level.CONFIG))
|
||||
this.logger.config("mail." + name + ".filecache.dir: " + dir);
|
||||
if (dir != null)
|
||||
this.fileCacheDir = new File(dir);
|
||||
this.keepMessageContent = getBoolProp("keepmessagecontent");
|
||||
this.useStartTLS = getBoolProp("starttls.enable");
|
||||
this.requireStartTLS = getBoolProp("starttls.required");
|
||||
String s = session.getProperty("mail." + name + ".message.class");
|
||||
if (s != null) {
|
||||
this.logger.log(Level.CONFIG, "message class: {0}", s);
|
||||
try {
|
||||
ClassLoader cl = getClass().getClassLoader();
|
||||
Class<?> messageClass = null;
|
||||
try {
|
||||
messageClass = Class.forName(s, false, cl);
|
||||
} catch (ClassNotFoundException ex1) {
|
||||
messageClass = Class.forName(s);
|
||||
}
|
||||
Class[] c = { Folder.class, int.class };
|
||||
this.messageConstructor = messageClass.getConstructor(c);
|
||||
} catch (Exception ex) {
|
||||
this.logger.log(Level.CONFIG, "failed to load message class", (Throwable)ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final synchronized boolean getBoolProp(String prop) {
|
||||
prop = "mail." + this.name + "." + prop;
|
||||
boolean val = PropUtil.getBooleanSessionProperty(this.session, prop, false);
|
||||
if (this.logger.isLoggable(Level.CONFIG))
|
||||
this.logger.config(prop + ": " + val);
|
||||
return val;
|
||||
}
|
||||
|
||||
synchronized Session getSession() {
|
||||
return this.session;
|
||||
}
|
||||
|
||||
protected synchronized boolean protocolConnect(String host, int portNum, String user, String passwd) throws MessagingException {
|
||||
if (host == null || passwd == null || user == null)
|
||||
return false;
|
||||
if (portNum == -1)
|
||||
portNum = PropUtil.getIntSessionProperty(this.session, "mail." + this.name + ".port", -1);
|
||||
if (portNum == -1)
|
||||
portNum = this.defaultPort;
|
||||
this.host = host;
|
||||
this.portNum = portNum;
|
||||
this.user = user;
|
||||
this.passwd = passwd;
|
||||
try {
|
||||
this.port = getPort(null);
|
||||
} catch (EOFException eex) {
|
||||
throw new AuthenticationFailedException(eex.getMessage());
|
||||
} catch (SocketConnectException scex) {
|
||||
throw new MailConnectException(scex);
|
||||
} catch (IOException ioex) {
|
||||
throw new MessagingException("Connect failed", ioex);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public synchronized boolean isConnected() {
|
||||
if (!super.isConnected())
|
||||
return false;
|
||||
try {
|
||||
if (this.port == null) {
|
||||
this.port = getPort(null);
|
||||
} else if (!this.port.noop()) {
|
||||
throw new IOException("NOOP failed");
|
||||
}
|
||||
return true;
|
||||
} catch (IOException ioex) {
|
||||
try {
|
||||
super.close();
|
||||
} catch (MessagingException e) {
|
||||
|
||||
} finally {
|
||||
return false;
|
||||
}
|
||||
while (true);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized Protocol getPort(POP3Folder owner) throws IOException {
|
||||
if (this.port != null && this.portOwner == null) {
|
||||
this.portOwner = owner;
|
||||
return this.port;
|
||||
}
|
||||
Protocol p = new Protocol(this.host, this.portNum, this.logger,
|
||||
this.session.getProperties(), "mail." + this.name, this.isSSL);
|
||||
if (this.useStartTLS || this.requireStartTLS)
|
||||
if (p.hasCapability("STLS")) {
|
||||
if (p.stls()) {
|
||||
p.setCapabilities(p.capa());
|
||||
} else if (this.requireStartTLS) {
|
||||
this.logger.fine("STLS required but failed");
|
||||
try {
|
||||
p.quit();
|
||||
} catch (IOException e) {
|
||||
|
||||
} finally {
|
||||
throw new EOFException("STLS required but failed");
|
||||
}
|
||||
}
|
||||
} else if (this.requireStartTLS) {
|
||||
this.logger.fine("STLS required but not supported");
|
||||
try {
|
||||
p.quit();
|
||||
} catch (IOException e) {
|
||||
|
||||
} finally {
|
||||
throw new EOFException("STLS required but not supported");
|
||||
}
|
||||
}
|
||||
this.capabilities = p.getCapabilities();
|
||||
this.usingSSL = p.isSSL();
|
||||
if (!this.disableTop && this.capabilities != null &&
|
||||
!this.capabilities.containsKey("TOP")) {
|
||||
this.disableTop = true;
|
||||
this.logger.fine("server doesn't support TOP, disabling it");
|
||||
}
|
||||
this.supportsUidl = (this.capabilities == null || this.capabilities.containsKey("UIDL"));
|
||||
String msg = null;
|
||||
if ((msg = p.login(this.user, this.passwd)) != null)
|
||||
try {
|
||||
p.quit();
|
||||
} catch (IOException e) {
|
||||
|
||||
} finally {
|
||||
throw new EOFException(msg);
|
||||
}
|
||||
if (this.port == null && owner != null) {
|
||||
this.port = p;
|
||||
this.portOwner = owner;
|
||||
}
|
||||
if (this.portOwner == null)
|
||||
this.portOwner = owner;
|
||||
return p;
|
||||
}
|
||||
|
||||
synchronized void closePort(POP3Folder owner) {
|
||||
if (this.portOwner == owner) {
|
||||
this.port = null;
|
||||
this.portOwner = null;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void close() throws MessagingException {
|
||||
try {
|
||||
if (this.port != null)
|
||||
this.port.quit();
|
||||
} catch (IOException e) {
|
||||
|
||||
} finally {
|
||||
this.port = null;
|
||||
super.close();
|
||||
}
|
||||
}
|
||||
|
||||
public Folder getDefaultFolder() throws MessagingException {
|
||||
checkConnected();
|
||||
return new DefaultFolder(this);
|
||||
}
|
||||
|
||||
public Folder getFolder(String name) throws MessagingException {
|
||||
checkConnected();
|
||||
return new POP3Folder(this, name);
|
||||
}
|
||||
|
||||
public Folder getFolder(URLName url) throws MessagingException {
|
||||
checkConnected();
|
||||
return new POP3Folder(this, url.getFile());
|
||||
}
|
||||
|
||||
public Map capabilities() throws MessagingException {
|
||||
Map<?, ?> c;
|
||||
synchronized (this) {
|
||||
c = this.capabilities;
|
||||
}
|
||||
if (c != null)
|
||||
return Collections.unmodifiableMap(c);
|
||||
return Collections.EMPTY_MAP;
|
||||
}
|
||||
|
||||
public synchronized boolean isSSL() {
|
||||
return this.usingSSL;
|
||||
}
|
||||
|
||||
protected void finalize() throws Throwable {
|
||||
super.finalize();
|
||||
if (this.port != null)
|
||||
close();
|
||||
}
|
||||
|
||||
private void checkConnected() throws MessagingException {
|
||||
if (!super.isConnected())
|
||||
throw new MessagingException("Not connected");
|
||||
}
|
||||
}
|
||||
624
rus/WEB-INF/lib/javax.mail_src/com/sun/mail/pop3/Protocol.java
Normal file
624
rus/WEB-INF/lib/javax.mail_src/com/sun/mail/pop3/Protocol.java
Normal file
|
|
@ -0,0 +1,624 @@
|
|||
package com.sun.mail.pop3;
|
||||
|
||||
import com.sun.mail.util.LineInputStream;
|
||||
import com.sun.mail.util.MailLogger;
|
||||
import com.sun.mail.util.PropUtil;
|
||||
import com.sun.mail.util.SharedByteArrayOutputStream;
|
||||
import com.sun.mail.util.SocketFetcher;
|
||||
import com.sun.mail.util.TraceInputStream;
|
||||
import com.sun.mail.util.TraceOutputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.logging.Level;
|
||||
|
||||
class Protocol {
|
||||
private Socket socket;
|
||||
|
||||
private String host;
|
||||
|
||||
private Properties props;
|
||||
|
||||
private String prefix;
|
||||
|
||||
private BufferedReader input;
|
||||
|
||||
private PrintWriter output;
|
||||
|
||||
private TraceInputStream traceInput;
|
||||
|
||||
private TraceOutputStream traceOutput;
|
||||
|
||||
private MailLogger logger;
|
||||
|
||||
private MailLogger traceLogger;
|
||||
|
||||
private String apopChallenge;
|
||||
|
||||
private Map capabilities;
|
||||
|
||||
private boolean pipelining;
|
||||
|
||||
private boolean noauthdebug;
|
||||
|
||||
private boolean traceSuspended;
|
||||
|
||||
private static final int POP3_PORT = 110;
|
||||
|
||||
private static final String CRLF = "\r\n";
|
||||
|
||||
private static final int SLOP = 128;
|
||||
|
||||
Protocol(String host, int port, MailLogger logger, Properties props, String prefix, boolean isSSL) throws IOException {
|
||||
Response r;
|
||||
this.apopChallenge = null;
|
||||
this.capabilities = null;
|
||||
this.noauthdebug = true;
|
||||
this.host = host;
|
||||
this.props = props;
|
||||
this.prefix = prefix;
|
||||
this.logger = logger;
|
||||
this.traceLogger = logger.getSubLogger("protocol", null);
|
||||
this.noauthdebug = !PropUtil.getBooleanProperty(props, "mail.debug.auth", false);
|
||||
boolean enableAPOP = getBoolProp(props, prefix + ".apop.enable");
|
||||
boolean disableCapa = getBoolProp(props, prefix + ".disablecapa");
|
||||
try {
|
||||
if (port == -1)
|
||||
port = 110;
|
||||
if (logger.isLoggable(Level.FINE))
|
||||
logger.fine("connecting to host \"" + host + "\", port " + port + ", isSSL " + isSSL);
|
||||
this.socket = SocketFetcher.getSocket(host, port, props, prefix, isSSL);
|
||||
initStreams();
|
||||
r = simpleCommand(null);
|
||||
} catch (IOException ioe) {
|
||||
try {
|
||||
this.socket.close();
|
||||
} finally {
|
||||
throw ioe;
|
||||
}
|
||||
}
|
||||
if (!r.ok)
|
||||
try {
|
||||
this.socket.close();
|
||||
} finally {
|
||||
throw new IOException("Connect failed");
|
||||
}
|
||||
if (enableAPOP) {
|
||||
int challStart = r.data.indexOf('<');
|
||||
int challEnd = r.data.indexOf('>', challStart);
|
||||
if (challStart != -1 && challEnd != -1)
|
||||
this.apopChallenge = r.data.substring(challStart, challEnd + 1);
|
||||
logger.log(Level.FINE, "APOP challenge: {0}", this.apopChallenge);
|
||||
}
|
||||
if (!disableCapa)
|
||||
setCapabilities(capa());
|
||||
this
|
||||
.pipelining = (hasCapability("PIPELINING") || PropUtil.getBooleanProperty(props, prefix + ".pipelining", false));
|
||||
if (this.pipelining)
|
||||
logger.config("PIPELINING enabled");
|
||||
}
|
||||
|
||||
private final synchronized boolean getBoolProp(Properties props, String prop) {
|
||||
boolean val = PropUtil.getBooleanProperty(props, prop, false);
|
||||
if (this.logger.isLoggable(Level.CONFIG))
|
||||
this.logger.config(prop + ": " + val);
|
||||
return val;
|
||||
}
|
||||
|
||||
private void initStreams() throws IOException {
|
||||
boolean quote = PropUtil.getBooleanProperty(this.props, "mail.debug.quote", false);
|
||||
this
|
||||
.traceInput = new TraceInputStream(this.socket.getInputStream(), this.traceLogger);
|
||||
this.traceInput.setQuote(quote);
|
||||
this
|
||||
.traceOutput = new TraceOutputStream(this.socket.getOutputStream(), this.traceLogger);
|
||||
this.traceOutput.setQuote(quote);
|
||||
this.input = new BufferedReader(new InputStreamReader(this.traceInput, "iso-8859-1"));
|
||||
this.output = new PrintWriter(new BufferedWriter(new OutputStreamWriter(this.traceOutput, "iso-8859-1")));
|
||||
}
|
||||
|
||||
protected void finalize() throws Throwable {
|
||||
super.finalize();
|
||||
if (this.socket != null)
|
||||
quit();
|
||||
}
|
||||
|
||||
synchronized void setCapabilities(InputStream in) {
|
||||
if (in == null) {
|
||||
this.capabilities = null;
|
||||
return;
|
||||
}
|
||||
this.capabilities = new HashMap(10);
|
||||
BufferedReader r = null;
|
||||
try {
|
||||
r = new BufferedReader(new InputStreamReader(in, "us-ascii"));
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
assert false;
|
||||
}
|
||||
while (true) {
|
||||
try {
|
||||
String s;
|
||||
if ((s = r.readLine()) != null) {
|
||||
String cap = s;
|
||||
int i = cap.indexOf(' ');
|
||||
if (i > 0)
|
||||
cap = cap.substring(0, i);
|
||||
this.capabilities.put(cap.toUpperCase(Locale.ENGLISH), s);
|
||||
continue;
|
||||
}
|
||||
} catch (IOException e) {}
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException e) {}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
synchronized boolean hasCapability(String c) {
|
||||
return (this.capabilities != null &&
|
||||
this.capabilities.containsKey(c.toUpperCase(Locale.ENGLISH)));
|
||||
}
|
||||
|
||||
synchronized Map getCapabilities() {
|
||||
return this.capabilities;
|
||||
}
|
||||
|
||||
synchronized String login(String user, String password) throws IOException {
|
||||
boolean batch = (this.pipelining && this.socket instanceof javax.net.ssl.SSLSocket);
|
||||
try {
|
||||
Response r;
|
||||
if (this.noauthdebug && isTracing()) {
|
||||
this.logger.fine("authentication command trace suppressed");
|
||||
suspendTracing();
|
||||
}
|
||||
String dpw = null;
|
||||
if (this.apopChallenge != null)
|
||||
dpw = getDigest(password);
|
||||
if (this.apopChallenge != null && dpw != null) {
|
||||
r = simpleCommand("APOP " + user + " " + dpw);
|
||||
} else if (batch) {
|
||||
String cmd = "USER " + user;
|
||||
batchCommandStart(cmd);
|
||||
issueCommand(cmd);
|
||||
cmd = "PASS " + password;
|
||||
batchCommandContinue(cmd);
|
||||
issueCommand(cmd);
|
||||
r = readResponse();
|
||||
if (!r.ok) {
|
||||
String err = (r.data != null) ? r.data : "USER command failed";
|
||||
readResponse();
|
||||
batchCommandEnd();
|
||||
return err;
|
||||
}
|
||||
r = readResponse();
|
||||
batchCommandEnd();
|
||||
} else {
|
||||
r = simpleCommand("USER " + user);
|
||||
if (!r.ok)
|
||||
return (r.data != null) ? r.data : "USER command failed";
|
||||
r = simpleCommand("PASS " + password);
|
||||
}
|
||||
if (this.noauthdebug && isTracing())
|
||||
this.logger.log(Level.FINE, "authentication command {0}", r.ok ? "succeeded" : "failed");
|
||||
if (!r.ok)
|
||||
return (r.data != null) ? r.data : "login failed";
|
||||
return null;
|
||||
} finally {
|
||||
resumeTracing();
|
||||
}
|
||||
}
|
||||
|
||||
private String getDigest(String password) {
|
||||
byte[] digest;
|
||||
String key = this.apopChallenge + password;
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
digest = md.digest(key.getBytes("iso-8859-1"));
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
return null;
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
return null;
|
||||
}
|
||||
return toHex(digest);
|
||||
}
|
||||
|
||||
private static char[] digits = new char[] {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'a', 'b', 'c', 'd', 'e', 'f' };
|
||||
|
||||
private static String toHex(byte[] bytes) {
|
||||
char[] result = new char[bytes.length * 2];
|
||||
for (int index = 0, i = 0; index < bytes.length; index++) {
|
||||
int temp = bytes[index] & 0xFF;
|
||||
result[i++] = digits[temp >> 4];
|
||||
result[i++] = digits[temp & 0xF];
|
||||
}
|
||||
return new String(result);
|
||||
}
|
||||
|
||||
synchronized boolean quit() throws IOException {
|
||||
boolean ok = false;
|
||||
try {
|
||||
Response r = simpleCommand("QUIT");
|
||||
ok = r.ok;
|
||||
} finally {
|
||||
try {
|
||||
this.socket.close();
|
||||
} finally {
|
||||
this.socket = null;
|
||||
this.input = null;
|
||||
this.output = null;
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
synchronized Status stat() throws IOException {
|
||||
Response r = simpleCommand("STAT");
|
||||
Status s = new Status();
|
||||
if (!r.ok)
|
||||
throw new IOException("STAT command failed: " + r.data);
|
||||
if (r.data != null)
|
||||
try {
|
||||
StringTokenizer st = new StringTokenizer(r.data);
|
||||
s.total = Integer.parseInt(st.nextToken());
|
||||
s.size = Integer.parseInt(st.nextToken());
|
||||
} catch (RuntimeException e) {}
|
||||
return s;
|
||||
}
|
||||
|
||||
synchronized int list(int msg) throws IOException {
|
||||
Response r = simpleCommand("LIST " + msg);
|
||||
int size = -1;
|
||||
if (r.ok && r.data != null)
|
||||
try {
|
||||
StringTokenizer st = new StringTokenizer(r.data);
|
||||
st.nextToken();
|
||||
size = Integer.parseInt(st.nextToken());
|
||||
} catch (RuntimeException e) {}
|
||||
return size;
|
||||
}
|
||||
|
||||
synchronized InputStream list() throws IOException {
|
||||
Response r = multilineCommand("LIST", 128);
|
||||
return r.bytes;
|
||||
}
|
||||
|
||||
synchronized InputStream retr(int msg, int size) throws IOException {
|
||||
Response r;
|
||||
boolean batch = (size == 0 && this.pipelining);
|
||||
if (batch) {
|
||||
String cmd = "LIST " + msg;
|
||||
batchCommandStart(cmd);
|
||||
issueCommand(cmd);
|
||||
cmd = "RETR " + msg;
|
||||
batchCommandContinue(cmd);
|
||||
issueCommand(cmd);
|
||||
r = readResponse();
|
||||
if (r.ok && r.data != null)
|
||||
try {
|
||||
StringTokenizer st = new StringTokenizer(r.data);
|
||||
st.nextToken();
|
||||
size = Integer.parseInt(st.nextToken());
|
||||
if (size > 1073741824 || size < 0) {
|
||||
size = 0;
|
||||
} else {
|
||||
if (this.logger.isLoggable(Level.FINE))
|
||||
this.logger.fine("pipeline message size " + size);
|
||||
size += 128;
|
||||
}
|
||||
} catch (RuntimeException e) {}
|
||||
r = readResponse();
|
||||
if (r.ok)
|
||||
r.bytes = readMultilineResponse(size + 128);
|
||||
batchCommandEnd();
|
||||
} else {
|
||||
String cmd = "RETR " + msg;
|
||||
multilineCommandStart(cmd);
|
||||
issueCommand(cmd);
|
||||
r = readResponse();
|
||||
if (!r.ok) {
|
||||
multilineCommandEnd();
|
||||
return null;
|
||||
}
|
||||
if (size <= 0 && r.data != null)
|
||||
try {
|
||||
StringTokenizer st = new StringTokenizer(r.data);
|
||||
String s = st.nextToken();
|
||||
String octets = st.nextToken();
|
||||
if (octets.equals("octets")) {
|
||||
size = Integer.parseInt(s);
|
||||
if (size > 1073741824 || size < 0) {
|
||||
size = 0;
|
||||
} else {
|
||||
if (this.logger.isLoggable(Level.FINE))
|
||||
this.logger.fine("guessing message size: " + size);
|
||||
size += 128;
|
||||
}
|
||||
}
|
||||
} catch (RuntimeException e) {}
|
||||
r.bytes = readMultilineResponse(size);
|
||||
multilineCommandEnd();
|
||||
}
|
||||
if (r.ok &&
|
||||
size > 0 && this.logger.isLoggable(Level.FINE))
|
||||
this.logger.fine("got message size " + r.bytes.available());
|
||||
return r.bytes;
|
||||
}
|
||||
|
||||
synchronized boolean retr(int msg, OutputStream os) throws IOException {
|
||||
int b;
|
||||
String cmd = "RETR " + msg;
|
||||
multilineCommandStart(cmd);
|
||||
issueCommand(cmd);
|
||||
Response r = readResponse();
|
||||
if (!r.ok) {
|
||||
multilineCommandEnd();
|
||||
return false;
|
||||
}
|
||||
Throwable terr = null;
|
||||
int lastb = 10;
|
||||
try {
|
||||
while ((b = this.input.read()) >= 0) {
|
||||
if (lastb == 10 && b == 46) {
|
||||
b = this.input.read();
|
||||
if (b == 13) {
|
||||
b = this.input.read();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (terr == null)
|
||||
try {
|
||||
os.write(b);
|
||||
} catch (IOException ex) {
|
||||
this.logger.log(Level.FINE, "exception while streaming", (Throwable)ex);
|
||||
terr = ex;
|
||||
} catch (RuntimeException ex) {
|
||||
this.logger.log(Level.FINE, "exception while streaming", (Throwable)ex);
|
||||
terr = ex;
|
||||
}
|
||||
lastb = b;
|
||||
}
|
||||
} catch (InterruptedIOException iioex) {
|
||||
try {
|
||||
this.socket.close();
|
||||
} catch (IOException e) {}
|
||||
throw iioex;
|
||||
}
|
||||
if (b < 0)
|
||||
throw new EOFException("EOF on socket");
|
||||
if (terr != null) {
|
||||
if (terr instanceof IOException)
|
||||
throw (IOException)terr;
|
||||
if (terr instanceof RuntimeException)
|
||||
throw (RuntimeException)terr;
|
||||
assert false;
|
||||
}
|
||||
multilineCommandEnd();
|
||||
return true;
|
||||
}
|
||||
|
||||
synchronized InputStream top(int msg, int n) throws IOException {
|
||||
Response r = multilineCommand("TOP " + msg + " " + n, 0);
|
||||
return r.bytes;
|
||||
}
|
||||
|
||||
synchronized boolean dele(int msg) throws IOException {
|
||||
Response r = simpleCommand("DELE " + msg);
|
||||
return r.ok;
|
||||
}
|
||||
|
||||
synchronized String uidl(int msg) throws IOException {
|
||||
Response r = simpleCommand("UIDL " + msg);
|
||||
if (!r.ok)
|
||||
return null;
|
||||
int i = r.data.indexOf(' ');
|
||||
if (i > 0)
|
||||
return r.data.substring(i + 1);
|
||||
return null;
|
||||
}
|
||||
|
||||
synchronized boolean uidl(String[] uids) throws IOException {
|
||||
Response r = multilineCommand("UIDL", 15 * uids.length);
|
||||
if (!r.ok)
|
||||
return false;
|
||||
LineInputStream lis = new LineInputStream(r.bytes);
|
||||
String line = null;
|
||||
while ((line = lis.readLine()) != null) {
|
||||
int i = line.indexOf(' ');
|
||||
if (i < 1 || i >= line.length())
|
||||
continue;
|
||||
int n = Integer.parseInt(line.substring(0, i));
|
||||
if (n > 0 && n <= uids.length)
|
||||
uids[n - 1] = line.substring(i + 1);
|
||||
}
|
||||
try {
|
||||
r.bytes.close();
|
||||
} catch (IOException e) {}
|
||||
return true;
|
||||
}
|
||||
|
||||
synchronized boolean noop() throws IOException {
|
||||
Response r = simpleCommand("NOOP");
|
||||
return r.ok;
|
||||
}
|
||||
|
||||
synchronized boolean rset() throws IOException {
|
||||
Response r = simpleCommand("RSET");
|
||||
return r.ok;
|
||||
}
|
||||
|
||||
synchronized boolean stls() throws IOException {
|
||||
if (this.socket instanceof javax.net.ssl.SSLSocket)
|
||||
return true;
|
||||
Response r = simpleCommand("STLS");
|
||||
if (r.ok)
|
||||
try {
|
||||
this.socket = SocketFetcher.startTLS(this.socket, this.host, this.props, this.prefix);
|
||||
initStreams();
|
||||
} catch (IOException ioex) {
|
||||
try {
|
||||
this.socket.close();
|
||||
} finally {
|
||||
this.socket = null;
|
||||
this.input = null;
|
||||
this.output = null;
|
||||
}
|
||||
IOException sioex = new IOException("Could not convert socket to TLS");
|
||||
sioex.initCause(ioex);
|
||||
throw sioex;
|
||||
}
|
||||
return r.ok;
|
||||
}
|
||||
|
||||
synchronized boolean isSSL() {
|
||||
return this.socket instanceof javax.net.ssl.SSLSocket;
|
||||
}
|
||||
|
||||
synchronized InputStream capa() throws IOException {
|
||||
Response r = multilineCommand("CAPA", 128);
|
||||
if (!r.ok)
|
||||
return null;
|
||||
return r.bytes;
|
||||
}
|
||||
|
||||
private Response simpleCommand(String cmd) throws IOException {
|
||||
simpleCommandStart(cmd);
|
||||
issueCommand(cmd);
|
||||
Response r = readResponse();
|
||||
simpleCommandEnd();
|
||||
return r;
|
||||
}
|
||||
|
||||
private void issueCommand(String cmd) throws IOException {
|
||||
if (this.socket == null)
|
||||
throw new IOException("Folder is closed");
|
||||
if (cmd != null) {
|
||||
cmd = cmd + "\r\n";
|
||||
this.output.print(cmd);
|
||||
this.output.flush();
|
||||
}
|
||||
}
|
||||
|
||||
private Response readResponse() throws IOException {
|
||||
String line = null;
|
||||
try {
|
||||
line = this.input.readLine();
|
||||
} catch (InterruptedIOException iioex) {
|
||||
try {
|
||||
this.socket.close();
|
||||
} catch (IOException e) {}
|
||||
throw new EOFException(iioex.getMessage());
|
||||
} catch (SocketException ex) {
|
||||
try {
|
||||
this.socket.close();
|
||||
} catch (IOException e) {}
|
||||
throw new EOFException(ex.getMessage());
|
||||
}
|
||||
if (line == null) {
|
||||
this.traceLogger.finest("<EOF>");
|
||||
throw new EOFException("EOF on socket");
|
||||
}
|
||||
Response r = new Response();
|
||||
if (line.startsWith("+OK")) {
|
||||
r.ok = true;
|
||||
} else if (line.startsWith("-ERR")) {
|
||||
r.ok = false;
|
||||
} else {
|
||||
throw new IOException("Unexpected response: " + line);
|
||||
}
|
||||
int i;
|
||||
if ((i = line.indexOf(' ')) >= 0)
|
||||
r.data = line.substring(i + 1);
|
||||
return r;
|
||||
}
|
||||
|
||||
private Response multilineCommand(String cmd, int size) throws IOException {
|
||||
multilineCommandStart(cmd);
|
||||
issueCommand(cmd);
|
||||
Response r = readResponse();
|
||||
if (!r.ok) {
|
||||
multilineCommandEnd();
|
||||
return r;
|
||||
}
|
||||
r.bytes = readMultilineResponse(size);
|
||||
multilineCommandEnd();
|
||||
return r;
|
||||
}
|
||||
|
||||
private InputStream readMultilineResponse(int size) throws IOException {
|
||||
int b;
|
||||
SharedByteArrayOutputStream buf = new SharedByteArrayOutputStream(size);
|
||||
int lastb = 10;
|
||||
try {
|
||||
while ((b = this.input.read()) >= 0) {
|
||||
if (lastb == 10 && b == 46) {
|
||||
b = this.input.read();
|
||||
if (b == 13) {
|
||||
b = this.input.read();
|
||||
break;
|
||||
}
|
||||
}
|
||||
buf.write(b);
|
||||
lastb = b;
|
||||
}
|
||||
} catch (InterruptedIOException iioex) {
|
||||
try {
|
||||
this.socket.close();
|
||||
} catch (IOException e) {}
|
||||
throw iioex;
|
||||
}
|
||||
if (b < 0)
|
||||
throw new EOFException("EOF on socket");
|
||||
return buf.toStream();
|
||||
}
|
||||
|
||||
protected boolean isTracing() {
|
||||
return this.traceLogger.isLoggable(Level.FINEST);
|
||||
}
|
||||
|
||||
private void suspendTracing() {
|
||||
if (this.traceLogger.isLoggable(Level.FINEST)) {
|
||||
this.traceInput.setTrace(false);
|
||||
this.traceOutput.setTrace(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void resumeTracing() {
|
||||
if (this.traceLogger.isLoggable(Level.FINEST)) {
|
||||
this.traceInput.setTrace(true);
|
||||
this.traceOutput.setTrace(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void simpleCommandStart(String command) {}
|
||||
|
||||
private void simpleCommandEnd() {}
|
||||
|
||||
private void multilineCommandStart(String command) {}
|
||||
|
||||
private void multilineCommandEnd() {}
|
||||
|
||||
private void batchCommandStart(String command) {}
|
||||
|
||||
private void batchCommandContinue(String command) {}
|
||||
|
||||
private void batchCommandEnd() {}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.sun.mail.pop3;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
class Response {
|
||||
boolean ok = false;
|
||||
|
||||
String data = null;
|
||||
|
||||
InputStream bytes = null;
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package com.sun.mail.pop3;
|
||||
|
||||
class Status {
|
||||
int total = 0;
|
||||
|
||||
int size = 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package com.sun.mail.pop3;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
class TempFile {
|
||||
private File file;
|
||||
|
||||
private WritableSharedFile sf;
|
||||
|
||||
public TempFile(File dir) throws IOException {
|
||||
this.file = File.createTempFile("pop3.", ".mbox", dir);
|
||||
this.file.deleteOnExit();
|
||||
this.sf = new WritableSharedFile(this.file);
|
||||
}
|
||||
|
||||
public AppendStream getAppendStream() throws IOException {
|
||||
return this.sf.getAppendStream();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
try {
|
||||
this.sf.close();
|
||||
} catch (IOException e) {}
|
||||
this.file.delete();
|
||||
}
|
||||
|
||||
protected void finalize() throws Throwable {
|
||||
super.finalize();
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
package com.sun.mail.pop3;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import javax.mail.util.SharedFileInputStream;
|
||||
|
||||
class WritableSharedFile extends SharedFileInputStream {
|
||||
private RandomAccessFile raf;
|
||||
|
||||
private AppendStream af;
|
||||
|
||||
public WritableSharedFile(File file) throws IOException {
|
||||
super(file);
|
||||
try {
|
||||
this.raf = new RandomAccessFile(file, "rw");
|
||||
} catch (IOException ex) {
|
||||
super.close();
|
||||
}
|
||||
}
|
||||
|
||||
public RandomAccessFile getWritableFile() {
|
||||
return this.raf;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
try {
|
||||
super.close();
|
||||
} finally {
|
||||
this.raf.close();
|
||||
}
|
||||
}
|
||||
|
||||
synchronized long updateLength() throws IOException {
|
||||
this.datalen = this.in.length();
|
||||
this.af = null;
|
||||
return this.datalen;
|
||||
}
|
||||
|
||||
public synchronized AppendStream getAppendStream() throws IOException {
|
||||
if (this.af != null)
|
||||
throw new IOException("POP3 file cache only supports single threaded access");
|
||||
this.af = new AppendStream(this);
|
||||
return this.af;
|
||||
}
|
||||
}
|
||||
136
rus/WEB-INF/lib/javax.mail_src/com/sun/mail/smtp/DigestMD5.java
Normal file
136
rus/WEB-INF/lib/javax.mail_src/com/sun/mail/smtp/DigestMD5.java
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
package com.sun.mail.smtp;
|
||||
|
||||
import com.sun.mail.util.ASCIIUtility;
|
||||
import com.sun.mail.util.BASE64DecoderStream;
|
||||
import com.sun.mail.util.BASE64EncoderStream;
|
||||
import com.sun.mail.util.MailLogger;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.StreamTokenizer;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Hashtable;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class DigestMD5 {
|
||||
private MailLogger logger;
|
||||
|
||||
private MessageDigest md5;
|
||||
|
||||
private String uri;
|
||||
|
||||
private String clientResponse;
|
||||
|
||||
public DigestMD5(MailLogger logger) {
|
||||
this.logger = logger.getLogger(getClass(), "DEBUG DIGEST-MD5");
|
||||
logger.config("DIGEST-MD5 Loaded");
|
||||
}
|
||||
|
||||
public byte[] authClient(String host, String user, String passwd, String realm, String serverChallenge) throws IOException {
|
||||
SecureRandom random;
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
OutputStream b64os = new BASE64EncoderStream(bos, Integer.MAX_VALUE);
|
||||
try {
|
||||
random = new SecureRandom();
|
||||
this.md5 = MessageDigest.getInstance("MD5");
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
this.logger.log(Level.FINE, "NoSuchAlgorithmException", (Throwable)ex);
|
||||
throw new IOException(ex.toString());
|
||||
}
|
||||
StringBuffer result = new StringBuffer();
|
||||
this.uri = "smtp/" + host;
|
||||
String nc = "00000001";
|
||||
String qop = "auth";
|
||||
byte[] bytes = new byte[32];
|
||||
this.logger.fine("Begin authentication ...");
|
||||
Hashtable map = tokenize(serverChallenge);
|
||||
if (realm == null) {
|
||||
String text = (String)map.get("realm");
|
||||
realm = (text != null) ? new StringTokenizer(text, ",").nextToken() : host;
|
||||
}
|
||||
String nonce = (String)map.get("nonce");
|
||||
random.nextBytes(bytes);
|
||||
b64os.write(bytes);
|
||||
b64os.flush();
|
||||
String cnonce = bos.toString("iso-8859-1");
|
||||
bos.reset();
|
||||
this.md5.update(this.md5.digest(
|
||||
ASCIIUtility.getBytes(user + ":" + realm + ":" + passwd)));
|
||||
this.md5.update(ASCIIUtility.getBytes(":" + nonce + ":" + cnonce));
|
||||
this.clientResponse = toHex(this.md5.digest()) + ":" + nonce + ":" + nc + ":" + cnonce + ":" + qop + ":";
|
||||
this.md5.update(ASCIIUtility.getBytes("AUTHENTICATE:" + this.uri));
|
||||
this.md5.update(ASCIIUtility.getBytes(this.clientResponse + toHex(this.md5.digest())));
|
||||
result.append("username=\"" + user + "\"");
|
||||
result.append(",realm=\"" + realm + "\"");
|
||||
result.append(",qop=" + qop);
|
||||
result.append(",nc=" + nc);
|
||||
result.append(",nonce=\"" + nonce + "\"");
|
||||
result.append(",cnonce=\"" + cnonce + "\"");
|
||||
result.append(",digest-uri=\"" + this.uri + "\"");
|
||||
result.append(",response=" + toHex(this.md5.digest()));
|
||||
if (this.logger.isLoggable(Level.FINE))
|
||||
this.logger.fine("Response => " + result.toString());
|
||||
b64os.write(ASCIIUtility.getBytes(result.toString()));
|
||||
b64os.flush();
|
||||
return bos.toByteArray();
|
||||
}
|
||||
|
||||
public boolean authServer(String serverResponse) throws IOException {
|
||||
Hashtable map = tokenize(serverResponse);
|
||||
this.md5.update(ASCIIUtility.getBytes(":" + this.uri));
|
||||
this.md5.update(ASCIIUtility.getBytes(this.clientResponse + toHex(this.md5.digest())));
|
||||
String text = toHex(this.md5.digest());
|
||||
if (!text.equals(map.get("rspauth"))) {
|
||||
if (this.logger.isLoggable(Level.FINE))
|
||||
this.logger.fine("Expected => rspauth=" + text);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private Hashtable tokenize(String serverResponse) throws IOException {
|
||||
Hashtable<String, String> map = new Hashtable();
|
||||
byte[] bytes = serverResponse.getBytes("iso-8859-1");
|
||||
String key = null;
|
||||
StreamTokenizer tokens = new StreamTokenizer(new InputStreamReader(new BASE64DecoderStream(new ByteArrayInputStream(bytes, 4, bytes.length - 4)), "iso-8859-1"));
|
||||
tokens.ordinaryChars(48, 57);
|
||||
tokens.wordChars(48, 57);
|
||||
int ttype;
|
||||
while ((ttype = tokens.nextToken()) != -1) {
|
||||
switch (ttype) {
|
||||
case -3:
|
||||
if (key == null)
|
||||
key = tokens.sval;
|
||||
case 34:
|
||||
if (this.logger.isLoggable(Level.FINE))
|
||||
this.logger.fine("Received => " + key + "='" + tokens.sval + "'");
|
||||
if (map.containsKey(key)) {
|
||||
map.put(key, new StringBuilder().append((Object)map.get(key)).append(",").append(tokens.sval).toString());
|
||||
} else {
|
||||
map.put(key, tokens.sval);
|
||||
}
|
||||
key = null;
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private static char[] digits = new char[] {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'a', 'b', 'c', 'd', 'e', 'f' };
|
||||
|
||||
private static String toHex(byte[] bytes) {
|
||||
char[] result = new char[bytes.length * 2];
|
||||
for (int index = 0, i = 0; index < bytes.length; index++) {
|
||||
int temp = bytes[index] & 0xFF;
|
||||
result[i++] = digits[temp >> 4];
|
||||
result[i++] = digits[temp & 0xF];
|
||||
}
|
||||
return new String(result);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package com.sun.mail.smtp;
|
||||
|
||||
import javax.mail.SendFailedException;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
|
||||
public class SMTPAddressFailedException extends SendFailedException {
|
||||
protected InternetAddress addr;
|
||||
|
||||
protected String cmd;
|
||||
|
||||
protected int rc;
|
||||
|
||||
private static final long serialVersionUID = 804831199768630097L;
|
||||
|
||||
public SMTPAddressFailedException(InternetAddress addr, String cmd, int rc, String err) {
|
||||
super(err);
|
||||
this.addr = addr;
|
||||
this.cmd = cmd;
|
||||
this.rc = rc;
|
||||
}
|
||||
|
||||
public InternetAddress getAddress() {
|
||||
return this.addr;
|
||||
}
|
||||
|
||||
public String getCommand() {
|
||||
return this.cmd;
|
||||
}
|
||||
|
||||
public int getReturnCode() {
|
||||
return this.rc;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package com.sun.mail.smtp;
|
||||
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
|
||||
public class SMTPAddressSucceededException extends MessagingException {
|
||||
protected InternetAddress addr;
|
||||
|
||||
protected String cmd;
|
||||
|
||||
protected int rc;
|
||||
|
||||
private static final long serialVersionUID = -1168335848623096749L;
|
||||
|
||||
public SMTPAddressSucceededException(InternetAddress addr, String cmd, int rc, String err) {
|
||||
super(err);
|
||||
this.addr = addr;
|
||||
this.cmd = cmd;
|
||||
this.rc = rc;
|
||||
}
|
||||
|
||||
public InternetAddress getAddress() {
|
||||
return this.addr;
|
||||
}
|
||||
|
||||
public String getCommand() {
|
||||
return this.cmd;
|
||||
}
|
||||
|
||||
public int getReturnCode() {
|
||||
return this.rc;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
package com.sun.mail.smtp;
|
||||
|
||||
import java.io.InputStream;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
|
||||
public class SMTPMessage extends MimeMessage {
|
||||
public static final int NOTIFY_NEVER = -1;
|
||||
|
||||
public static final int NOTIFY_SUCCESS = 1;
|
||||
|
||||
public static final int NOTIFY_FAILURE = 2;
|
||||
|
||||
public static final int NOTIFY_DELAY = 4;
|
||||
|
||||
public static final int RETURN_FULL = 1;
|
||||
|
||||
public static final int RETURN_HDRS = 2;
|
||||
|
||||
private static final String[] returnOptionString = new String[] { null, "FULL", "HDRS" };
|
||||
|
||||
private String envelopeFrom;
|
||||
|
||||
private int notifyOptions = 0;
|
||||
|
||||
private int returnOption = 0;
|
||||
|
||||
private boolean sendPartial = false;
|
||||
|
||||
private boolean allow8bitMIME = false;
|
||||
|
||||
private String submitter = null;
|
||||
|
||||
private String extension = null;
|
||||
|
||||
public SMTPMessage(Session session) {
|
||||
super(session);
|
||||
}
|
||||
|
||||
public SMTPMessage(Session session, InputStream is) throws MessagingException {
|
||||
super(session, is);
|
||||
}
|
||||
|
||||
public SMTPMessage(MimeMessage source) throws MessagingException {
|
||||
super(source);
|
||||
}
|
||||
|
||||
public void setEnvelopeFrom(String from) {
|
||||
this.envelopeFrom = from;
|
||||
}
|
||||
|
||||
public String getEnvelopeFrom() {
|
||||
return this.envelopeFrom;
|
||||
}
|
||||
|
||||
public void setNotifyOptions(int options) {
|
||||
if (options < -1 || options >= 8)
|
||||
throw new IllegalArgumentException("Bad return option");
|
||||
this.notifyOptions = options;
|
||||
}
|
||||
|
||||
public int getNotifyOptions() {
|
||||
return this.notifyOptions;
|
||||
}
|
||||
|
||||
String getDSNNotify() {
|
||||
if (this.notifyOptions == 0)
|
||||
return null;
|
||||
if (this.notifyOptions == -1)
|
||||
return "NEVER";
|
||||
StringBuffer sb = new StringBuffer();
|
||||
if ((this.notifyOptions & 0x1) != 0)
|
||||
sb.append("SUCCESS");
|
||||
if ((this.notifyOptions & 0x2) != 0) {
|
||||
if (sb.length() != 0)
|
||||
sb.append(',');
|
||||
sb.append("FAILURE");
|
||||
}
|
||||
if ((this.notifyOptions & 0x4) != 0) {
|
||||
if (sb.length() != 0)
|
||||
sb.append(',');
|
||||
sb.append("DELAY");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void setReturnOption(int option) {
|
||||
if (option < 0 || option > 2)
|
||||
throw new IllegalArgumentException("Bad return option");
|
||||
this.returnOption = option;
|
||||
}
|
||||
|
||||
public int getReturnOption() {
|
||||
return this.returnOption;
|
||||
}
|
||||
|
||||
String getDSNRet() {
|
||||
return returnOptionString[this.returnOption];
|
||||
}
|
||||
|
||||
public void setAllow8bitMIME(boolean allow) {
|
||||
this.allow8bitMIME = allow;
|
||||
}
|
||||
|
||||
public boolean getAllow8bitMIME() {
|
||||
return this.allow8bitMIME;
|
||||
}
|
||||
|
||||
public void setSendPartial(boolean partial) {
|
||||
this.sendPartial = partial;
|
||||
}
|
||||
|
||||
public boolean getSendPartial() {
|
||||
return this.sendPartial;
|
||||
}
|
||||
|
||||
public String getSubmitter() {
|
||||
return this.submitter;
|
||||
}
|
||||
|
||||
public void setSubmitter(String submitter) {
|
||||
this.submitter = submitter;
|
||||
}
|
||||
|
||||
public String getMailExtension() {
|
||||
return this.extension;
|
||||
}
|
||||
|
||||
public void setMailExtension(String extension) {
|
||||
this.extension = extension;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package com.sun.mail.smtp;
|
||||
|
||||
import com.sun.mail.util.CRLFOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class SMTPOutputStream extends CRLFOutputStream {
|
||||
public SMTPOutputStream(OutputStream os) {
|
||||
super(os);
|
||||
}
|
||||
|
||||
public void write(int b) throws IOException {
|
||||
if ((this.lastb == 10 || this.lastb == 13 || this.lastb == -1) && b == 46)
|
||||
this.out.write(46);
|
||||
super.write(b);
|
||||
}
|
||||
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
int lastc = (this.lastb == -1) ? 10 : this.lastb;
|
||||
int start = off;
|
||||
len += off;
|
||||
for (int i = off; i < len; i++) {
|
||||
if ((lastc == 10 || lastc == 13) && b[i] == 46) {
|
||||
super.write(b, start, i - start);
|
||||
this.out.write(46);
|
||||
start = i;
|
||||
}
|
||||
lastc = b[i];
|
||||
}
|
||||
if (len - start > 0)
|
||||
super.write(b, start, len - start);
|
||||
}
|
||||
|
||||
public void flush() {}
|
||||
|
||||
public void ensureAtBOL() throws IOException {
|
||||
if (!this.atBOL)
|
||||
writeln();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.sun.mail.smtp;
|
||||
|
||||
import javax.mail.Session;
|
||||
import javax.mail.URLName;
|
||||
|
||||
public class SMTPSSLTransport extends SMTPTransport {
|
||||
public SMTPSSLTransport(Session session, URLName urlname) {
|
||||
super(session, urlname, "smtps", true);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
package com.sun.mail.smtp;
|
||||
|
||||
import com.sun.mail.auth.OAuth2SaslClientFactory;
|
||||
import com.sun.mail.util.ASCIIUtility;
|
||||
import com.sun.mail.util.BASE64DecoderStream;
|
||||
import com.sun.mail.util.BASE64EncoderStream;
|
||||
import com.sun.mail.util.MailLogger;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.logging.Level;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
import javax.security.auth.callback.NameCallback;
|
||||
import javax.security.auth.callback.PasswordCallback;
|
||||
import javax.security.sasl.RealmCallback;
|
||||
import javax.security.sasl.RealmChoiceCallback;
|
||||
import javax.security.sasl.Sasl;
|
||||
import javax.security.sasl.SaslClient;
|
||||
import javax.security.sasl.SaslException;
|
||||
|
||||
public class SMTPSaslAuthenticator implements SaslAuthenticator {
|
||||
private SMTPTransport pr;
|
||||
|
||||
private String name;
|
||||
|
||||
private Properties props;
|
||||
|
||||
private MailLogger logger;
|
||||
|
||||
private String host;
|
||||
|
||||
static {
|
||||
try {
|
||||
OAuth2SaslClientFactory.init();
|
||||
} catch (Throwable e) {}
|
||||
}
|
||||
|
||||
public SMTPSaslAuthenticator(SMTPTransport pr, String name, Properties props, MailLogger logger, String host) {
|
||||
this.pr = pr;
|
||||
this.name = name;
|
||||
this.props = props;
|
||||
this.logger = logger;
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
public boolean authenticate(String[] mechs, final String realm, String authzid, final String u, final String p) throws MessagingException {
|
||||
SaslClient sc;
|
||||
int resp;
|
||||
boolean done = false;
|
||||
if (this.logger.isLoggable(Level.FINE)) {
|
||||
this.logger.fine("SASL Mechanisms:");
|
||||
for (int i = 0; i < mechs.length; i++)
|
||||
this.logger.fine(" " + mechs[i]);
|
||||
this.logger.fine("");
|
||||
}
|
||||
CallbackHandler cbh = new CallbackHandler() {
|
||||
public void handle(Callback[] callbacks) {
|
||||
if (SMTPSaslAuthenticator.this.logger.isLoggable(Level.FINE))
|
||||
SMTPSaslAuthenticator.this.logger.fine("SASL callback length: " + callbacks.length);
|
||||
for (int i = 0; i < callbacks.length; i++) {
|
||||
if (SMTPSaslAuthenticator.this.logger.isLoggable(Level.FINE))
|
||||
SMTPSaslAuthenticator.this.logger.fine("SASL callback " + i + ": " + callbacks[i]);
|
||||
if (callbacks[i] instanceof NameCallback) {
|
||||
NameCallback ncb = (NameCallback)callbacks[i];
|
||||
ncb.setName(u);
|
||||
} else if (callbacks[i] instanceof PasswordCallback) {
|
||||
PasswordCallback pcb = (PasswordCallback)callbacks[i];
|
||||
pcb.setPassword(p.toCharArray());
|
||||
} else if (callbacks[i] instanceof RealmCallback) {
|
||||
RealmCallback rcb = (RealmCallback)callbacks[i];
|
||||
rcb.setText((realm != null) ? realm :
|
||||
rcb.getDefaultText());
|
||||
} else if (callbacks[i] instanceof RealmChoiceCallback) {
|
||||
RealmChoiceCallback rcb = (RealmChoiceCallback)callbacks[i];
|
||||
if (realm == null) {
|
||||
rcb.setSelectedIndex(rcb.getDefaultChoice());
|
||||
} else {
|
||||
String[] choices = rcb.getChoices();
|
||||
for (int k = 0; k < choices.length; k++) {
|
||||
if (choices[k].equals(realm)) {
|
||||
rcb.setSelectedIndex(k);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
try {
|
||||
sc = Sasl.createSaslClient(mechs, authzid, this.name, this.host, (Map<String, ?>)this.props, cbh);
|
||||
} catch (SaslException sex) {
|
||||
this.logger.log(Level.FINE, "Failed to create SASL client", (Throwable)sex);
|
||||
throw new UnsupportedOperationException(sex.getMessage(), sex);
|
||||
}
|
||||
if (sc == null) {
|
||||
this.logger.fine("No SASL support");
|
||||
throw new UnsupportedOperationException("No SASL support");
|
||||
}
|
||||
if (this.logger.isLoggable(Level.FINE))
|
||||
this.logger.fine("SASL client " + sc.getMechanismName());
|
||||
try {
|
||||
String mech = sc.getMechanismName();
|
||||
String ir = null;
|
||||
if (sc.hasInitialResponse()) {
|
||||
byte[] ba = sc.evaluateChallenge(new byte[0]);
|
||||
if (ba.length > 0) {
|
||||
ba = BASE64EncoderStream.encode(ba);
|
||||
ir = ASCIIUtility.toString(ba, 0, ba.length);
|
||||
} else {
|
||||
ir = "=";
|
||||
}
|
||||
}
|
||||
if (ir != null) {
|
||||
resp = this.pr.simpleCommand("AUTH " + mech + " " + ir);
|
||||
} else {
|
||||
resp = this.pr.simpleCommand("AUTH " + mech);
|
||||
}
|
||||
if (resp == 530) {
|
||||
this.pr.startTLS();
|
||||
if (ir != null) {
|
||||
resp = this.pr.simpleCommand("AUTH " + mech + " " + ir);
|
||||
} else {
|
||||
resp = this.pr.simpleCommand("AUTH " + mech);
|
||||
}
|
||||
}
|
||||
if (resp == 235)
|
||||
return true;
|
||||
if (resp != 334)
|
||||
return false;
|
||||
} catch (Exception ex) {
|
||||
this.logger.log(Level.FINE, "SASL AUTHENTICATE Exception", (Throwable)ex);
|
||||
return false;
|
||||
}
|
||||
while (!done) {
|
||||
try {
|
||||
if (resp == 334) {
|
||||
byte[] ba = null;
|
||||
if (!sc.isComplete()) {
|
||||
ba = ASCIIUtility.getBytes(responseText(this.pr));
|
||||
if (ba.length > 0)
|
||||
ba = BASE64DecoderStream.decode(ba);
|
||||
if (this.logger.isLoggable(Level.FINE))
|
||||
this.logger.fine("SASL challenge: " +
|
||||
ASCIIUtility.toString(ba, 0, ba.length) + " :");
|
||||
ba = sc.evaluateChallenge(ba);
|
||||
}
|
||||
if (ba == null) {
|
||||
this.logger.fine("SASL: no response");
|
||||
resp = this.pr.simpleCommand("");
|
||||
continue;
|
||||
}
|
||||
if (this.logger.isLoggable(Level.FINE))
|
||||
this.logger.fine("SASL response: " +
|
||||
ASCIIUtility.toString(ba, 0, ba.length) + " :");
|
||||
ba = BASE64EncoderStream.encode(ba);
|
||||
resp = this.pr.simpleCommand(ba);
|
||||
continue;
|
||||
}
|
||||
done = true;
|
||||
} catch (Exception ioex) {
|
||||
this.logger.log(Level.FINE, "SASL Exception", (Throwable)ioex);
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
if (resp != 235)
|
||||
return false;
|
||||
if (sc.isComplete()) {
|
||||
String qop = (String)sc.getNegotiatedProperty("javax.security.sasl.qop");
|
||||
if (qop != null && (qop.equalsIgnoreCase("auth-int") ||
|
||||
qop.equalsIgnoreCase("auth-conf"))) {
|
||||
this.logger.fine("SASL Mechanism requires integrity or confidentiality");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static final String responseText(SMTPTransport pr) {
|
||||
String resp = pr.getLastServerResponse().trim();
|
||||
if (resp.length() > 4)
|
||||
return resp.substring(4);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package com.sun.mail.smtp;
|
||||
|
||||
import javax.mail.Address;
|
||||
import javax.mail.SendFailedException;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
|
||||
public class SMTPSendFailedException extends SendFailedException {
|
||||
protected InternetAddress addr;
|
||||
|
||||
protected String cmd;
|
||||
|
||||
protected int rc;
|
||||
|
||||
private static final long serialVersionUID = 8049122628728932894L;
|
||||
|
||||
public SMTPSendFailedException(String cmd, int rc, String err, Exception ex, Address[] vs, Address[] vus, Address[] inv) {
|
||||
super(err, ex, vs, vus, inv);
|
||||
this.cmd = cmd;
|
||||
this.rc = rc;
|
||||
}
|
||||
|
||||
public String getCommand() {
|
||||
return this.cmd;
|
||||
}
|
||||
|
||||
public int getReturnCode() {
|
||||
return this.rc;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package com.sun.mail.smtp;
|
||||
|
||||
import javax.mail.SendFailedException;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
|
||||
public class SMTPSenderFailedException extends SendFailedException {
|
||||
protected InternetAddress addr;
|
||||
|
||||
protected String cmd;
|
||||
|
||||
protected int rc;
|
||||
|
||||
private static final long serialVersionUID = 514540454964476947L;
|
||||
|
||||
public SMTPSenderFailedException(InternetAddress addr, String cmd, int rc, String err) {
|
||||
super(err);
|
||||
this.addr = addr;
|
||||
this.cmd = cmd;
|
||||
this.rc = rc;
|
||||
}
|
||||
|
||||
public InternetAddress getAddress() {
|
||||
return this.addr;
|
||||
}
|
||||
|
||||
public String getCommand() {
|
||||
return this.cmd;
|
||||
}
|
||||
|
||||
public int getReturnCode() {
|
||||
return this.rc;
|
||||
}
|
||||
}
|
||||
1498
rus/WEB-INF/lib/javax.mail_src/com/sun/mail/smtp/SMTPTransport.java
Normal file
1498
rus/WEB-INF/lib/javax.mail_src/com/sun/mail/smtp/SMTPTransport.java
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,7 @@
|
|||
package com.sun.mail.smtp;
|
||||
|
||||
import javax.mail.MessagingException;
|
||||
|
||||
public interface SaslAuthenticator {
|
||||
boolean authenticate(String[] paramArrayOfString, String paramString1, String paramString2, String paramString3, String paramString4) throws MessagingException;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue