working on fixes for mail test server

This commit is contained in:
Jörg Prante 2024-07-31 18:37:32 +02:00
parent d803fab767
commit 0849a6decf
15 changed files with 340 additions and 376 deletions

View file

@ -24,6 +24,7 @@ import org.junit.jupiter.api.Test;
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.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -80,7 +81,7 @@ public final class IMAPAlertTest {
store.close(); store.close();
} }
} catch (final Exception e) { } catch (final Exception e) {
e.printStackTrace(); //e.printStackTrace();
fail(e.getMessage()); fail(e.getMessage());
} finally { } finally {
if (server != null) { if (server != null) {
@ -94,9 +95,9 @@ public final class IMAPAlertTest {
*/ */
private static final class IMAPHandlerAlert extends IMAPHandler { private static final class IMAPHandlerAlert extends IMAPHandler {
@Override @Override
public void login() throws IOException { public void login(OutputStream outputStream) throws IOException {
untagged("OK [ALERT] account is over quota"); untagged(outputStream, "OK [ALERT] account is over quota");
super.login(); super.login(outputStream);
} }
} }
} }

View file

@ -23,6 +23,7 @@ import org.junit.jupiter.api.Test;
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;
@ -37,11 +38,11 @@ public final class IMAPCloseFailureTest {
static boolean first = true; static boolean first = true;
@Override @Override
public void examine(String line) throws IOException { public void examine(OutputStream outputStream, String line) throws IOException {
if (first) if (first)
no("mailbox gone"); no(outputStream, "mailbox gone");
else else
super.examine(line); super.examine(outputStream, line);
first = false; first = false;
} }
} }
@ -50,11 +51,11 @@ public final class IMAPCloseFailureTest {
static boolean first = true; static boolean first = true;
@Override @Override
public void examine(String line) throws IOException { public void examine(OutputStream outputStream, String line) throws IOException {
if (first) if (first)
bad("mailbox gone"); bad(outputStream, "mailbox gone");
else else
super.examine(line); super.examine(outputStream, line);
first = false; first = false;
} }
} }

View file

@ -25,6 +25,7 @@ import org.xbib.net.mail.test.test.TestServer;
import org.xbib.net.mail.util.MailConnectException; import org.xbib.net.mail.util.MailConnectException;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.util.Properties; import java.util.Properties;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@ -89,12 +90,12 @@ public final class IMAPConnectFailureTest {
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 {
untagged("OK IMAPHandler"); untagged(outputStream, "OK IMAPHandler");
} }
@Override @Override
public void capability() throws IOException { public void capability(OutputStream outputStream) throws IOException {
exit(); exit();
} }
}; };

View file

