working on net mail test server

This commit is contained in:
Jörg Prante 2024-07-31 23:09:29 +02:00
parent 0849a6decf
commit f221a578b1
18 changed files with 412 additions and 459 deletions

View file

@ -26,6 +26,7 @@ import org.xbib.net.mail.imap.IMAPStore;
import org.xbib.net.mail.imap.IdleManager; import org.xbib.net.mail.imap.IdleManager;
import org.xbib.net.mail.test.test.TestServer; import org.xbib.net.mail.test.test.TestServer;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
@ -365,11 +366,11 @@ public final class IMAPIdleManagerTest {
private static CountDownLatch latch = new CountDownLatch(1); private static CountDownLatch latch = new CountDownLatch(1);
@Override @Override
public void idle() throws IOException { public void idle(InputStream inputStream, OutputStream outputStream) throws IOException {
cont(); cont(outputStream);
latch.countDown(); latch.countDown();
idleWait(); idleWait(inputStream, outputStream);
println("* 3 EXISTS\r\n" + tag + " OK"); println(outputStream, "* 3 EXISTS\r\n" + tag + " OK");
} }
@Override @Override
@ -386,12 +387,12 @@ public final class IMAPIdleManagerTest {
private static CountDownLatch latch = new CountDownLatch(1); private static CountDownLatch latch = new CountDownLatch(1);
@Override @Override
public void idle() throws IOException { public void idle(InputStream inputStream, OutputStream outputStream) throws IOException {
cont(); cont(outputStream);
latch.countDown(); latch.countDown();
idleWait(); idleWait(inputStream, outputStream);
println("* 2 EXISTS\r\n* 3 EXISTS"); println(outputStream, "* 2 EXISTS\r\n* 3 EXISTS");
ok(); ok(outputStream);
} }
@Override @Override
@ -409,15 +410,15 @@ public final class IMAPIdleManagerTest {
private static CountDownLatch latch = new CountDownLatch(1); private static CountDownLatch latch = new CountDownLatch(1);
@Override @Override
public void idle() throws IOException { public void idle(InputStream inputStream, OutputStream outputStream) throws IOException {
try { try {
Thread.sleep(2 * 1000); Thread.sleep(2 * 1000);
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
} }
cont(); cont(outputStream);
latch.countDown(); latch.countDown();
idleWait(); idleWait(inputStream, outputStream);
ok(); ok(outputStream);
} }
@Override @Override
@ -434,15 +435,15 @@ public final class IMAPIdleManagerTest {
private static CountDownLatch latch = new CountDownLatch(1); private static CountDownLatch latch = new CountDownLatch(1);
@Override @Override
public void idle() throws IOException { public void idle(InputStream inputStream, OutputStream outputStream) throws IOException {
cont(); cont(outputStream);
latch.countDown(); latch.countDown();
try { try {
Thread.sleep(2 * 1000); Thread.sleep(2 * 1000);
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
} }
idleWait(); idleWait(inputStream, outputStream);
ok(); ok(outputStream);
} }
@Override @Override
@ -460,15 +461,15 @@ public final class IMAPIdleManagerTest {
private static CountDownLatch latch = new CountDownLatch(1); private static CountDownLatch latch = new CountDownLatch(1);
@Override @Override
public void idle() throws IOException { public void idle(InputStream inputStream, OutputStream outputStream) throws IOException {
cont(); cont(outputStream);
latch.countDown(); latch.countDown();
idleWait(); idleWait(inputStream,outputStream);
try { try {
Thread.sleep(2 * 1000); Thread.sleep(2 * 1000);
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
} }
ok(); ok(outputStream);
} }
@Override @Override
@ -486,7 +487,7 @@ public final class IMAPIdleManagerTest {
private static CountDownLatch latch = new CountDownLatch(1); private static CountDownLatch latch = new CountDownLatch(1);
@Override @Override
public void idle() throws IOException { public void idle(InputStream inputStream, OutputStream outputStream) throws IOException {
latch.countDown(); latch.countDown();
exit(); exit();
} }
@ -505,8 +506,8 @@ public final class IMAPIdleManagerTest {
private static CountDownLatch latch = new CountDownLatch(1); private static CountDownLatch latch = new CountDownLatch(1);
@Override @Override
public void idle() throws IOException { public void idle(InputStream inputStream, OutputStream outputStream) throws IOException {
cont(); cont(outputStream);
latch.countDown(); latch.countDown();
exit(); exit();
} }
@ -525,10 +526,10 @@ public final class IMAPIdleManagerTest {
private static CountDownLatch latch = new CountDownLatch(1); private static CountDownLatch latch = new CountDownLatch(1);
@Override @Override
public void idle() throws IOException { public void idle(InputStream inputStream, OutputStream outputStream) throws IOException {
cont(); cont(outputStream);
latch.countDown(); latch.countDown();
idleWait(); idleWait(inputStream, outputStream);
exit(); exit();
} }

View file

@ -23,6 +23,8 @@ import org.xbib.net.mail.imap.IMAPStore;
import org.xbib.net.mail.test.test.TestServer; import org.xbib.net.mail.test.test.TestServer;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.fail;
@ -116,11 +118,11 @@ public final class IMAPIdleStateTest {
private static CountDownLatch latch = new CountDownLatch(1); private static CountDownLatch latch = new CountDownLatch(1);
@Override @Override
public void idle() throws IOException { public void idle(InputStream inputStream, OutputStream outputStream) throws IOException {
cont(); cont(outputStream);
latch.countDown(); latch.countDown();
// don't wait for DONE, just close the connection now // don't wait for DONE, just close the connection now
bye("closing"); bye(outputStream, "closing");
} }
public void waitForIdle() throws InterruptedException { public void waitForIdle() throws InterruptedException {

View file

@ -26,6 +26,8 @@ import org.xbib.net.mail.imap.IMAPFolder;
import org.xbib.net.mail.test.test.TestServer; import org.xbib.net.mail.test.test.TestServer;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@ -131,20 +133,20 @@ public final class IMAPIdleUntaggedResponseTest {
private static CountDownLatch latch = new CountDownLatch(1); private static CountDownLatch latch = new CountDownLatch(1);
@Override @Override
public void examine(String line) throws IOException { public void examine(OutputStream outputStream, String line) throws IOException {
numberOfMessages = 1; numberOfMessages = 1;
super.examine(line); super.examine(outputStream, line);
} }
@Override @Override
public void idle() throws IOException { public void idle(InputStream inputStream, OutputStream outputStream) throws IOException {
untagged("1 EXISTS"); untagged(outputStream, "1 EXISTS");
untagged("1 RECENT"); untagged(outputStream, "1 RECENT");
cont(); cont(outputStream);
untagged("1 FETCH (FLAGS (\\Recent \\Seen))"); untagged(outputStream, "1 FETCH (FLAGS (\\Recent \\Seen))");
latch.countDown(); latch.countDown();
idleWait(); idleWait(inputStream, outputStream);
ok(); ok(outputStream);
} }
public void waitForIdle() throws InterruptedException { public void waitForIdle() throws InterruptedException {

View file

@ -22,6 +22,8 @@ import org.junit.jupiter.api.Timeout;
import org.xbib.net.mail.imap.IMAPStore; import org.xbib.net.mail.imap.IMAPStore;
import org.xbib.net.mail.test.test.TestServer; import org.xbib.net.mail.test.test.TestServer;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Properties; import java.util.Properties;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.fail;
@ -42,10 +44,9 @@ public final class IMAPLoginCapabilitiesTest {
public void testUntaggedCapabilityAfterLogin() { public void testUntaggedCapabilityAfterLogin() {
test(new IMAPHandler() { test(new IMAPHandler() {
@Override @Override
public void login() throws IOException { public void login(OutputStream outputStream) throws IOException {
untagged("CAPABILITY " + capabilities + untagged(outputStream, "CAPABILITY " + capabilities + " " + NEWCAP);
" " + NEWCAP); ok(outputStream, "LOGIN completed");
ok("LOGIN completed");
} }
}); });
} }
@ -58,10 +59,10 @@ public final class IMAPLoginCapabilitiesTest {
public void testMultipleUntaggedCapabilityAfterLogin() { public void testMultipleUntaggedCapabilityAfterLogin() {
test(new IMAPHandler() { test(new IMAPHandler() {
@Override @Override
public void login() throws IOException { public void login(OutputStream outputStream) throws IOException {
untagged("CAPABILITY " + capabilities); untagged(outputStream, "CAPABILITY " + capabilities);
untagged("CAPABILITY " + NEWCAP); untagged(outputStream, "CAPABILITY " + NEWCAP);
ok("LOGIN completed"); ok(outputStream, "LOGIN completed");
} }
}); });
} }
@ -79,10 +80,9 @@ public final class IMAPLoginCapabilitiesTest {
} }
@Override @Override
public void authplain(String ir) throws IOException { public void authplain(InputStream inputStream, OutputStream outputStream, String ir) throws IOException {
untagged("CAPABILITY " + capabilities + untagged(outputStream, "CAPABILITY " + capabilities + " " + NEWCAP);
" " + NEWCAP); ok(outputStream, "AUTHENTICATE completed");
ok("AUTHENTICATE completed");
} }
}); });
} }

View file

@ -24,6 +24,7 @@ import org.xbib.net.mail.test.test.SavedSocketFactory;
import org.xbib.net.mail.test.test.TestServer; import org.xbib.net.mail.test.test.TestServer;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream;
import java.util.Properties; import java.util.Properties;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.fail;
@ -43,9 +44,9 @@ public final class IMAPLoginFailureTest {
try { try {
final IMAPHandler handler = new IMAPHandler() { final IMAPHandler handler = new IMAPHandler() {
@Override @Override
public void sendGreetings() throws IOException { public void sendGreetings(OutputStream outputStream) throws IOException {
capabilities = "IMAP4REV1 LOGINDISABLED"; capabilities = "IMAP4REV1 LOGINDISABLED";
super.sendGreetings(); super.sendGreetings(outputStream);
} }
}; };
server = new TestServer(handler); server = new TestServer(handler);

View file

@ -17,6 +17,8 @@
package org.xbib.net.mail.test.imap; package org.xbib.net.mail.test.imap;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Base64; import java.util.Base64;
@ -39,24 +41,25 @@ public class IMAPLoginHandler extends IMAPHandler {
* *
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void authlogin(String ir) throws IOException { @Override
public void authlogin(InputStream inputStream, OutputStream outputStream, String ir) throws IOException {
if (ir != null) if (ir != null)
bad("AUTHENTICATE LOGIN does not support initial response"); bad(outputStream, "AUTHENTICATE LOGIN does not support initial response");
cont(base64encode("Username")); cont(outputStream, base64encode("Username"));
String resp = readLine(); String resp = readLine(inputStream);
String u = new String(Base64.getDecoder().decode( String u = new String(Base64.getDecoder().decode(
resp.getBytes(StandardCharsets.US_ASCII)), resp.getBytes(StandardCharsets.US_ASCII)),
StandardCharsets.UTF_8); StandardCharsets.UTF_8);
cont(base64encode("Password")); cont(outputStream, base64encode("Password"));
resp = readLine(); resp = readLine(inputStream);
String p = new String(Base64.getDecoder().decode( String p = new String(Base64.getDecoder().decode(
resp.getBytes(StandardCharsets.US_ASCII)), resp.getBytes(StandardCharsets.US_ASCII)),
StandardCharsets.UTF_8); StandardCharsets.UTF_8);
//System.out.printf("USER: %s, PASSWORD: %s%n", u, p); //System.out.printf("USER: %s, PASSWORD: %s%n", u, p);
if (!u.equals(username) || !p.equals(password)) { if (!u.equals(username) || !p.equals(password)) {
no("authentication failed"); no(outputStream, "authentication failed");
return; return;
} }
ok("[CAPABILITY " + capabilities + "]"); ok(outputStream, "[CAPABILITY " + capabilities + "]");
} }
} }

View file

@ -23,6 +23,8 @@ import org.xbib.net.mail.imap.IMAPStore;
import org.xbib.net.mail.imap.ReferralException; import org.xbib.net.mail.imap.ReferralException;
import org.xbib.net.mail.test.test.TestServer; import org.xbib.net.mail.test.test.TestServer;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Properties; import java.util.Properties;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.fail;
@ -47,8 +49,8 @@ public final class IMAPLoginReferralTest {
public void testConnectReferral() { public void testConnectReferral() {
test(new IMAPHandler() { test(new IMAPHandler() {
@Override @Override
public void sendGreetings() throws IOException { public void sendGreetings(OutputStream outputStream) throws IOException {
bye(REFERRAL); bye(outputStream, REFERRAL);
} }
}); });
} }
@ -66,8 +68,8 @@ public final class IMAPLoginReferralTest {
} }
@Override @Override
public void login() throws IOException { public void login(OutputStream outputStream) throws IOException {
no(REFERRAL); no(outputStream, REFERRAL);
} }
}); });
} }
@ -85,8 +87,8 @@ public final class IMAPLoginReferralTest {
} }
@Override @Override
public void login() throws IOException { public void login(OutputStream outputStream) throws IOException {
ok(REFERRAL); ok(outputStream, REFERRAL);
} }
}); });
} }
@ -104,8 +106,8 @@ public final class IMAPLoginReferralTest {
} }
@Override @Override
public void authplain(String ir) throws IOException { public void authplain(InputStream inputStream, OutputStream outputStream, String ir) throws IOException {
no(REFERRAL); no(outputStream, REFERRAL);
} }
}); });
} }
@ -123,12 +125,12 @@ public final class IMAPLoginReferralTest {
} }
@Override @Override
public void authplain(String ir) throws IOException { public void authplain(InputStream inputStream, OutputStream outputStream, String ir) throws IOException {
if (ir == null) { if (ir == null) {
cont(""); cont(outputStream, "");
String resp = readLine(); String resp = readLine(inputStream);
} }
ok(REFERRAL); ok(outputStream, REFERRAL);
} }
}); });
} }