@ -28,6 +28,7 @@ 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.OutputStream;
import java.util.HashSet; import java.util.HashSet;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
@ -75,11 +76,12 @@ public final class IMAPFetchProfileTest {
}, },
new IMAPHandlerFetch() { new IMAPHandlerFetch() {
@Override @Override
public void fetch(String line) throws IOException { public void fetch(OutputStream outputStream, String line) throws IOException {
if (line.contains("INTERNALDATE")) if (line.contains("INTERNALDATE")) {
saw.add("INTERNALDATE"); saw.add("INTERNALDATE");
untagged("1 FETCH (INTERNALDATE \"" + RDATE + "\")"); }
ok(); untagged(outputStream, "1 FETCH (INTERNALDATE \"" + RDATE + "\")");
ok(outputStream);
} }
}); });
} }
@ -103,11 +105,12 @@ public final class IMAPFetchProfileTest {
}, },
new IMAPHandlerFetch() { new IMAPHandlerFetch() {
@Override @Override
public void fetch(String line) throws IOException { public void fetch(OutputStream outputStream, String line) throws IOException {
if (line.contains("INTERNALDATE")) if (line.contains("INTERNALDATE")) {
saw.add("INTERNALDATE"); saw.add("INTERNALDATE");
untagged("1 FETCH (INTERNALDATE \"" + RDATE + "\")"); }
ok(); untagged(outputStream, "1 FETCH (INTERNALDATE \"" + RDATE + "\")");
ok(outputStream);
} }
}); });
} }
@ -126,12 +129,13 @@ public final class IMAPFetchProfileTest {
}, },
new IMAPHandlerFetch() { new IMAPHandlerFetch() {
@Override @Override
public void fetch(String line) throws IOException { public void fetch(OutputStream outputStream, String line) throws IOException {
if (line.contains("INTERNALDATE")) if (line.contains("INTERNALDATE")) {
saw.add("INTERNALDATE"); saw.add("INTERNALDATE");
untagged("1 FETCH (ENVELOPE " + ENVELOPE + }
untagged(outputStream, "1 FETCH (ENVELOPE " + ENVELOPE +
" INTERNALDATE \"" + RDATE + "\" RFC822.SIZE 0)"); " INTERNALDATE \"" + RDATE + "\" RFC822.SIZE 0)");
ok(); ok(outputStream);
} }
}); });
} }
@ -182,9 +186,9 @@ public final class IMAPFetchProfileTest {
protected static Set<String> saw = new HashSet<>(); protected static Set<String> saw = new HashSet<>();
@Override @Override
public void select(String line) throws IOException { public void select(OutputStream outputStream, String line) throws IOException {
numberOfMessages = 1; numberOfMessages = 1;
super.select(line); super.select(outputStream, line);
} }
public boolean saw(String item) { public boolean saw(String item) {

View file

@ -27,6 +27,7 @@ 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.OutputStream;
import java.util.Properties; import java.util.Properties;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import java.util.logging.Level; import java.util.logging.Level;
@ -75,21 +76,21 @@ class IMAPFolderTest {
}, },
new IMAPHandler() { new IMAPHandler() {
@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 = st.nextToken(); String name = st.nextToken();
if (name.equals(utf7Folder)) if (name.equals(utf7Folder))
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) \"/\" " + utf7Folder); untagged(outputStream, "LIST (\\HasNoChildren) \"/\" " + utf7Folder);
ok(); ok(outputStream);
} }
}); });
} }
@ -111,22 +112,21 @@ class IMAPFolderTest {
}, },
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(outputStream);
ok();
} }
}); });
} }
@ -148,15 +148,15 @@ class IMAPFolderTest {
}, },
new IMAPHandler() { new IMAPHandler() {
@Override @Override
public void delete(String line) throws IOException { public void delete(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 "DELETE" st.nextToken(); // skip "DELETE"
String name = st.nextToken(); String name = st.nextToken();
if (name.equals(utf7Folder)) if (name.equals(utf7Folder))
ok(); ok(outputStream);
else else
no("wrong name"); no(outputStream, "wrong name");
} }
}); });
} }
@ -178,15 +178,16 @@ class IMAPFolderTest {
}, },
new IMAPUtf8Handler() { new IMAPUtf8Handler() {
@Override @Override
public void delete(String line) throws IOException { public void delete(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 "DELETE" st.nextToken(); // skip "DELETE"
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");
}
} }
}); });
} }
@ -210,15 +211,15 @@ class IMAPFolderTest {
}, },
new IMAPHandler() { new IMAPHandler() {
@Override @Override
public void select(String line) throws IOException { public void select(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 "SELECT" st.nextToken(); // skip "SELECT"
String name = st.nextToken(); String name = st.nextToken();
if (name.equals(utf7Folder)) if (name.equals(utf7Folder))
ok(); ok(outputStream);
else else
no("wrong name"); no(outputStream, "wrong name");
} }
}); });
} }
@ -242,15 +243,15 @@ class IMAPFolderTest {
}, },
new IMAPUtf8Handler() { new IMAPUtf8Handler() {
@Override @Override
public void select(String line) throws IOException { public void select(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 "SELECT" st.nextToken(); // skip "SELECT"
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");
} }
}); });
} }
@ -274,15 +275,15 @@ class IMAPFolderTest {
}, },
new IMAPHandler() { new IMAPHandler() {
@Override @Override
public void examine(String line) throws IOException { public void examine(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 "EXAMINE" st.nextToken(); // skip "EXAMINE"
String name = st.nextToken(); String name = st.nextToken();
if (name.equals(utf7Folder)) if (name.equals(utf7Folder))
ok(); ok(outputStream);
else else
no("wrong name"); no(outputStream, "wrong name");
} }
}); });
} }
@ -306,15 +307,15 @@ class IMAPFolderTest {
}, },
new IMAPUtf8Handler() { new IMAPUtf8Handler() {
@Override @Override
public void examine(String line) throws IOException { public void examine(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 "EXAMINE" st.nextToken(); // skip "EXAMINE"
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");
} }
}); });
} }
@ -336,17 +337,17 @@ class IMAPFolderTest {
}, },
new IMAPHandler() { new IMAPHandler() {
@Override @Override
public void status(String line) throws IOException { public void status(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 "STATUS" st.nextToken(); // skip "STATUS"
String name = st.nextToken(); String name = st.nextToken();
if (name.equals(utf7Folder)) { if (name.equals(utf7Folder)) {
untagged("STATUS " + utf7Folder + untagged(outputStream, "STATUS " + utf7Folder +
" (UIDVALIDITY 123)"); " (UIDVALIDITY 123)");
ok(); ok(outputStream);
} else } else
no("wrong name"); no(outputStream, "wrong name");
} }
}); });
} }
@ -368,17 +369,17 @@ class IMAPFolderTest {
}, },
new IMAPUtf8Handler() { new IMAPUtf8Handler() {
@Override @Override
public void status(String line) throws IOException { public void status(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 "STATUS" st.nextToken(); // skip "STATUS"
String name = unquote(st.nextToken()); String name = unquote(st.nextToken());
if (name.equals(utf8Folder)) { if (name.equals(utf8Folder)) {
untagged("STATUS \"" + utf8Folder + untagged(outputStream, "STATUS \"" + utf8Folder +
"\" (UIDVALIDITY 123)"); "\" (UIDVALIDITY 123)");
ok(); ok(outputStream);
} else } else
no("wrong name"); no(outputStream, "wrong name");
} }
}); });
} }
@ -426,9 +427,9 @@ class IMAPFolderTest {
}, },
new IMAPHandler() { new IMAPHandler() {
@Override @Override
public void select(String line) throws IOException { public void select(OutputStream outputStream, String line) throws IOException {
untagged("NO [UIDNOTSTICKY]"); untagged(outputStream, "NO [UIDNOTSTICKY]");
super.select(line); super.select(outputStream, line);
} }
}); });
} }
@ -457,10 +458,10 @@ class IMAPFolderTest {
}, },
new IMAPHandler() { new IMAPHandler() {
@Override @Override
public void search(String line) throws IOException { public void search(OutputStream outputStream, String line) throws IOException {
untagged("1 EXPUNGE"); untagged(outputStream, "1 EXPUNGE");
untagged("0 EXISTS"); untagged(outputStream, "0 EXISTS");
super.search(line); super.search(outputStream, line);
} }
}); });
} }
@ -527,8 +528,8 @@ class IMAPFolderTest {
} }
@Override @Override
public void enable(String line) throws IOException { public void enable(OutputStream outputStream, String line) throws IOException {
ok(); ok(outputStream);
} }
} }
} }

View file