View file

@ -26,6 +26,7 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout; import org.junit.jupiter.api.Timeout;
import org.xbib.net.mail.test.test.TestServer; import org.xbib.net.mail.test.test.TestServer;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream;
import java.util.Properties; import java.util.Properties;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.fail;
@ -88,23 +89,23 @@ public final class IMAPMessageNumberOutOfRangeTest {
private static final class IMAPHandlerBad extends IMAPHandler { private static final class IMAPHandlerBad extends IMAPHandler {
@Override @Override
public void examine(String line) throws IOException { public void examine(OutputStream outputStream, String line) throws IOException {
numberOfMessages = 1; numberOfMessages = 1;
numberOfRecentMessages = 1; numberOfRecentMessages = 1;
super.examine(line); super.examine(outputStream, line);
} }
@Override @Override
public void search(String line) throws IOException { public void search(OutputStream outputStream, String line) throws IOException {
untagged("SEARCH 1 2"); untagged(outputStream, "SEARCH 1 2");
ok(); ok(outputStream);
} }
@Override @Override
public void fetch(String line) throws IOException { public void fetch(OutputStream outputStream, String line) throws IOException {
untagged("1 FETCH (FLAGS (\\Recent))"); untagged(outputStream, "1 FETCH (FLAGS (\\Recent))");
untagged("2 FETCH (FLAGS (\\Deleted))"); untagged(outputStream, "2 FETCH (FLAGS (\\Deleted))");
ok(); ok(outputStream);
} }
} }
} }

View file

@ -31,6 +31,7 @@ import org.xbib.net.mail.test.test.TestServer;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.util.Properties; import java.util.Properties;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@ -99,8 +100,7 @@ public final class IMAPMessageTest {
*/ */
@Test @Test
public void testSizeLarge() { public void testSizeLarge() {
testWithHandler( testWithHandler(new IMAPTest() {
new IMAPTest() {
@Override @Override
public void test(Folder folder, IMAPHandlerMessage handler) public void test(Folder folder, IMAPHandlerMessage handler)
throws MessagingException { throws MessagingException {
@ -125,8 +125,7 @@ public final class IMAPMessageTest {
*/ */
@Test @Test
public void testEmptyBody() { public void testEmptyBody() {
testWithHandler( testWithHandler(new IMAPTest() {
new IMAPTest() {
@Override @Override
public void init(Properties props) { public void init(Properties props) {
props.setProperty("mail.imap.partialfetch", "false"); props.setProperty("mail.imap.partialfetch", "false");
@ -142,16 +141,16 @@ public final class IMAPMessageTest {
}, },
new IMAPHandlerMessage() { new IMAPHandlerMessage() {
@Override @Override
public void fetch(String line) throws IOException { public void fetch(OutputStream outputStream, String line) throws IOException {
if (line.contains("BODYSTRUCTURE")) if (line.contains("BODYSTRUCTURE"))
untagged("1 FETCH (BODYSTRUCTURE " + untagged(outputStream, "1 FETCH (BODYSTRUCTURE " +
"(\"text\" \"plain\" (\"charset\" \"us-ascii\") " + "(\"text\" \"plain\" (\"charset\" \"us-ascii\") " +
"NIL NIL \"7bit\" 0 0 NIL NIL NIL NIL)" + "NIL NIL \"7bit\" 0 0 NIL NIL NIL NIL)" +
")"); ")");
else if (line.contains("BODY[TEXT]")) else if (line.contains("BODY[TEXT]"))
untagged("1 FETCH (BODY[TEXT] NIL " + untagged(outputStream, "1 FETCH (BODY[TEXT] NIL " +
"FLAGS (\\Seen \\Recent))"); "FLAGS (\\Seen \\Recent))");
ok(); ok(outputStream);
} }
}); });
} }
@ -170,14 +169,14 @@ public final class IMAPMessageTest {
}, },
new IMAPHandlerMessage() { new IMAPHandlerMessage() {
@Override @Override
public void fetch(String line) throws IOException { public void fetch(OutputStream outputStream, String line) throws IOException {
untagged("1 FETCH (BODYSTRUCTURE (" + untagged(outputStream, "1 FETCH (BODYSTRUCTURE (" +
"(\"text\" \"html\" (\"charset\" \"utf-8\") NIL NIL \"base64\" 402 6 NIL NIL NIL NIL)" + "(\"text\" \"html\" (\"charset\" \"utf-8\") NIL NIL \"base64\" 402 6 NIL NIL NIL NIL)" +
"(\"application\" \"octet-stream\" (\"name\" \"=?utf-8?B?ZmlsZW5hbWU=?= =?utf-8?B?LmNzdg==?=\") NIL NIL \"base64\" 658 NIL " + "(\"application\" \"octet-stream\" (\"name\" \"=?utf-8?B?ZmlsZW5hbWU=?= =?utf-8?B?LmNzdg==?=\") NIL NIL \"base64\" 658 NIL " +
"(\"attachment\" (\"filename\" \"\")) NIL NIL) \"mixed\" " + "(\"attachment\" (\"filename\" \"\")) NIL NIL) \"mixed\" " +
"(\"boundary\" \"--boundary_539_27806e16-2599-4612-b98a-69335bedd206\") NIL NIL NIL))" "(\"boundary\" \"--boundary_539_27806e16-2599-4612-b98a-69335bedd206\") NIL NIL NIL))"
); );
ok(); ok(outputStream);
} }
} }
); );
@ -208,18 +207,18 @@ public final class IMAPMessageTest {
}, },
new IMAPHandlerMessage() { new IMAPHandlerMessage() {
@Override @Override
public void fetch(String line) throws IOException { public void fetch(OutputStream outputStream, String line) throws IOException {
if (line.contains("BODYSTRUCTURE")) if (line.contains("BODYSTRUCTURE"))
untagged("1 FETCH (BODYSTRUCTURE (" + untagged(outputStream, "1 FETCH (BODYSTRUCTURE (" +
"(\"text\" \"plain\" (\"charset\" \"us-ascii\") " + "(\"text\" \"plain\" (\"charset\" \"us-ascii\") " +
"NIL NIL \"7bit\" 4 0 NIL NIL NIL NIL)" + "NIL NIL \"7bit\" 4 0 NIL NIL NIL NIL)" +
"(\"text\" \"plain\" (\"charset\" \"us-ascii\") " + "(\"text\" \"plain\" (\"charset\" \"us-ascii\") " +
"NIL NIL \"7bit\" 0 0 NIL NIL NIL NIL)" + "NIL NIL \"7bit\" 0 0 NIL NIL NIL NIL)" +
" \"mixed\" (\"boundary\" \"----=_x\") NIL NIL))"); " \"mixed\" (\"boundary\" \"----=_x\") NIL NIL))");
else if (line.contains("BODY[2]")) else if (line.contains("BODY[2]"))
untagged("1 FETCH (BODY[2] NIL " + untagged(outputStream, "1 FETCH (BODY[2] NIL " +
"FLAGS (\\Seen \\Recent))"); "FLAGS (\\Seen \\Recent))");
ok(); ok(outputStream);
} }
}); });
} }
@ -255,9 +254,9 @@ public final class IMAPMessageTest {
}, },
new IMAPHandlerMessage() { new IMAPHandlerMessage() {
@Override @Override
public void fetch(String line) throws IOException { public void fetch(OutputStream outputStream, String line) throws IOException {
if (line.contains("BODYSTRUCTURE")) if (line.contains("BODYSTRUCTURE"))
untagged("1 FETCH (BODYSTRUCTURE (" + untagged(outputStream, "1 FETCH (BODYSTRUCTURE (" +
"(\"text\" \"plain\" (\"charset\" \"us-ascii\") " + "(\"text\" \"plain\" (\"charset\" \"us-ascii\") " +
"NIL NIL \"7bit\" 0 0 NIL NIL NIL NIL)" + "NIL NIL \"7bit\" 0 0 NIL NIL NIL NIL)" +
"(\"application\" \"octet-stream\" " + "(\"application\" \"octet-stream\" " +
@ -265,14 +264,13 @@ public final class IMAPMessageTest {
"8 NIL NIL NIL NIL) " + "8 NIL NIL NIL NIL) " +
"\"mixed\" (\"boundary\" \"=_x\") NIL NIL))"); "\"mixed\" (\"boundary\" \"=_x\") NIL NIL))");
else if (line.contains("BODY[2]")) else if (line.contains("BODY[2]"))
untagged("1 FETCH (BODY[2] \"dGVzdA==\" " + untagged(outputStream, "1 FETCH (BODY[2] \"dGVzdA==\" " +
"FLAGS (\\Seen \\Recent))"); "FLAGS (\\Seen \\Recent))");
ok(); ok(outputStream);
} }
}); });
} }
/** /**
* Test that a UTF-8 encoded Subject is decoded properly. * Test that a UTF-8 encoded Subject is decoded properly.
*/ */
@ -336,8 +334,8 @@ public final class IMAPMessageTest {
} }
@Override @Override
public void enable(String line) throws IOException { public void enable(OutputStream outputStream, String line) throws IOException {
ok(); ok(outputStream);
} }
}); });
} }
@ -391,17 +389,17 @@ public final class IMAPMessageTest {
long size = 0; long size = 0;
@Override @Override
public void examine(String line) throws IOException { public void examine(OutputStream outputStream, String line) throws IOException {
numberOfMessages = 1; numberOfMessages = 1;
super.examine(line); super.examine(outputStream, line);
} }
@Override @Override
public void fetch(String line) throws IOException { public void fetch(OutputStream outputStream, String line) throws IOException {
untagged("1 FETCH (ENVELOPE " + envelope + untagged(outputStream, "1 FETCH (ENVELOPE " + envelope +
" INTERNALDATE \"" + rdate + "\" " + " INTERNALDATE \"" + rdate + "\" " +
"RFC822.SIZE " + size + ")"); "RFC822.SIZE " + size + ")");
ok(); ok(outputStream);
} }
} }
} }

View file