@ -21,10 +21,12 @@ import org.xbib.net.mail.test.test.ProtocolHandler;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.channels.Channels;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Base64; import java.util.Base64;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* Handle IMAP connection. * Handle IMAP connection.
@ -33,6 +35,8 @@ import java.util.logging.Level;
*/ */
public class IMAPHandler extends ProtocolHandler { public class IMAPHandler extends ProtocolHandler {
private static final Logger logger = Logger.getLogger(IMAPHandler.class.getName());
/** /**
* Current line. * Current line.
*/ */
@ -58,19 +62,14 @@ public class IMAPHandler extends ProtocolHandler {
*/ */
protected int numberOfRecentMessages = 0; protected int numberOfRecentMessages = 0;
public IMAPHandler(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 {
untagged("OK [CAPABILITY " + capabilities + "] IMAPHandler"); untagged(outputStream, "OK [CAPABILITY " + capabilities + "] IMAPHandler");
} }
/** /**
@ -79,10 +78,9 @@ public class IMAPHandler 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); Channels.newChannel(outputStream).write(StandardCharsets.UTF_8.encode(str + "\r\n"));
writer.print("\r\n"); outputStream.flush();
writer.flush();
} }
/** /**
@ -91,8 +89,8 @@ public class IMAPHandler extends ProtocolHandler {
* @param resp the response to send * @param resp the response to send
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void tagged(final String resp) throws IOException { public void tagged(OutputStream outputStream, final String resp) throws IOException {
println(tag + " " + resp); println(outputStream, tag + " " + resp);
} }
/** /**
@ -101,8 +99,8 @@ public class IMAPHandler extends ProtocolHandler {
* @param resp the response to send * @param resp the response to send
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void untagged(final String resp) throws IOException { public void untagged(OutputStream outputStream, final String resp) throws IOException {
println("* " + resp); println(outputStream, "* " + resp);
} }
/** /**
@ -110,8 +108,8 @@ public class IMAPHandler extends ProtocolHandler {
* *
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void ok() throws IOException { public void ok(OutputStream outputStream) throws IOException {
tagged("OK"); tagged(outputStream, "OK");
} }
/** /**
@ -120,8 +118,8 @@ public class IMAPHandler extends ProtocolHandler {
* @param msg the message to send * @param msg the message to send
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void ok(final String msg) throws IOException { public void ok(OutputStream outputStream, final String msg) throws IOException {
tagged("OK " + (msg != null ? msg : "")); tagged(outputStream, "OK " + (msg != null ? msg : ""));
} }
/** /**
@ -130,8 +128,8 @@ public class IMAPHandler extends ProtocolHandler {
* @param msg the message to send * @param msg the message to send
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void no(final String msg) throws IOException { public void no(OutputStream outputStream, final String msg) throws IOException {
tagged("NO " + (msg != null ? msg : "")); tagged(outputStream, "NO " + (msg != null ? msg : ""));
} }
/** /**
@ -140,8 +138,8 @@ public class IMAPHandler extends ProtocolHandler {
* @param msg the message to send * @param msg the message to send
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void bad(final String msg) throws IOException { public void bad(OutputStream outputStream, final String msg) throws IOException {
tagged("BAD " + (msg != null ? msg : "")); tagged(outputStream, "BAD " + (msg != null ? msg : ""));
} }
/** /**
@ -150,8 +148,8 @@ public class IMAPHandler extends ProtocolHandler {
* @param msg the message to send * @param msg the message to send
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void bye(final String msg) throws IOException { public void bye(OutputStream outputStream, final String msg) throws IOException {
untagged("BYE " + (msg != null ? msg : "")); untagged(outputStream, "BYE " + (msg != null ? msg : ""));
exit(); exit();
} }
@ -160,8 +158,8 @@ public class IMAPHandler extends ProtocolHandler {
* *
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void cont() throws IOException { public void cont(OutputStream outputStream) throws IOException {
println("+ please continue"); println(outputStream, "+ please continue");
} }
/** /**
@ -169,8 +167,8 @@ public class IMAPHandler extends ProtocolHandler {
* *
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void cont(String msg) throws IOException { public void cont(OutputStream outputStream, String msg) throws IOException {
println("+ " + (msg != null ? msg : "")); println(outputStream, "+ " + (msg != null ? msg : ""));
} }
/** /**
@ -179,96 +177,92 @@ public class IMAPHandler extends ProtocolHandler {
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
@Override @Override
public void handleCommand() throws IOException { public void handleCommand(InputStream inputStream, OutputStream outputStream) throws IOException {
currentLine = super.readLine(); currentLine = super.readLine(inputStream);
if (currentLine == null) { if (currentLine == null) {
// probably just EOF because the socket was closed // probably just EOF because the socket was closed
//LOGGER.severe("Current line is null!"); //LOGGER.severe("Current line is null!");
exit(); exit();
return; return;
} }
StringTokenizer ct = new StringTokenizer(currentLine, " "); StringTokenizer ct = new StringTokenizer(currentLine, " ");
if (!ct.hasMoreTokens()) { if (!ct.hasMoreTokens()) {
LOGGER.log(Level.SEVERE, "ERROR no command tag: {0}", logger.log(Level.SEVERE, "ERROR no command tag: {0}", escape(currentLine));
escape(currentLine)); bad(outputStream, "no command tag");
bad("no command tag");
return; return;
} }
tag = ct.nextToken(); tag = ct.nextToken();
if (!ct.hasMoreTokens()) { if (!ct.hasMoreTokens()) {
LOGGER.log(Level.SEVERE, "ERROR no command: {0}", logger.log(Level.SEVERE, "ERROR no command: {0}",
escape(currentLine)); escape(currentLine));
bad("no command"); bad(outputStream, "no command");
return; return;
} }
final String commandName = ct.nextToken().toUpperCase(); final String commandName = ct.nextToken().toUpperCase();
if (commandName == null) { if (commandName.isEmpty()) {
LOGGER.severe("Command name is empty!"); logger.severe("Command name is empty!");
exit(); exit();
return; return;
} }
if (commandName.equals("LOGIN")) { if (commandName.equals("LOGIN")) {
login(); login(outputStream);
} else if (commandName.equals("AUTHENTICATE")) { } else if (commandName.equals("AUTHENTICATE")) {
String mech = ct.nextToken().toUpperCase(); String mech = ct.nextToken().toUpperCase();
String ir = null; String ir = null;
if (ct.hasMoreTokens()) if (ct.hasMoreTokens()) {
ir = ct.nextToken(); ir = ct.nextToken();
authenticate(mech, ir); }
authenticate(inputStream, outputStream, mech, ir);
} else if (commandName.equals("CAPABILITY")) { } else if (commandName.equals("CAPABILITY")) {
capability(); capability(outputStream);
} else if (commandName.equals("NOOP")) { } else if (commandName.equals("NOOP")) {
noop(); noop(outputStream);
} else if (commandName.equals("SELECT")) { } else if (commandName.equals("SELECT")) {
select(currentLine); select(outputStream, currentLine);
} else if (commandName.equals("EXAMINE")) { } else if (commandName.equals("EXAMINE")) {
examine(currentLine); examine(outputStream, currentLine);
} else if (commandName.equals("LIST")) { } else if (commandName.equals("LIST")) {
list(currentLine); list(outputStream, currentLine);
} else if (commandName.equals("IDLE")) { } else if (commandName.equals("IDLE")) {
idle(); idle(inputStream, outputStream);
} else if (commandName.equals("FETCH")) { } else if (commandName.equals("FETCH")) {
fetch(currentLine); fetch(outputStream, currentLine);
} else if (commandName.equals("STORE")) { } else if (commandName.equals("STORE")) {
store(currentLine); store(outputStream, currentLine);
} else if (commandName.equals("SEARCH")) { } else if (commandName.equals("SEARCH")) {
search(currentLine); search(outputStream, currentLine);
} else if (commandName.equals("APPEND")) { } else if (commandName.equals("APPEND")) {
append(currentLine); append(inputStream, outputStream, currentLine);
} else if (commandName.equals("CLOSE")) { } else if (commandName.equals("CLOSE")) {
close(); close(outputStream);
} else if (commandName.equals("LOGOUT")) { } else if (commandName.equals("LOGOUT")) {
logout(); logout(outputStream);
} else if (commandName.equals("UID")) { } else if (commandName.equals("UID")) {
String subcommandName = ct.nextToken().toUpperCase(); String subcommandName = ct.nextToken().toUpperCase();
if (subcommandName.equals("FETCH")) { if (subcommandName.equals("FETCH")) {
uidfetch(currentLine); uidfetch(outputStream, currentLine);
} else if (subcommandName.equals("STORE")) { } else if (subcommandName.equals("STORE")) {
uidstore(currentLine); uidstore(outputStream, currentLine);
} else { } else {
LOGGER.log(Level.SEVERE, "ERROR UID command unknown: {0}", logger.log(Level.SEVERE, "ERROR UID command unknown: {0}", subcommandName);
subcommandName); bad(outputStream, "unknown UID command");
bad("unknown UID command");
} }
} else if (commandName.equals("ID")) { } else if (commandName.equals("ID")) {
id(currentLine); id(outputStream, currentLine);
} else if (commandName.equals("ENABLE")) { } else if (commandName.equals("ENABLE")) {
enable(currentLine); enable(outputStream, currentLine);
} else if (commandName.equals("CREATE")) { } else if (commandName.equals("CREATE")) {
create(currentLine); create(outputStream, currentLine);
} else if (commandName.equals("DELETE")) { } else if (commandName.equals("DELETE")) {
delete(currentLine); delete(outputStream, currentLine);
} else if (commandName.equals("STATUS")) { } else if (commandName.equals("STATUS")) {
status(currentLine); status(outputStream, currentLine);
} else if (commandName.equals("NAMESPACE")) { } else if (commandName.equals("NAMESPACE")) {
namespace(); namespace(outputStream);
} else { } else {
LOGGER.log(Level.SEVERE, "ERROR command unknown: {0}", logger.log(Level.SEVERE, "ERROR command unknown: {0}",
escape(currentLine)); escape(currentLine));
bad("unknown command"); bad(outputStream, "unknown command");
} }
} }
@ -277,8 +271,8 @@ public class IMAPHandler extends ProtocolHandler {
* *
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void login() throws IOException { public void login(OutputStream outputStream) throws IOException {
ok("[CAPABILITY " + capabilities + "]"); ok(outputStream, "[CAPABILITY " + capabilities + "]");
} }
/** /**
@ -286,13 +280,13 @@ public class IMAPHandler extends ProtocolHandler {
* *
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void authenticate(String mech, String ir) throws IOException { public void authenticate(InputStream inputStream, OutputStream outputStream, String mech, String ir) throws IOException {
if (mech.equals("LOGIN")) if (mech.equals("LOGIN"))
authlogin(ir); authlogin(inputStream, outputStream, ir);
else if (mech.equals("PLAIN")) else if (mech.equals("PLAIN"))
authplain(ir); authplain(inputStream, outputStream, ir);
else else
bad("AUTHENTICATE not supported"); bad(outputStream, "AUTHENTICATE not supported");
} }
/** /**
@ -300,14 +294,14 @@ public class IMAPHandler extends ProtocolHandler {
* *
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void authlogin(String ir) throws IOException { 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 username = readLine(); String username = readLine(inputStream);
cont(base64encode("Password")); cont(outputStream, base64encode("Password"));
String password = readLine(); String password = readLine(inputStream);
ok("[CAPABILITY " + capabilities + "]"); ok(outputStream, "[CAPABILITY " + capabilities + "]");
} }
/** /**
@ -315,12 +309,12 @@ public class IMAPHandler extends ProtocolHandler {
* *
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
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("[CAPABILITY " + capabilities + "]"); ok(outputStream, "[CAPABILITY " + capabilities + "]");
} }
/** /**
@ -328,9 +322,9 @@ public class IMAPHandler extends ProtocolHandler {
* *
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void capability() throws IOException { public void capability(OutputStream outputStream) throws IOException {
untagged("CAPABILITY " + capabilities); untagged(outputStream, "CAPABILITY " + capabilities);
ok(); ok(outputStream);
} }
/** /**
@ -338,10 +332,10 @@ public class IMAPHandler extends ProtocolHandler {
* *
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void select(String line) throws IOException { public void select(OutputStream outputStream, String line) throws IOException {
untagged(numberOfMessages + " EXISTS"); untagged(outputStream, numberOfMessages + " EXISTS");
untagged(numberOfRecentMessages + " RECENT"); untagged(outputStream, numberOfRecentMessages + " RECENT");
ok(); ok(outputStream);
} }
/** /**
@ -349,10 +343,10 @@ public class IMAPHandler extends ProtocolHandler {
* *
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void examine(String line) throws IOException { public void examine(OutputStream outputStream, String line) throws IOException {
untagged(numberOfMessages + " EXISTS"); untagged(outputStream, numberOfMessages + " EXISTS");
untagged(numberOfRecentMessages + " RECENT"); untagged(outputStream, numberOfRecentMessages + " RECENT");
ok(); ok(outputStream);
} }
/** /**
@ -360,8 +354,8 @@ public class IMAPHandler extends ProtocolHandler {
* *
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void list(String line) throws IOException { public void list(OutputStream outputStream, String line) throws IOException {
ok(); ok(outputStream);
} }
/** /**
@ -369,29 +363,27 @@ public class IMAPHandler extends ProtocolHandler {
* *
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void idle() throws IOException { public void idle(InputStream inputStream, OutputStream outputStream) throws IOException {
cont(); cont(outputStream);
idleWait(); idleWait(inputStream, outputStream);
ok(); ok(outputStream);
} }
@Override @Override
protected String readLine() throws IOException { protected String readLine(InputStream inputStream) throws IOException {
currentLine = super.readLine(); currentLine = super.readLine(inputStream);
if (currentLine == null) { if (currentLine == null) {
LOGGER.severe("Current line is null!"); logger.severe("Current line is null!");
exit(); exit();
} }
return currentLine; return currentLine;
} }
protected void idleWait() throws IOException { protected void idleWait(InputStream inputStream, OutputStream outputStream) throws IOException {
String line = readLine(); String line = readLine(inputStream);
if (line != null && !line.equalsIgnoreCase("DONE")) { if (line != null && !line.equalsIgnoreCase("DONE")) {
LOGGER.severe("Didn't get DONE response to IDLE"); logger.severe("Didn't get DONE response to IDLE");
exit(); exit();
return;
} }
} }
@ -400,8 +392,8 @@ public class IMAPHandler extends ProtocolHandler {
* *
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void fetch(String line) throws IOException { public void fetch(OutputStream outputStream, String line) throws IOException {
ok(); // XXX ok(outputStream);
} }
/** /**
@ -409,8 +401,8 @@ public class IMAPHandler extends ProtocolHandler {
* *
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void store(String line) throws IOException { public void store(OutputStream outputStream, String line) throws IOException {
ok(); // XXX ok(outputStream);
} }
/** /**
@ -418,9 +410,9 @@ public class IMAPHandler extends ProtocolHandler {
* *
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void search(String line) throws IOException { public void search(OutputStream outputStream, String line) throws IOException {
untagged("SEARCH"); untagged(outputStream, "SEARCH");
ok(); // XXX ok(outputStream);
} }
/** /**
@ -428,8 +420,8 @@ public class IMAPHandler extends ProtocolHandler {
* *
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void uidfetch(String line) throws IOException { public void uidfetch(OutputStream outputStream, String line) throws IOException {
ok(); // XXX ok(outputStream);
} }
/** /**
@ -437,8 +429,8 @@ public class IMAPHandler extends ProtocolHandler {
* *
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void uidstore(String line) throws IOException { public void uidstore(OutputStream outputStream, String line) throws IOException {
ok(); // XXX ok(outputStream);
} }
/** /**
@ -446,13 +438,13 @@ public class IMAPHandler extends ProtocolHandler {
* *
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void append(String line) throws IOException { public void append(InputStream inputStream, OutputStream outputStream, String line) throws IOException {
int left = line.lastIndexOf('{'); int left = line.lastIndexOf('{');
int right = line.indexOf('}', left); int right = line.indexOf('}', left);
int bytes = Integer.parseInt(line.substring(left + 1, right)); int bytes = Integer.parseInt(line.substring(left + 1, right));
cont("waiting for message"); cont(outputStream, "waiting for message");
collectMessage(bytes); collectMessage(inputStream, outputStream, bytes);
ok(); // XXX ok(outputStream);
} }
/** /**
@ -460,9 +452,9 @@ public class IMAPHandler extends ProtocolHandler {
* *
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void id(String line) throws IOException { public void id(OutputStream outputStream, String line) throws IOException {
untagged("ID NIL"); untagged(outputStream, "ID NIL");
ok(); ok(outputStream);
} }
/** /**
@ -470,8 +462,8 @@ public class IMAPHandler extends ProtocolHandler {
* *
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void enable(String line) throws IOException { public void enable(OutputStream outputStream, String line) throws IOException {
no("can't enable"); no(outputStream, "can't enable");
} }
/** /**
@ -479,8 +471,8 @@ public class IMAPHandler extends ProtocolHandler {
* *
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void create(String line) throws IOException { public void create(OutputStream outputStream, String line) throws IOException {
no("can't create"); no(outputStream, "can't create");
} }
/** /**
@ -488,8 +480,8 @@ public class IMAPHandler extends ProtocolHandler {
* *
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void delete(String line) throws IOException { public void delete(OutputStream outputStream, String line) throws IOException {
no("can't delete"); no(outputStream, "can't delete");
} }
/** /**
@ -497,8 +489,8 @@ public class IMAPHandler extends ProtocolHandler {
* *
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void status(String line) throws IOException { public void status(OutputStream outputStream, String line) throws IOException {
no("can't get status"); no(outputStream, "can't get status");
} }
/** /**
@ -506,23 +498,23 @@ public class IMAPHandler extends ProtocolHandler {
* *
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void namespace() throws IOException { public void namespace(OutputStream outputStream) throws IOException {
no("no namespaces"); no(outputStream, "no namespaces");
} }
/** /**
* Collect "bytes" worth of data for the message being appended. * Collect "bytes" worth of data for the message being appended.
*/ */
protected void collectMessage(int bytes) throws IOException { protected void collectMessage(InputStream inputStream, OutputStream outputStream, int bytes) throws IOException {
readLiteral(bytes); // read the data and throw it away readLiteral(inputStream, outputStream, bytes); // read the data and throw it away
super.readLine(); // data followed by a newline super.readLine(inputStream); // data followed by a newline
} }
/** /**
* Read a literal of "bytes" bytes and return it as a UTF-8 string. * Read a literal of "bytes" bytes and return it as a UTF-8 string.
*/ */
protected String readLiteral(int bytes) throws IOException { protected String readLiteral(InputStream inputStream, OutputStream outputStream, int bytes) throws IOException {
println("+"); println(outputStream, "+");
byte[] data = new byte[bytes]; byte[] data = new byte[bytes];
int len = data.length; int len = data.length;
int off = 0; int off = 0;
@ -539,8 +531,8 @@ public class IMAPHandler extends ProtocolHandler {
* *
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void close() throws IOException { public void close(OutputStream outputStream) throws IOException {
ok(); ok(outputStream);
} }
/** /**
@ -548,8 +540,8 @@ public class IMAPHandler extends ProtocolHandler {
* *
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void noop() throws IOException { public void noop(OutputStream outputStream) throws IOException {
ok(); ok(outputStream);
} }
/** /**
@ -557,8 +549,8 @@ public class IMAPHandler extends ProtocolHandler {
* *
* @throws IOException unable to read/write to socket * @throws IOException unable to read/write to socket
*/ */
public void logout() throws IOException { public void logout(OutputStream outputStream) throws IOException {
ok(); ok(outputStream);
exit(); exit();
} }

View file

@ -23,6 +23,7 @@ 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.OutputStream;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.StringTokenizer; import java.util.StringTokenizer;
@ -79,13 +80,13 @@ public final class IMAPIDTest {
private static final class IMAPHandlerID extends IMAPHandler { private static final class IMAPHandlerID extends IMAPHandler {
@Override @Override
public void id(String line) throws IOException { public void id(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 cmd = st.nextToken(); String cmd = st.nextToken();
String arg = st.nextToken(); String arg = st.nextToken();
untagged("ID (\"test\" \"" + arg.equals("NIL") + "\")"); untagged(outputStream, "ID (\"test\" \"" + arg.equals("NIL") + "\")");
ok(); ok(outputStream);
} }
} }
} }

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.OutputStream;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
@ -347,9 +348,9 @@ public final class IMAPIdleManagerTest {
*/ */
private static abstract class IMAPHandlerIdle extends IMAPHandler { private static abstract class IMAPHandlerIdle extends IMAPHandler {
@Override @Override
public void select(String line) throws IOException { public void select(OutputStream outputStream, String line) throws IOException {
numberOfMessages = 1; numberOfMessages = 1;
super.select(line); super.select(outputStream, line);
} }
public abstract void waitForIdle() throws InterruptedException; public abstract void waitForIdle() throws InterruptedException;

View file

@ -57,11 +57,11 @@ public class IMAPSaslHandler extends IMAPHandler {
CallbackHandler cbh = new CallbackHandler() { CallbackHandler cbh = new CallbackHandler() {
@Override @Override
public void handle(Callback[] callbacks) { public void handle(Callback[] callbacks) {
if (LOGGER.isLoggable(Level.FINE)) if (logger.isLoggable(Level.FINE))
LOGGER.fine("SASL callback length: " + callbacks.length); logger.fine("SASL callback length: " + callbacks.length);
for (int i = 0; i < callbacks.length; i++) { for (int i = 0; i < callbacks.length; i++) {
if (LOGGER.isLoggable(Level.FINE)) if (logger.isLoggable(Level.FINE))
LOGGER.fine("SASL callback " + i + ": " + callbacks[i]); logger.fine("SASL callback " + i + ": " + callbacks[i]);
if (callbacks[i] instanceof NameCallback) { if (callbacks[i] instanceof NameCallback) {
NameCallback ncb = (NameCallback) callbacks[i]; NameCallback ncb = (NameCallback) callbacks[i];
ncb.setName(u); ncb.setName(u);
@ -70,8 +70,8 @@ public class IMAPSaslHandler extends IMAPHandler {
pcb.setPassword(p.toCharArray()); pcb.setPassword(p.toCharArray());
} else if (callbacks[i] instanceof AuthorizeCallback) { } else if (callbacks[i] instanceof AuthorizeCallback) {
AuthorizeCallback ac = (AuthorizeCallback) callbacks[i]; AuthorizeCallback ac = (AuthorizeCallback) callbacks[i];
if (LOGGER.isLoggable(Level.FINE)) if (logger.isLoggable(Level.FINE))
LOGGER.fine("SASL authorize: " + logger.fine("SASL authorize: " +
"authn: " + ac.getAuthenticationID() + ", " + "authn: " + ac.getAuthenticationID() + ", " +
"authz: " + ac.getAuthorizationID() + ", " + "authz: " + ac.getAuthorizationID() + ", " +
"authorized: " + ac.getAuthorizedID()); "authorized: " + ac.getAuthorizedID());
@ -104,17 +104,17 @@ public class IMAPSaslHandler extends IMAPHandler {
try { try {
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("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("No SASL support");
return; return;
} }
if (LOGGER.isLoggable(Level.FINE)) if (logger.isLoggable(Level.FINE))
LOGGER.fine("SASL server " + ss.getMechanismName()); logger.fine("SASL server " + ss.getMechanismName());
byte[] response = new byte[0]; byte[] response = new byte[0];
while (!ss.isComplete()) { while (!ss.isComplete()) {
@ -124,8 +124,8 @@ public class IMAPSaslHandler extends IMAPHandler {
break; break;
} else { } else {
// send challenge // send challenge
if (LOGGER.isLoggable(Level.FINE)) if (logger.isLoggable(Level.FINE))
LOGGER.fine("SASL challenge: " + logger.fine("SASL challenge: " +
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)
@ -148,7 +148,7 @@ 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("SASL Mechanism requires integrity or confidentiality"); no("SASL Mechanism requires integrity or confidentiality");
return; return;

View file

@ -118,7 +118,7 @@ public class POP3Handler extends ProtocolHandler {
final String commandName = st.nextToken().toUpperCase(); final String commandName = st.nextToken().toUpperCase();
final String arg = st.hasMoreTokens() ? st.nextToken() : null; final String arg = st.hasMoreTokens() ? st.nextToken() : null;
if (commandName == null) { if (commandName == null) {
LOGGER.severe("Command name is empty!"); logger.severe("Command name is empty!");
this.exit(); this.exit();
return; return;
} }
@ -150,7 +150,7 @@ public class POP3Handler extends ProtocolHandler {
} else if (commandName.equals("AUTH")) { } else if (commandName.equals("AUTH")) {
this.auth(); this.auth();
} else { } else {
LOGGER.log(Level.SEVERE, "ERROR command unknown: {0}", commandName); logger.log(Level.SEVERE, "ERROR command unknown: {0}", commandName);
this.println("-ERR unknown command"); this.println("-ERR unknown command");
} }
} }

View file

@ -94,7 +94,7 @@ public class SMTPHandler extends ProtocolHandler {
final StringTokenizer st = new StringTokenizer(currentLine, " "); final StringTokenizer st = new StringTokenizer(currentLine, " ");
final String commandName = st.nextToken().toUpperCase(); final String commandName = st.nextToken().toUpperCase();
if (commandName == null) { if (commandName == null) {
LOGGER.severe("Command name is empty!"); logger.severe("Command name is empty!");
exit(); exit();
return; return;
} }
@ -120,7 +120,7 @@ public class SMTPHandler extends ProtocolHandler {
} else if (commandName.equals("AUTH")) { } else if (commandName.equals("AUTH")) {
auth(currentLine); auth(currentLine);
} else { } else {
LOGGER.log(Level.SEVERE, "ERROR command unknown: {0}", commandName); logger.log(Level.SEVERE, "ERROR command unknown: {0}", commandName);
println("-ERR unknown command"); println("-ERR unknown command");
} }
} }

View file

@ -58,8 +58,8 @@ public class SMTPLoginHandler extends SMTPHandler {
if (ct.hasMoreTokens()) if (ct.hasMoreTokens())
ir = ct.nextToken(); ir = ct.nextToken();
if (LOGGER.isLoggable(Level.FINE)) if (logger.isLoggable(Level.FINE))
LOGGER.fine(line); logger.fine(line);
if (mech.equalsIgnoreCase("PLAIN")) if (mech.equalsIgnoreCase("PLAIN"))
plain(ir); plain(ir);
else if (mech.equalsIgnoreCase("LOGIN")) else if (mech.equalsIgnoreCase("LOGIN"))
@ -82,8 +82,8 @@ public class SMTPLoginHandler extends SMTPHandler {
byte[] response = resp.getBytes(StandardCharsets.US_ASCII); byte[] response = resp.getBytes(StandardCharsets.US_ASCII);
response = Base64.getDecoder().decode(response); response = Base64.getDecoder().decode(response);
String u = new String(response, StandardCharsets.UTF_8); String u = new String(response, StandardCharsets.UTF_8);
if (LOGGER.isLoggable(Level.FINE)) if (logger.isLoggable(Level.FINE))
LOGGER.fine("USER: " + u); logger.fine("USER: " + u);
println("334"); println("334");
// read password // read password
@ -95,8 +95,8 @@ public class SMTPLoginHandler extends SMTPHandler {
response = resp.getBytes(StandardCharsets.US_ASCII); response = resp.getBytes(StandardCharsets.US_ASCII);
response = Base64.getDecoder().decode(response); response = Base64.getDecoder().decode(response);
String p = new String(response, StandardCharsets.UTF_8); String p = new String(response, StandardCharsets.UTF_8);
if (LOGGER.isLoggable(Level.FINE)) if (logger.isLoggable(Level.FINE))
LOGGER.fine("PASSWORD: " + p); logger.fine("PASSWORD: " + p);
//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)) {

View file

@ -72,11 +72,11 @@ public class SMTPSaslHandler extends SMTPHandler {
CallbackHandler cbh = new CallbackHandler() { CallbackHandler cbh = new CallbackHandler() {
@Override @Override
public void handle(Callback[] callbacks) { public void handle(Callback[] callbacks) {
if (LOGGER.isLoggable(Level.FINE)) if (logger.isLoggable(Level.FINE))
LOGGER.fine("SASL callback length: " + callbacks.length); logger.fine("SASL callback length: " + callbacks.length);
for (int i = 0; i < callbacks.length; i++) { for (int i = 0; i < callbacks.length; i++) {
if (LOGGER.isLoggable(Level.FINE)) if (logger.isLoggable(Level.FINE))
LOGGER.fine("SASL callback " + i + ": " + callbacks[i]); logger.fine("SASL callback " + i + ": " + callbacks[i]);
if (callbacks[i] instanceof NameCallback) { if (callbacks[i] instanceof NameCallback) {
NameCallback ncb = (NameCallback) callbacks[i]; NameCallback ncb = (NameCallback) callbacks[i];
ncb.setName(u); ncb.setName(u);
@ -85,8 +85,8 @@ public class SMTPSaslHandler extends SMTPHandler {
pcb.setPassword(p.toCharArray()); pcb.setPassword(p.toCharArray());
} else if (callbacks[i] instanceof AuthorizeCallback) { } else if (callbacks[i] instanceof AuthorizeCallback) {
AuthorizeCallback ac = (AuthorizeCallback) callbacks[i]; AuthorizeCallback ac = (AuthorizeCallback) callbacks[i];
if (LOGGER.isLoggable(Level.FINE)) if (logger.isLoggable(Level.FINE))
LOGGER.fine("SASL authorize: " + logger.fine("SASL authorize: " +
"authn: " + ac.getAuthenticationID() + ", " + "authn: " + ac.getAuthenticationID() + ", " +
"authz: " + ac.getAuthorizationID() + ", " + "authz: " + ac.getAuthorizationID() + ", " +
"authorized: " + ac.getAuthorizedID()); "authorized: " + ac.getAuthorizedID());
@ -119,25 +119,25 @@ public class SMTPSaslHandler extends SMTPHandler {
try { try {
ss = Sasl.createSaslServer(mech, "smtp", "localhost", null, cbh); ss = Sasl.createSaslServer(mech, "smtp", "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);
println("501 Failed to create SASL server"); println("501 Failed to create SASL server");
return; return;
} }
if (ss == null) { if (ss == null) {
LOGGER.fine("No SASL support"); logger.fine("No SASL support");
println("501 No SASL support"); println("501 No SASL support");
return; return;
} }
if (LOGGER.isLoggable(Level.FINE)) if (logger.isLoggable(Level.FINE))
LOGGER.fine("SASL server " + ss.getMechanismName()); logger.fine("SASL server " + ss.getMechanismName());
byte[] response = ir.getBytes(); byte[] response = ir.getBytes();
while (!ss.isComplete()) { while (!ss.isComplete()) {
try { try {
byte[] chal = ss.evaluateResponse(response); byte[] chal = ss.evaluateResponse(response);
// send challenge // send challenge
if (LOGGER.isLoggable(Level.FINE)) if (logger.isLoggable(Level.FINE))
LOGGER.fine("SASL challenge: " + logger.fine("SASL challenge: " +
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)
@ -164,7 +164,7 @@ public class SMTPSaslHandler extends SMTPHandler {
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");
println("501 " + println("501 " +
"SASL Mechanism requires integrity or confidentiality"); "SASL Mechanism requires integrity or confidentiality");

View file

@ -16,12 +16,9 @@
package org.xbib.net.mail.test.test; package org.xbib.net.mail.test.test;
import java.io.BufferedInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.PushbackInputStream; import java.io.PushbackInputStream;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.logging.Level; import java.util.logging.Level;
@ -35,64 +32,82 @@ import java.util.logging.Logger;
* @author sbo * @author sbo
* @author Bill Shannon * @author Bill Shannon
*/ */
public abstract class ProtocolHandler implements Runnable { public abstract class ProtocolHandler {
/** /**
* Logger for this class. * Logger for this class.
*/ */
protected final Logger LOGGER = Logger.getLogger(this.getClass().getName()); private static final Logger logger = Logger.getLogger(ProtocolHandler.class.getName());
/** /**
* Quit? * Quit?
*/ */
protected boolean quit; protected boolean quit;
/** public void handle(InputStream inputStream, OutputStream outputStream) {
* Writer to socket. try {
*/ sendGreetings(outputStream);
protected PrintWriter writer; while (!quit) {
handleCommand(inputStream, outputStream);
/** }
* Input from socket. if (quit) {
*/ try {
protected InputStream inputStream; if (inputStream != null)
inputStream.close();
public ProtocolHandler(InputStream inputStream, OutputStream outputStream) { if (outputStream != null) {
this.inputStream = new BufferedInputStream(inputStream); outputStream.close();
this.writer = new PrintWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)); }
} catch (final IOException e) {
logger.log(Level.SEVERE, "Error", e);
}
}
} catch (IOException sex) {
// ignore it, often get "connection reset" when client closes
} catch (Exception e) {
logger.log(Level.SEVERE, "Error", e);
} finally {
try {
if (inputStream != null)
inputStream.close();
if (outputStream != null) {
outputStream.close();
}
} catch (final IOException ioe) {
logger.log(Level.SEVERE, "Error", ioe);
}
}
} }
/** /**
* Optionally send a greeting when first connected. * Optionally send a greeting when first connected.
*/ */
public void sendGreetings() throws IOException { public void sendGreetings(OutputStream outputStream) throws IOException {
} }
/** /**
* Read and process a single command. * Read and process a single command.
*/ */
public abstract void handleCommand() throws IOException; public abstract void handleCommand(InputStream inputStream, OutputStream outputStream) throws IOException;
/** /**
* Read a single line terminated by newline or CRLF. * Read a single line terminated by newline or CRLF.
* Convert the UTF-8 bytes in the line (minus the line terminator) * Convert the UTF-8 bytes in the line (minus the line terminator)
* to a String. * to a String.
*/ */
protected String readLine() throws IOException { protected String readLine(InputStream inputStream) throws IOException {
byte[] buf = new byte[128]; byte[] buf = new byte[128];
int room = buf.length; int room = buf.length;
int offset = 0; int offset = 0;
int c; int c;
while ((c = inputStream.read()) != -1) { while ((c = inputStream.read()) != -1) {
if (c == '\n') { if (c == '\n') {
break; break;
} else if (c == '\r') { } else if (c == '\r') {
int c2 = inputStream.read(); int c2 = inputStream.read();
if ((c2 != '\n') && (c2 != -1)) { if ((c2 != '\n') && (c2 != -1)) {
if (!(inputStream instanceof PushbackInputStream)) if (!(inputStream instanceof PushbackInputStream)) {
this.inputStream = new PushbackInputStream(inputStream); inputStream = new PushbackInputStream(inputStream);
}
((PushbackInputStream) inputStream).unread(c2); ((PushbackInputStream) inputStream).unread(c2);
} }
break; break;
@ -106,51 +121,13 @@ public abstract class ProtocolHandler implements Runnable {
buf[offset++] = (byte) c; buf[offset++] = (byte) c;
} }
} }
if ((c == -1) && (offset == 0)) if ((c == -1) && (offset == 0)) {
return null; return null;
}
return new String(buf, 0, offset, StandardCharsets.UTF_8); return new String(buf, 0, offset, StandardCharsets.UTF_8);
} }
/**
* {@inheritDoc}
*/
@Override
public final void run() {
try {
sendGreetings();
while (!quit) {
handleCommand();
}
} catch (IOException sex) {
// ignore it, often get "connection reset" when client closes
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "Error", e);
} finally {
try {
if (inputStream != null)
inputStream.close();
if (writer != null) {
writer.close();
}
} catch (final IOException ioe) {
LOGGER.log(Level.SEVERE, "Error", ioe);
}
}
}
/**
* Quit.
*/
public void exit() { public void exit() {
quit = true; quit = true;
try {
if (inputStream != null)
inputStream.close();
if (writer != null) {
writer.close();
}
} catch (final IOException e) {
LOGGER.log(Level.SEVERE, "Error", e);
}
} }
} }

View file

@ -16,6 +16,9 @@
package org.xbib.net.mail.test.test; package org.xbib.net.mail.test.test;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.KeyManagementException; import java.security.KeyManagementException;
import java.security.KeyStoreException; import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
@ -32,8 +35,11 @@ import java.net.InetSocketAddress;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import java.security.KeyStore; import java.security.KeyStore;
import java.util.ArrayList; import java.util.concurrent.Callable;
import java.util.List; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* A simple server for testing. * A simple server for testing.
@ -46,13 +52,17 @@ import java.util.List;
* @author sbo * @author sbo
* @author Bill Shannon * @author Bill Shannon
*/ */
public final class TestServer extends Thread { public final class TestServer {
private static final Logger logger = Logger.getLogger(TestServer.class.getName());
/** /**
* Server socket. * Server socket.
*/ */
private ServerSocket serverSocket; private ServerSocket serverSocket;
private final ExecutorService executorService = Executors.newCachedThreadPool();
/** /**
* Keep on? * Keep on?
*/ */
@ -63,7 +73,6 @@ public final class TestServer extends Thread {
*/ */
private final ProtocolHandler handler; private final ProtocolHandler handler;
private List<Thread> clients = new ArrayList<Thread>();
/** /**
* Test server. * Test server.
@ -83,7 +92,6 @@ public final class TestServer extends Thread {
public TestServer(final ProtocolHandler handler, final boolean isSSL) public TestServer(final ProtocolHandler handler, final boolean isSSL)
throws IOException { throws IOException {
this.handler = handler; this.handler = handler;
/* /*
* Allowing the JDK to pick a port number sometimes results in it * Allowing the JDK to pick a port number sometimes results in it
* picking a number that's already in use by another process, but * picking a number that's already in use by another process, but
@ -96,10 +104,6 @@ public final class TestServer extends Thread {
* already in use. * already in use.
*/ */
for (int port = 49152; port < 50000 /*65535*/; port++) { for (int port = 49152; port < 50000 /*65535*/; port++) {
/*
if (isListening(port))
continue;
*/
try { try {
serverSocket = createServerSocket(port, isSSL); serverSocket = createServerSocket(port, isSSL);
return; return;
@ -170,12 +174,7 @@ public final class TestServer extends Thread {
} }
} }
/**
* {@inheritDoc}
*/
@Override
public void start() { public void start() {
super.start();
// don't return until server is really listening // don't return until server is really listening
// XXX - this might not be necessary // XXX - this might not be necessary
for (int tries = 0; tries < 10; tries++) { for (int tries = 0; tries < 10; tries++) {
@ -193,25 +192,23 @@ public final class TestServer extends Thread {
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override
public void run() { public void run() {
try { try {
keepOn = true; keepOn = true;
while (keepOn) { while (keepOn) {
try { try {
final Socket clientSocket = serverSocket.accept(); final Socket clientSocket = serverSocket.accept();
final ProtocolHandler pHandler = handler; executorService.submit(new Callable<Object>() {
pHandler.setClientSocket(clientSocket); final InputStream inputStream = new BufferedInputStream(clientSocket.getInputStream());
Thread t = new Thread(pHandler); final OutputStream outputStream = clientSocket.getOutputStream();
synchronized (clients) { @Override
clients.add(t); public Object call() {
} handler.handle(inputStream, outputStream);
t.start(); return null;
} catch (final IOException e) { }
//e.printStackTrace(); });
} catch (NullPointerException nex) { } catch (Exception e) {
// serverSocket can be set to null before we could check logger.log(Level.SEVERE, e.getMessage(), e);
} }
} }
} finally { } finally {
@ -219,20 +216,14 @@ public final class TestServer extends Thread {
} }
} }
/** /*public int clientCount() {
* Return number of clients ever created.
*/
public int clientCount() {
synchronized (clients) { synchronized (clients) {
// isListening creates a client that we don't count // isListening creates a client that we don't count
return clients.size() - 1; return clients.size() - 1;
} }
} }*/
/** /*public void waitForClients(int n) {
* Wait for at least n clients to terminate.
*/
public void waitForClients(int n) {
if (n > clientCount()) if (n > clientCount())
throw new RuntimeException("not that many clients"); throw new RuntimeException("not that many clients");
for (; ; ) { for (; ; ) {
@ -250,7 +241,7 @@ public final class TestServer extends Thread {
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
} }
} }
} }*/
private boolean isListening(int port) { private boolean isListening(int port) {
try { try {
@ -265,10 +256,4 @@ public final class TestServer extends Thread {
return false; return false;
} }
class WrappedProtocolHandler {
Socket clientSocket;
ProtocolHandler handler;
}
} }