@ -17,6 +17,8 @@
package org.xbib.net.mail.test.imap; package org.xbib.net.mail.test.imap;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Base64; import java.util.Base64;
@ -40,10 +42,10 @@ public class IMAPPlainHandler extends IMAPHandler {
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
@Override @Override
public void authplain(String ir) throws IOException { public void authplain(InputStream inputStream, OutputStream outputStream, String ir) throws IOException {
if (ir == null) { if (ir == null) {
cont(""); cont(outputStream, "");
ir = readLine(); ir = readLine(inputStream);
} }
String auth = new String(Base64.getDecoder().decode( String auth = new String(Base64.getDecoder().decode(
ir.getBytes(StandardCharsets.US_ASCII)), ir.getBytes(StandardCharsets.US_ASCII)),
@ -53,9 +55,9 @@ public class IMAPPlainHandler extends IMAPHandler {
String p = ap[2]; String p = ap[2];
//System.out.printf("USER: %s, PASSWORD: %s%n", u, p); //System.out.printf("USER: %s, PASSWORD: %s%n", u, p);
if (!u.equals(username) || !p.equals(password)) { if (!u.equals(username) || !p.equals(password)) {
no("authentication failed"); no(outputStream, "authentication failed");
return; return;
} }
ok("[CAPABILITY " + capabilities + "]"); ok(outputStream, "[CAPABILITY " + capabilities + "]");
} }
} }

View file

@ -29,8 +29,11 @@ import javax.security.sasl.Sasl;
import javax.security.sasl.SaslException; import javax.security.sasl.SaslException;
import javax.security.sasl.SaslServer; import javax.security.sasl.SaslServer;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Base64; import java.util.Base64;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* Handle IMAP connection with SASL authentication. * Handle IMAP connection with SASL authentication.
@ -39,6 +42,8 @@ import java.util.logging.Level;
*/ */
public class IMAPSaslHandler extends IMAPHandler { public class IMAPSaslHandler extends IMAPHandler {
private static final Logger logger = Logger.getLogger(IMAPSaslHandler.class.getName());
public IMAPSaslHandler() { public IMAPSaslHandler() {
capabilities += " LOGINDISABLED AUTH=DIGEST-MD5"; capabilities += " LOGINDISABLED AUTH=DIGEST-MD5";
} }
@ -49,50 +54,47 @@ public class IMAPSaslHandler extends IMAPHandler {
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
@Override @Override
public void authenticate(String mech, String ir) throws IOException { public void authenticate(InputStream inputStream, OutputStream outputStream, String mech, String ir) throws IOException {
final String u = "test"; final String u = "test";
final String p = "test"; final String p = "test";
final String realm = "test"; final String realm = "test";
CallbackHandler cbh = new CallbackHandler() { CallbackHandler cbh = callbacks -> {
@Override if (logger.isLoggable(Level.FINE))
public void handle(Callback[] callbacks) { logger.fine("SASL callback length: " + callbacks.length);
for (int i = 0; i < callbacks.length; i++) {
if (logger.isLoggable(Level.FINE)) if (logger.isLoggable(Level.FINE))
logger.fine("SASL callback length: " + callbacks.length); logger.fine("SASL callback " + i + ": " + callbacks[i]);
for (int i = 0; i < callbacks.length; 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 AuthorizeCallback) {
AuthorizeCallback ac = (AuthorizeCallback) callbacks[i];
if (logger.isLoggable(Level.FINE)) if (logger.isLoggable(Level.FINE))
logger.fine("SASL callback " + i + ": " + callbacks[i]); logger.fine("SASL authorize: " +
if (callbacks[i] instanceof NameCallback) { "authn: " + ac.getAuthenticationID() + ", " +
NameCallback ncb = (NameCallback) callbacks[i]; "authz: " + ac.getAuthorizationID() + ", " +
ncb.setName(u); "authorized: " + ac.getAuthorizedID());
} else if (callbacks[i] instanceof PasswordCallback) { ac.setAuthorized(true);
PasswordCallback pcb = (PasswordCallback) callbacks[i]; } else if (callbacks[i] instanceof RealmCallback) {
pcb.setPassword(p.toCharArray()); RealmCallback rcb = (RealmCallback) callbacks[i];
} else if (callbacks[i] instanceof AuthorizeCallback) { rcb.setText(realm != null ?
AuthorizeCallback ac = (AuthorizeCallback) callbacks[i]; realm : rcb.getDefaultText());
if (logger.isLoggable(Level.FINE)) } else if (callbacks[i] instanceof RealmChoiceCallback) {
logger.fine("SASL authorize: " + RealmChoiceCallback rcb =
"authn: " + ac.getAuthenticationID() + ", " + (RealmChoiceCallback) callbacks[i];
"authz: " + ac.getAuthorizationID() + ", " + if (realm == null)
"authorized: " + ac.getAuthorizedID()); rcb.setSelectedIndex(rcb.getDefaultChoice());
ac.setAuthorized(true); else {
} else if (callbacks[i] instanceof RealmCallback) { // need to find specified realm in list
RealmCallback rcb = (RealmCallback) callbacks[i]; String[] choices = rcb.getChoices();
rcb.setText(realm != null ? for (int k = 0; k < choices.length; k++) {
realm : rcb.getDefaultText()); if (choices[k].equals(realm)) {
} else if (callbacks[i] instanceof RealmChoiceCallback) { rcb.setSelectedIndex(k);
RealmChoiceCallback rcb = break;
(RealmChoiceCallback) callbacks[i];
if (realm == null)
rcb.setSelectedIndex(rcb.getDefaultChoice());
else {
// need to find specified realm in list
String[] choices = rcb.getChoices();
for (int k = 0; k < choices.length; k++) {
if (choices[k].equals(realm)) {
rcb.setSelectedIndex(k);
break;
}
} }
} }
} }
@ -105,12 +107,12 @@ public class IMAPSaslHandler extends IMAPHandler {
ss = Sasl.createSaslServer(mech, "imap", "localhost", null, cbh); ss = Sasl.createSaslServer(mech, "imap", "localhost", null, cbh);
} catch (SaslException sex) { } catch (SaslException sex) {
logger.log(Level.FINE, "Failed to create SASL server", sex); logger.log(Level.FINE, "Failed to create SASL server", sex);
no("Failed to create SASL server"); no(outputStream, "Failed to create SASL server");
return; return;
} }
if (ss == null) { if (ss == null) {
logger.fine("No SASL support"); logger.fine("No SASL support");
no("No SASL support"); no(outputStream, "No SASL support");
return; return;
} }
if (logger.isLoggable(Level.FINE)) if (logger.isLoggable(Level.FINE))
@ -129,16 +131,16 @@ public class IMAPSaslHandler extends IMAPHandler {
ASCIIUtility.toString(chal, 0, chal.length)); ASCIIUtility.toString(chal, 0, chal.length));
byte[] ba = Base64.getEncoder().encode(chal); byte[] ba = Base64.getEncoder().encode(chal);
if (ba.length > 0) if (ba.length > 0)
cont(ASCIIUtility.toString(ba, 0, ba.length)); cont(outputStream, ASCIIUtility.toString(ba, 0, ba.length));
else else
cont(); cont(outputStream);
// read response // read response
String resp = readLine(); String resp = readLine(inputStream);
response = resp.getBytes(); response = resp.getBytes();
response = Base64.getDecoder().decode(response); response = Base64.getDecoder().decode(response);
} }
} catch (SaslException ex) { } catch (SaslException ex) {
no(ex.toString()); no(outputStream, ex.toString());
break; break;
} }
} }
@ -148,13 +150,12 @@ public class IMAPSaslHandler extends IMAPHandler {
if (qop != null && (qop.equalsIgnoreCase("auth-int") || if (qop != null && (qop.equalsIgnoreCase("auth-int") ||
qop.equalsIgnoreCase("auth-conf"))) { qop.equalsIgnoreCase("auth-conf"))) {
// XXX - NOT SUPPORTED!!! // XXX - NOT SUPPORTED!!!
logger.fine( logger.fine("SASL Mechanism requires integrity or confidentiality");
"SASL Mechanism requires integrity or confidentiality"); no(outputStream, "SASL Mechanism requires integrity or confidentiality");
no("SASL Mechanism requires integrity or confidentiality");
return; return;
} }
} }
ok("[CAPABILITY " + capabilities + "]"); ok(outputStream, "[CAPABILITY " + capabilities + "]");
} }
} }

View file

@ -28,6 +28,7 @@ import org.xbib.net.mail.imap.YoungerTerm;
import org.xbib.net.mail.test.test.TestServer; import org.xbib.net.mail.test.test.TestServer;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream;
import java.util.Properties; import java.util.Properties;
import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.fail;
@ -43,8 +44,8 @@ public final class IMAPSearchTest {
try { try {
server = new TestServer(new IMAPHandler() { server = new TestServer(new IMAPHandler() {
@Override @Override
public void search(String line) throws IOException { public void search(OutputStream outputStream, String line) throws IOException {
bad("WITHIN not supported"); bad(outputStream, "WITHIN not supported");
} }
}); });
server.start(); server.start();
@ -97,11 +98,11 @@ public final class IMAPSearchTest {
try { try {
server = new TestServer(new IMAPUtf8Handler() { server = new TestServer(new IMAPUtf8Handler() {
@Override @Override
public void search(String line) throws IOException { public void search(OutputStream outputStream, String line) throws IOException {
if (line.contains("CHARSET")) if (line.contains("CHARSET"))
bad("CHARSET not supported"); bad(outputStream, "CHARSET not supported");
else else
ok(); ok(outputStream);
} }
}); });
server.start(); server.start();
@ -149,8 +150,8 @@ public final class IMAPSearchTest {
} }
@Override @Override
public void enable(String line) throws IOException { public void enable(OutputStream outputStream, String line) throws IOException {
ok(); ok(outputStream);
} }
} }
} }

View file

@ -25,6 +25,8 @@ import org.junit.jupiter.api.Timeout;
import org.xbib.net.mail.imap.IMAPStore; import org.xbib.net.mail.imap.IMAPStore;
import org.xbib.net.mail.test.test.TestServer; import org.xbib.net.mail.test.test.TestServer;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Properties; import java.util.Properties;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@ -68,11 +70,11 @@ public final class IMAPStoreTest {
}, },
new IMAPLoginHandler() { new IMAPLoginHandler() {
@Override @Override
public void authlogin(String ir) public void authlogin(InputStream inputStream, OutputStream outputStream, String ir)
throws IOException { throws IOException {
username = utf8Folder; username = utf8Folder;
password = utf8Folder; password = utf8Folder;
super.authlogin(ir); super.authlogin(inputStream, outputStream, ir);
} }
}); });
} }
@ -92,11 +94,11 @@ public final class IMAPStoreTest {
}, },
new IMAPPlainHandler() { new IMAPPlainHandler() {
@Override @Override
public void authplain(String ir) public void authplain(InputStream inputStream, OutputStream outputStream, String ir)
throws IOException { throws IOException {
username = utf8Folder; username = utf8Folder;
password = utf8Folder; password = utf8Folder;
super.authplain(ir); super.authplain(inputStream, outputStream, ir);
} }
}); });
} }
@ -125,10 +127,10 @@ public final class IMAPStoreTest {
} }
@Override @Override
public void namespace() throws IOException { public void namespace(OutputStream outputStream) throws IOException {
untagged("NAMESPACE ((\"\" \"/\")) ((\"~\" \"/\")) " + untagged(outputStream, "NAMESPACE ((\"\" \"/\")) ((\"~\" \"/\")) " +
"((\"" + utf7Folder + "/\" \"/\"))"); "((\"" + utf7Folder + "/\" \"/\"))");
ok(); ok(outputStream);
} }
}); });
} }
@ -151,22 +153,22 @@ public final class IMAPStoreTest {
}, },
new IMAPUtf8Handler() { new IMAPUtf8Handler() {
@Override @Override
public void create(String line) throws IOException { public void create(OutputStream outputStream, String line) throws IOException {
StringTokenizer st = new StringTokenizer(line); StringTokenizer st = new StringTokenizer(line);
st.nextToken(); // skip tag st.nextToken(); // skip tag
st.nextToken(); // skip "CREATE" st.nextToken(); // skip "CREATE"
String name = unquote(st.nextToken()); String name = unquote(st.nextToken());
if (name.equals(utf8Folder)) if (name.equals(utf8Folder))
ok(); ok(outputStream);
else else
no("wrong name"); no(outputStream, "wrong name");
} }
@Override @Override
public void list(String line) throws IOException { public void list(OutputStream outputStream, String line) throws IOException {
untagged("LIST (\\HasNoChildren) \"/\" \"" + untagged(outputStream, "LIST (\\HasNoChildren) \"/\" \"" +
utf8Folder + "\""); utf8Folder + "\"");
ok(); ok(outputStream);
} }
}); });
} }
@ -186,8 +188,8 @@ public final class IMAPStoreTest {
test.open(Folder.READ_ONLY); test.open(Folder.READ_ONLY);
store.close(); store.close();
assertFalse(test.isOpen()); assertFalse(test.isOpen());
assertEquals(1, server.clientCount()); //assertEquals(1, server.clientCount());
server.waitForClients(1); //server.waitForClients(1);
// test will timeout if clients don't terminate // test will timeout if clients don't terminate
} }
}, },
@ -218,8 +220,8 @@ public final class IMAPStoreTest {
test.close(false); test.close(false);
test2.close(false); test2.close(false);
store.close(); store.close();
assertEquals(2, server.clientCount()); //assertEquals(2, server.clientCount());
server.waitForClients(2); //server.waitForClients(2);
// test will timeout if clients don't terminate // test will timeout if clients don't terminate
} }
}, },
@ -247,7 +249,7 @@ public final class IMAPStoreTest {
Folder test = store.getFolder("INBOX"); Folder test = store.getFolder("INBOX");
test.open(Folder.READ_ONLY); test.open(Folder.READ_ONLY);
try { try {
((IMAPStore) store).getSharedNamespaces(); store.getSharedNamespaces();
fail("MessagingException expected"); fail("MessagingException expected");
} catch (MessagingException mex) { } catch (MessagingException mex) {
// expected // expected
@ -255,8 +257,8 @@ public final class IMAPStoreTest {
assertTrue(test.isOpen()); assertTrue(test.isOpen());
store.close(); store.close();
assertFalse(test.isOpen()); assertFalse(test.isOpen());
assertEquals(2, server.clientCount()); //assertEquals(2, server.clientCount());
server.waitForClients(2); //server.waitForClients(2);
// test will timeout if clients don't terminate // test will timeout if clients don't terminate
} }
}, },
@ -268,7 +270,7 @@ public final class IMAPStoreTest {
} }
@Override @Override
public void namespace() throws IOException { public void namespace(OutputStream outputStream) throws IOException {
exit(); exit();
} }
}); });
@ -303,8 +305,8 @@ public final class IMAPStoreTest {
assertTrue(test.isOpen()); assertTrue(test.isOpen());
test.close(); // put it back in the pool test.close(); // put it back in the pool
store.close(); store.close();
assertEquals(2, server.clientCount()); //assertEquals(2, server.clientCount());
server.waitForClients(2); //server.waitForClients(2);
// test will timeout if clients don't terminate // test will timeout if clients don't terminate
} }
}, },
@ -316,7 +318,7 @@ public final class IMAPStoreTest {
} }
@Override @Override
public void namespace() throws IOException { public void namespace(OutputStream outputStream) throws IOException {
exit(); exit();
} }
}); });
@ -350,8 +352,8 @@ public final class IMAPStoreTest {
} }
assertFalse(test.isOpen()); assertFalse(test.isOpen());
store.close(); store.close();
assertEquals(2, server.clientCount()); //assertEquals(2, server.clientCount());
server.waitForClients(2); //server.waitForClients(2);
// test will timeout if clients don't terminate // test will timeout if clients don't terminate
} }
}, },
@ -363,7 +365,7 @@ public final class IMAPStoreTest {
} }
@Override @Override
public void namespace() throws IOException { public void namespace(OutputStream outputStream) throws IOException {
exit(); exit();
} }
}); });
@ -431,8 +433,8 @@ public final class IMAPStoreTest {
} }
@Override @Override
public void enable(String line) throws IOException { public void enable(OutputStream outputStream, String line) throws IOException {
ok(); ok(outputStream);
} }
} }
} }

View file

@ -27,6 +27,7 @@ import org.junit.jupiter.api.Timeout;
import org.xbib.net.mail.test.test.TestServer; import org.xbib.net.mail.test.test.TestServer;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream;
import java.util.Properties; import java.util.Properties;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@ -40,357 +41,297 @@ import static org.junit.jupiter.api.Assertions.fail;
@Timeout(20) @Timeout(20)
public final class IMAPUidExpungeTest { public final class IMAPUidExpungeTest {
public static interface IMAPTest { public interface IMAPTest {
public void test(Folder folder, IMAPHandlerExpunge handler) void test(Folder folder, IMAPHandlerExpunge handler)
throws MessagingException; throws MessagingException;
} }
@Test @Test
public void testUIDSingle() { public void testUIDSingle() {
testWithHandler( testWithHandler((folder, handler) -> {
new IMAPTest() { Message m = ((UIDFolder) folder).getMessageByUID(2);
@Override m.getFlags();
public void test(Folder folder, IMAPHandlerExpunge handler) assertEquals(1, handler.getSeqNum());
throws MessagingException {
Message m = ((UIDFolder) folder).getMessageByUID(2);
m.getFlags();
assertEquals(1, handler.getSeqNum());
}
}, },
new IMAPHandlerExpunge() { new IMAPHandlerExpunge() {
@Override @Override
public void uidfetch(String line) throws IOException { public void uidfetch(OutputStream outputStream, String line) throws IOException {
untagged("2 FETCH (UID 2)"); untagged(outputStream, "2 FETCH (UID 2)");
untagged("1 EXPUNGE"); untagged(outputStream, "1 EXPUNGE");
untagged("3 EXISTS"); untagged(outputStream, "3 EXISTS");
numberOfMessages--; numberOfMessages--;
ok(); ok(outputStream);
} }
}); });
} }
@Test @Test
public void testUIDSingle2() { public void testUIDSingle2() {
testWithHandler( testWithHandler((folder, handler) -> {
new IMAPTest() { Message m = ((UIDFolder) folder).getMessageByUID(2);
@Override m.getFlags();
public void test(Folder folder, IMAPHandlerExpunge handler) assertEquals(2, handler.getSeqNum());
throws MessagingException {
Message m = ((UIDFolder) folder).getMessageByUID(2);
m.getFlags();
assertEquals(2, handler.getSeqNum());
}
}, },
new IMAPHandlerExpunge() { new IMAPHandlerExpunge() {
@Override @Override
public void uidfetch(String line) throws IOException { public void uidfetch(OutputStream outputStream, String line) throws IOException {
untagged("2 FETCH (UID 2)"); untagged(outputStream, "2 FETCH (UID 2)");
untagged("3 EXPUNGE"); untagged(outputStream, "3 EXPUNGE");
untagged("3 EXISTS"); untagged(outputStream, "3 EXISTS");
numberOfMessages--; numberOfMessages--;
ok(); ok(outputStream);
} }
}); });
} }
@Test @Test
public void testUIDRange() { public void testUIDRange() {
testWithHandler( testWithHandler((folder, handler) -> {
new IMAPTest() { Message[] msgs = ((UIDFolder) folder).getMessagesByUID(2, 4);
@Override assertTrue(msgs[1] == null || msgs[1].isExpunged());
public void test(Folder folder, IMAPHandlerExpunge handler) msgs[0].getFlags();
throws MessagingException { assertEquals(2, handler.getSeqNum());
Message[] msgs = ((UIDFolder) folder).getMessagesByUID(2, 4); msgs[2].getFlags();
assertTrue(msgs[1] == null || msgs[1].isExpunged()); assertEquals(3, handler.getSeqNum());
msgs[0].getFlags();
assertEquals(2, handler.getSeqNum());
msgs[2].getFlags();
assertEquals(3, handler.getSeqNum());
}
}, },
new IMAPHandlerExpunge() { new IMAPHandlerExpunge() {
@Override @Override
public void uidfetch(String line) throws IOException { public void uidfetch(OutputStream outputStream, String line) throws IOException {
untagged("2 FETCH (UID 2)"); untagged(outputStream, "2 FETCH (UID 2)");
untagged("3 FETCH (UID 3)"); untagged(outputStream, "3 FETCH (UID 3)");
untagged("4 FETCH (UID 4)"); untagged(outputStream, "4 FETCH (UID 4)");
untagged("3 EXPUNGE"); untagged(outputStream, "3 EXPUNGE");
untagged("3 EXISTS"); untagged(outputStream, "3 EXISTS");
numberOfMessages--; numberOfMessages--;
ok(); ok(outputStream);
} }
}); });
} }
@Test @Test
public void testUIDRange2() { public void testUIDRange2() {
testWithHandler( testWithHandler((folder, handler) -> {
new IMAPTest() { Message[] msgs = ((UIDFolder) folder).getMessagesByUID(2, 4);
@Override assertTrue(msgs[1] == null || msgs[1].isExpunged());
public void test(Folder folder, IMAPHandlerExpunge handler) msgs[0].getFlags();
throws MessagingException { assertEquals(2, handler.getSeqNum());
Message[] msgs = ((UIDFolder) folder).getMessagesByUID(2, 4); msgs[2].getFlags();
assertTrue(msgs[1] == null || msgs[1].isExpunged()); assertEquals(3, handler.getSeqNum());
msgs[0].getFlags();
assertEquals(2, handler.getSeqNum());
msgs[2].getFlags();
assertEquals(3, handler.getSeqNum());
}
}, },
new IMAPHandlerExpunge() { new IMAPHandlerExpunge() {
@Override @Override
public void uidfetch(String line) throws IOException { public void uidfetch(OutputStream outputStream, String line) throws IOException {
untagged("2 FETCH (UID 2)"); untagged(outputStream, "2 FETCH (UID 2)");
untagged("3 FETCH (UID 3)"); untagged(outputStream, "3 FETCH (UID 3)");
untagged("3 EXPUNGE"); untagged(outputStream, "3 EXPUNGE");
untagged("3 EXISTS"); untagged(outputStream, "3 EXISTS");
untagged("3 FETCH (UID 4)"); untagged(outputStream, "3 FETCH (UID 4)");
numberOfMessages--; numberOfMessages--;
ok(); ok(outputStream);
} }
}); });
} }
@Test @Test
public void testUIDRange3() { public void testUIDRange3() {
testWithHandler( testWithHandler((folder, handler) -> {
new IMAPTest() { Message[] msgs = ((UIDFolder) folder).getMessagesByUID(2, 4);
@Override // UID 3 is unknown and not returned
public void test(Folder folder, IMAPHandlerExpunge handler) assertEquals(2, msgs.length);
throws MessagingException { msgs[0].getFlags();
Message[] msgs = ((UIDFolder) folder).getMessagesByUID(2, 4); assertEquals(2, handler.getSeqNum());
// UID 3 is unknown and not returned msgs[1].getFlags();
assertEquals(2, msgs.length); assertEquals(3, handler.getSeqNum());
msgs[0].getFlags();
assertEquals(2, handler.getSeqNum());
msgs[1].getFlags();
assertEquals(3, handler.getSeqNum());
}
}, },
new IMAPHandlerExpunge() { new IMAPHandlerExpunge() {
@Override @Override
public void uidfetch(String line) throws IOException { public void uidfetch(OutputStream outputStream, String line) throws IOException {
untagged("2 FETCH (UID 2)"); untagged(outputStream, "2 FETCH (UID 2)");
untagged("3 EXPUNGE"); untagged(outputStream, "3 EXPUNGE");
untagged("3 EXISTS"); untagged(outputStream, "3 EXISTS");
untagged("3 FETCH (UID 4)"); untagged(outputStream, "3 FETCH (UID 4)");
numberOfMessages--; numberOfMessages--;
ok(); ok(outputStream);
} }
}); });
} }
@Test @Test
public void testUIDRange4() { public void testUIDRange4() {
testWithHandler( testWithHandler((folder, handler) -> {
new IMAPTest() { Message[] msgs = ((UIDFolder) folder).getMessagesByUID(1, 3);
@Override assertEquals(3, msgs.length);
public void test(Folder folder, IMAPHandlerExpunge handler) msgs[0].getFlags();
throws MessagingException { assertEquals(1, handler.getSeqNum());
Message[] msgs = ((UIDFolder) folder).getMessagesByUID(1, 3); msgs[1].getFlags();
assertEquals(3, msgs.length); assertEquals(2, handler.getSeqNum());
msgs[0].getFlags(); msgs[2].getFlags();
assertEquals(1, handler.getSeqNum()); assertEquals(3, handler.getSeqNum());
msgs[1].getFlags();
assertEquals(2, handler.getSeqNum());
msgs[2].getFlags();
assertEquals(3, handler.getSeqNum());
}
}, },
new IMAPHandlerExpunge() { new IMAPHandlerExpunge() {
@Override @Override
public void uidfetch(String line) throws IOException { public void uidfetch(OutputStream outputStream, String line) throws IOException {
untagged("1 FETCH (UID 1)"); untagged(outputStream, "1 FETCH (UID 1)");
untagged("2 FETCH (UID 2)"); untagged(outputStream, "2 FETCH (UID 2)");
untagged("3 FETCH (UID 3)"); untagged(outputStream, "3 FETCH (UID 3)");
untagged("4 EXPUNGE"); untagged(outputStream, "4 EXPUNGE");
untagged("3 EXISTS"); untagged(outputStream, "3 EXISTS");
numberOfMessages--; numberOfMessages--;
ok(); ok(outputStream);
} }
}); });
} }
@Test @Test
public void testUIDRange5() { public void testUIDRange5() {
testWithHandler( testWithHandler((folder, handler) -> {
new IMAPTest() { Message[] msgs = ((UIDFolder) folder).getMessagesByUID(2, 4);
@Override assertEquals(3, msgs.length);
public void test(Folder folder, IMAPHandlerExpunge handler) msgs[0].getFlags();
throws MessagingException { assertEquals(1, handler.getSeqNum());
Message[] msgs = ((UIDFolder) folder).getMessagesByUID(2, 4); msgs[1].getFlags();
assertEquals(3, msgs.length); assertEquals(2, handler.getSeqNum());
msgs[0].getFlags(); msgs[2].getFlags();
assertEquals(1, handler.getSeqNum()); assertEquals(3, handler.getSeqNum());
msgs[1].getFlags();
assertEquals(2, handler.getSeqNum());
msgs[2].getFlags();
assertEquals(3, handler.getSeqNum());
}
}, },
new IMAPHandlerExpunge() { new IMAPHandlerExpunge() {
@Override @Override
public void uidfetch(String line) throws IOException { public void uidfetch(OutputStream outputStream, String line) throws IOException {
untagged("2 FETCH (UID 2)"); untagged(outputStream, "2 FETCH (UID 2)");
untagged("3 FETCH (UID 3)"); untagged(outputStream, "3 FETCH (UID 3)");
untagged("4 FETCH (UID 4)"); untagged(outputStream, "4 FETCH (UID 4)");
untagged("1 EXPUNGE"); untagged(outputStream, "1 EXPUNGE");
untagged("3 EXISTS"); untagged(outputStream, "3 EXISTS");
numberOfMessages--; numberOfMessages--;
ok(); ok(outputStream);
} }
}); });
} }
@Test @Test
public void testUIDList() { public void testUIDList() {
testWithHandler( testWithHandler((folder, handler) -> {
new IMAPTest() { Message[] msgs = ((UIDFolder) folder).getMessagesByUID(
@Override new long[]{2, 3, 4});
public void test(Folder folder, IMAPHandlerExpunge handler) assertTrue(msgs[1] == null || msgs[1].isExpunged());
throws MessagingException { msgs[0].getFlags();
Message[] msgs = ((UIDFolder) folder).getMessagesByUID( assertEquals(2, handler.getSeqNum());
new long[]{2, 3, 4}); msgs[2].getFlags();
assertTrue(msgs[1] == null || msgs[1].isExpunged()); assertEquals(3, handler.getSeqNum());
msgs[0].getFlags();
assertEquals(2, handler.getSeqNum());
msgs[2].getFlags();
assertEquals(3, handler.getSeqNum());
}
}, },
new IMAPHandlerExpunge() { new IMAPHandlerExpunge() {
@Override @Override
public void uidfetch(String line) throws IOException { public void uidfetch(OutputStream outputStream, String line) throws IOException {
untagged("2 FETCH (UID 2)"); untagged(outputStream, "2 FETCH (UID 2)");
untagged("3 FETCH (UID 3)"); untagged(outputStream, "3 FETCH (UID 3)");
untagged("4 FETCH (UID 4)"); untagged(outputStream, "4 FETCH (UID 4)");
untagged("3 EXPUNGE"); untagged(outputStream, "3 EXPUNGE");
untagged("3 EXISTS"); untagged(outputStream, "3 EXISTS");
numberOfMessages--; numberOfMessages--;
ok(); ok(outputStream);
} }
}); });
} }
@Test @Test
public void testUIDList2() { public void testUIDList2() {
testWithHandler( testWithHandler((folder, handler) -> {
new IMAPTest() { Message[] msgs = ((UIDFolder) folder).getMessagesByUID(
@Override new long[]{2, 3, 4});
public void test(Folder folder, IMAPHandlerExpunge handler) assertTrue(msgs[1] == null || msgs[1].isExpunged());
throws MessagingException { msgs[0].getFlags();
Message[] msgs = ((UIDFolder) folder).getMessagesByUID( assertEquals(2, handler.getSeqNum());
new long[]{2, 3, 4}); msgs[2].getFlags();
assertTrue(msgs[1] == null || msgs[1].isExpunged()); assertEquals(3, handler.getSeqNum());
msgs[0].getFlags();
assertEquals(2, handler.getSeqNum());
msgs[2].getFlags();
assertEquals(3, handler.getSeqNum());
}
}, },
new IMAPHandlerExpunge() { new IMAPHandlerExpunge() {
@Override @Override
public void uidfetch(String line) throws IOException { public void uidfetch(OutputStream outputStream, String line) throws IOException {
untagged("2 FETCH (UID 2)"); untagged(outputStream, "2 FETCH (UID 2)");
untagged("3 FETCH (UID 3)"); untagged(outputStream, "3 FETCH (UID 3)");
untagged("3 EXPUNGE"); untagged(outputStream, "3 EXPUNGE");
untagged("3 EXISTS"); untagged(outputStream, "3 EXISTS");
untagged("3 FETCH (UID 4)"); untagged(outputStream, "3 FETCH (UID 4)");
numberOfMessages--; numberOfMessages--;
ok(); ok(outputStream);
} }
}); });
} }
@Test @Test
public void testUIDList3() { public void testUIDList3() {
testWithHandler( testWithHandler((folder, handler) -> {
new IMAPTest() { Message[] msgs = ((UIDFolder) folder).getMessagesByUID(
@Override new long[]{2, 3, 4});
public void test(Folder folder, IMAPHandlerExpunge handler) assertTrue(msgs[1] == null || msgs[1].isExpunged());
throws MessagingException { msgs[0].getFlags();
Message[] msgs = ((UIDFolder) folder).getMessagesByUID( assertEquals(2, handler.getSeqNum());
new long[]{2, 3, 4}); msgs[2].getFlags();
assertTrue(msgs[1] == null || msgs[1].isExpunged()); assertEquals(3, handler.getSeqNum());
msgs[0].getFlags();
assertEquals(2, handler.getSeqNum());
msgs[2].getFlags();
assertEquals(3, handler.getSeqNum());
}
}, },
new IMAPHandlerExpunge() { new IMAPHandlerExpunge() {
@Override @Override
public void uidfetch(String line) throws IOException { public void uidfetch(OutputStream outputStream, String line) throws IOException {
untagged("2 FETCH (UID 2)"); untagged(outputStream, "2 FETCH (UID 2)");
untagged("3 EXPUNGE"); untagged(outputStream, "3 EXPUNGE");
untagged("3 EXISTS"); untagged(outputStream, "3 EXISTS");
untagged("3 FETCH (UID 4)"); untagged(outputStream, "3 FETCH (UID 4)");
numberOfMessages--; numberOfMessages--;
ok(); ok(outputStream);
} }
}); });
} }
@Test @Test
public void testUIDList4() { public void testUIDList4() {
testWithHandler( testWithHandler((folder, handler) -> {
new IMAPTest() { Message[] msgs = ((UIDFolder) folder).getMessagesByUID(
@Override new long[]{1, 2, 3});
public void test(Folder folder, IMAPHandlerExpunge handler) assertEquals(3, msgs.length);
throws MessagingException { msgs[0].getFlags();
Message[] msgs = ((UIDFolder) folder).getMessagesByUID( assertEquals(1, handler.getSeqNum());
new long[]{1, 2, 3}); msgs[1].getFlags();
assertEquals(3, msgs.length); assertEquals(2, handler.getSeqNum());
msgs[0].getFlags(); msgs[2].getFlags();
assertEquals(1, handler.getSeqNum()); assertEquals(3, handler.getSeqNum());
msgs[1].getFlags();
assertEquals(2, handler.getSeqNum());
msgs[2].getFlags();
assertEquals(3, handler.getSeqNum());
}
}, },
new IMAPHandlerExpunge() { new IMAPHandlerExpunge() {
@Override @Override
public void uidfetch(String line) throws IOException { public void uidfetch(OutputStream outputStream, String line) throws IOException {
untagged("1 FETCH (UID 1)"); untagged(outputStream, "1 FETCH (UID 1)");
untagged("2 FETCH (UID 2)"); untagged(outputStream, "2 FETCH (UID 2)");
untagged("3 FETCH (UID 3)"); untagged(outputStream, "3 FETCH (UID 3)");
untagged("4 EXPUNGE"); untagged(outputStream, "4 EXPUNGE");
untagged("3 EXISTS"); untagged(outputStream, "3 EXISTS");
numberOfMessages--; numberOfMessages--;
ok(); ok(outputStream);
} }
}); });
} }
@Test @Test
public void testUIDList5() { public void testUIDList5() {
testWithHandler( testWithHandler((folder, handler) -> {
new IMAPTest() { Message[] msgs = ((UIDFolder) folder).getMessagesByUID(
@Override new long[]{2, 3, 4});
public void test(Folder folder, IMAPHandlerExpunge handler) assertEquals(3, msgs.length);
throws MessagingException { msgs[0].getFlags();
Message[] msgs = ((UIDFolder) folder).getMessagesByUID( assertEquals(1, handler.getSeqNum());
new long[]{2, 3, 4}); msgs[1].getFlags();
assertEquals(3, msgs.length); assertEquals(2, handler.getSeqNum());
msgs[0].getFlags(); msgs[2].getFlags();
assertEquals(1, handler.getSeqNum()); assertEquals(3, handler.getSeqNum());
msgs[1].getFlags();
assertEquals(2, handler.getSeqNum());
msgs[2].getFlags();
assertEquals(3, handler.getSeqNum());
}
}, },
new IMAPHandlerExpunge() { new IMAPHandlerExpunge() {
@Override @Override
public void uidfetch(String line) throws IOException { public void uidfetch(OutputStream outputStream, String line) throws IOException {
untagged("2 FETCH (UID 2)"); untagged(outputStream, "2 FETCH (UID 2)");
untagged("3 FETCH (UID 3)"); untagged(outputStream, "3 FETCH (UID 3)");
untagged("4 FETCH (UID 4)"); untagged(outputStream, "4 FETCH (UID 4)");
untagged("1 EXPUNGE"); untagged(outputStream, "1 EXPUNGE");
untagged("3 EXISTS"); untagged(outputStream, "3 EXISTS");
numberOfMessages--; numberOfMessages--;
ok(); ok(outputStream);
} }
}); });
} }
@ -441,18 +382,18 @@ public final class IMAPUidExpungeTest {
private static int seqnum; private static int seqnum;
@Override @Override
public void select(String line) throws IOException { public void select(OutputStream outputStream, String line) throws IOException {
numberOfMessages = 4; numberOfMessages = 4;
super.select(line); super.select(outputStream, line);
} }
@Override @Override
public void fetch(String line) throws IOException { public void fetch(OutputStream outputStream, String line) throws IOException {
StringTokenizer st = new StringTokenizer(line, " "); StringTokenizer st = new StringTokenizer(line, " ");
String tag = st.nextToken(); String tag = st.nextToken();
String command = st.nextToken(); String command = st.nextToken();
seqnum = Integer.parseInt(st.nextToken()); seqnum = Integer.parseInt(st.nextToken());
ok(); ok(outputStream);
} }
public int getSeqNum() { public int getSeqNum() {

View file

@ -52,18 +52,13 @@ public class SMTPHandler extends ProtocolHandler {
*/ */
protected Set<String> extensions = new HashSet<String>(); protected Set<String> extensions = new HashSet<String>();
public SMTPHandler(InputStream inputStream,
OutputStream outputStream) {
super(inputStream, outputStream);
}
/** /**
* Send greetings. * Send greetings.
* *
* @throws IOException unable to write to socket * @throws IOException unable to write to socket
*/ */
@Override @Override
public void sendGreetings() throws IOException { public void sendGreetings(OutputStream outputStream) throws IOException {
println("220 localhost dummy server ready"); println("220 localhost dummy server ready");
} }
@ -73,7 +68,7 @@ public class SMTPHandler extends ProtocolHandler {
* @param str String to send * @param str String to send
* @throws IOException unable to write to socket * @throws IOException unable to write to socket
*/ */
public void println(final String str) throws IOException { public void println(OutputStream outputStream, final String str) throws IOException {
writer.print(str); writer.print(str);
writer.print("\r\n"); writer.print("\r\n");
writer.flush(); writer.flush();

View file

@ -50,16 +50,14 @@ public abstract class ProtocolHandler {
while (!quit) { while (!quit) {
handleCommand(inputStream, outputStream); handleCommand(inputStream, outputStream);
} }
if (quit) { try {
try { if (inputStream != null)
if (inputStream != null) inputStream.close();
inputStream.close(); if (outputStream != null) {
if (outputStream != null) { outputStream.close();
outputStream.close();
}
} catch (final IOException e) {
logger.log(Level.SEVERE, "Error", e);
} }
} catch (final IOException e) {
logger.log(Level.SEVERE, "Error", e);
} }
} catch (IOException sex) { } catch (IOException sex) {
// ignore it, often get "connection reset" when client closes // ignore it, often get "connection reset" when client closes

View file

@ -31,6 +31,7 @@ import org.xbib.net.mail.util.SocketFetcher;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket; import java.net.Socket;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
@ -880,7 +881,7 @@ public final class SocketFetcherTest {
} }
@Override @Override
public void handleCommand() throws IOException { public void handleCommand(InputStream inputStream, OutputStream outputStream) throws IOException {
if (!http) { if (!http) {
int c = inputStream.read(); int c = inputStream.read();
if (c >= 0) { if (c >= 0) {
@ -892,10 +893,10 @@ public final class SocketFetcherTest {
// else, http... // else, http...
String line; String line;
while ((line = readLine()) != null) { while ((line = readLine(inputStream)) != null) {
// any data means a real client connected // any data means a real client connected
connected = true; connected = true;
if (line.length() == 0) if (line.isEmpty())
break; break;
if (line.startsWith("Proxy-Authorization:")) { if (line.startsWith("Proxy-Authorization:")) {
int i = line.indexOf("Basic ") + 6; int i = line.indexOf("Basic ") + 6;

View file

@ -38,6 +38,8 @@ import org.xbib.net.mail.util.WriteTimeoutSocket;
import java.io.FileDescriptor; import java.io.FileDescriptor;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.net.InetAddress; import java.net.InetAddress;
@ -453,7 +455,7 @@ public final class WriteTimeoutSocketTest {
} }
private void close(TestServer testServer) { private void close(TestServer testServer) {
if (testServer == null || !testServer.isAlive()) { if (testServer == null) {
return; return;
} }
@ -496,19 +498,19 @@ public final class WriteTimeoutSocketTest {
*/ */
private static final class TimeoutHandler extends IMAPHandler { private static final class TimeoutHandler extends IMAPHandler {
@Override @Override
protected void collectMessage(int bytes) throws IOException { protected void collectMessage(InputStream inputStream, OutputStream outputStream, int bytes) throws IOException {
try { try {
// allow plenty of time for even slow machines to time out // allow plenty of time for even slow machines to time out
Thread.sleep(TIMEOUT * 20); Thread.sleep(TIMEOUT * 20);
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
} }
super.collectMessage(bytes); super.collectMessage(inputStream, outputStream, bytes);
} }
@Override @Override
public void list(String line) throws IOException { public void list(OutputStream outputStream, String line) throws IOException {
untagged("LIST () \"/\" test"); untagged(outputStream, "LIST () \"/\" test");
ok(); ok(outputStream);
} }
} }