From b74e122268839b0f45126f271cd4c8118157741a Mon Sep 17 00:00:00 2001 From: adam Date: Mon, 31 May 2004 03:52:30 +0000 Subject: [PATCH] more progress darcs-hash:20040531035230-5007d-bd274b234511ff8d20884b78260a2d77f65bc6d0.gz --- src/org/ibex/mail/protocol/IMAP.java | 383 +++++++++++++++++----------------- 1 file changed, 189 insertions(+), 194 deletions(-) diff --git a/src/org/ibex/mail/protocol/IMAP.java b/src/org/ibex/mail/protocol/IMAP.java index 1d895fd..02c2cbf 100644 --- a/src/org/ibex/mail/protocol/IMAP.java +++ b/src/org/ibex/mail/protocol/IMAP.java @@ -7,8 +7,7 @@ import java.net.*; import java.text.*; import java.io.*; -// FIXME: tagged responses - +// FEATURE: hoist all the ok()'s? // FEATURE: pipelining // FEATURE: support [charset] public class IMAP extends MessageProtocol { @@ -22,7 +21,7 @@ public class IMAP extends MessageProtocol { new Thread() { public void run() { try { - service(s); + new Listener(s, "megacz.com").handleRequest(); } catch (Exception e) { e.printStackTrace(); } @@ -31,31 +30,37 @@ public class IMAP extends MessageProtocol { } } - public static class IMAPException extends MailException { public IMAPException(String s) { super(s); } } - public static class No extends IMAPException { public No(String s) { super(s); } } - public static class Bad extends IMAPException { public Bad(String s) { super(s); } } - - public static void service(Socket s) { /* FIXME */ } + public static class Exn extends MailException { + public Exn(String s) { super(s); } + public static class No extends Exn { public No(String s) { super(s); } } + public static class Bad extends Exn { public Bad(String s) { super(s); } } + } private static class Listener extends Incoming { - private InputStream is; - private PushbackReader r; - - Socket conn; - String vhost; - Mailbox selected = null; Mailbox root = null; + Socket conn; + String vhost; PrintWriter pw; - LineReader lr; - + InputStream is; + PushbackReader r; public void init() { } - public Listener(Socket conn, String vhost) { this.vhost = vhost; this.conn = conn; this.selected = null; } + public Listener(Socket conn, String vhost) throws IOException { + this.vhost = vhost; + this.conn = conn; + this.selected = null; + this.pw = new PrintWriter(new OutputStreamWriter(conn.getOutputStream())); + this.is = conn.getInputStream(); + this.r = new PushbackReader(new InputStreamReader(is)); + } - private void ok(String s) { star("OK " + s); } + // ugly: not concurrent + String tag; + private void ok(String s) { pw.println(tag + " OK " + s); } private void star(String s) { pw.println("* " + s); } - private boolean auth(String user, String pass) { /* FEATURE */ return user.equals("megacz") && pass.equals(""); } + + // FIXME should throw a No if mailbox not found and create==false private Mailbox getMailbox(String name, boolean create) { Mailbox m = root; while(name.length() > 0) { @@ -67,74 +72,68 @@ public class IMAP extends MessageProtocol { return m; } - // sharing problem? immutability helps - public void copy(int[] set, Mailbox target) { - for(int i=0; i')); - s = s.substring(0, s.indexOf('<')); - if (range.indexOf('.') == -1) end = Integer.MAX_VALUE; - else { - end = Integer.parseInt(range.substring(range.indexOf('.') + 1)); - range = range.substring(0, range.indexOf('.')); + for(int j=0; j')); + s = s.substring(0, s.indexOf('<')); + if (range.indexOf('.') == -1) end = Integer.MAX_VALUE; + else { + end = Integer.parseInt(range.substring(range.indexOf('.') + 1)); + range = range.substring(0, range.indexOf('.')); + } + start = Integer.parseInt(range); } - start = Integer.parseInt(range); + if (s.equals("ENVELOPE") || all || full) reply.append("ENVELOPE " + envelope(m) + " "); + if (s.equals("FLAGS") || full || all || fast) reply.append("FLAGS (" + flags(m) + ") "); + if (s.equals("INTERNALDATE") || full || all || fast) reply.append("INTERNALDATE "+quotify(m.arrival)+" "); + if (s.equals("RFC822.SIZE") || full || all || fast) reply.append("RFC822.SIZE " + m.rfc822size() + " "); + if (s.equals("RFC822.HEADER") || s.equals("BODY[HEADER]")) + { reply.append("BODY[HEADER] {" + m.allHeaders.length() + "}\r\n"); reply.append(m.allHeaders); } + if (s.equals("RFC822")||s.equals("RFC822.TEXT")||s.equals("BODY")||s.equals("BODY[]")||s.equals("TEXT")||full) + { reply.append("BODY[TEXT] {" + m.body.length() + "}\r\n"); reply.append(m.body); } + if (s.equals("UID")) reply.append("UID " + m.uid); + if (s.equals("MIME")) throw new Exn.No("FETCH BODY.MIME not supported"); + if (s.startsWith("BODY[HEADER.FIELDS")) throw new Exn.No("partial headers not supported"); + if (s.startsWith("BODY[HEADER.FIELDS.NOT")) throw new Exn.No("partial headers not supported"); + if (s.equals("BODYSTRUCTURE")) + reply.append("(\"TEXT\" \"PLAIN\" (\"CHARSET\" \"US-ASCII\") NIL NIL \"7BIT\" " + + m.rfc822size()+" "+ m.numLines() +")"); } - if (s.equals("ENVELOPE")) reply.append("ENVELOPE " + envelope(m) + " "); - else if (s.equals("FLAGS")) reply.append("FLAGS (" + flags(m) + ") "); - else if (s.equals("INTERNALDATE")) reply.append("INTERNALDATE " + quotify(m.arrival) + " "); - else if (s.equals("RFC822.SIZE")) reply.append("RFC822.SIZE " + m.rfc822size() + " "); - else if (s.equals("RFC822.HEADER") || s.equals("BODY[HEADER]")) - { reply.append("BODY[HEADER] {" + m.allHeaders.length() + "}\r\n"); reply.append(m.allHeaders); } - else if (s.equals("RFC822")||s.equals("RFC822.TEXT")||s.equals("BODY") || s.equals("BODY[]") || s.equals("TEXT")) - { reply.append("BODY[TEXT] {" + m.body.length() + "}\r\n"); reply.append(m.body); } - else if (s.equals("UID")) reply.append("UID " + m.uid); - else if (s.equals("MIME")) throw new No("FETCH BODY.MIME not supported"); - else if (s.startsWith("BODY[HEADER.FIELDS")) throw new No("partial headers not supported"); - else if (s.startsWith("BODY[HEADER.FIELDS.NOT")) throw new No("partial headers not supported"); - else if (s.equals("BODYSTRUCTURE")) - reply.append("(\"TEXT\" \"PLAIN\" (\"CHARSET\" \"US-ASCII\") NIL NIL \"7BIT\" " + - m.rfc822size()+" "+ m.numLines() +")"); - else if (s.startsWith("BODY")) throw new No("FETCH BODY[*] not supported"); - else throw new Bad("unrecognized FETCH argument \"" + s + "\""); + star(m.messageNum + " FETCH (" + reply.toString() + ")"); + // FEATURE set seen flag if not BODY.PEEK } - star(m.messageNum + " FETCH (" + reply.toString() + ")"); - // FEATURE set seen flag if not BODY.PEEK } public void store(int[] messages, String what, Token[] flags) { @@ -229,13 +224,14 @@ public class IMAP extends MessageProtocol { } } - public boolean handleRequest(LineReader r, PrintWriter pw) throws IOException { + public boolean handleRequest() throws IOException { + LineReader lr = new LineReader(r); pw.println("* OK " + vhost + " " + IMAP.class.getName() + " IMAP4 v0.1 server ready"); while(true) { boolean uid = false; - String s = r.readLine(); + String s = lr.readLine(); if (s.indexOf(' ') == -1) { pw.println("* BAD Invalid tag"); continue; } - String tag = atom(); + tag = atom(); String command = atom(); if (command.equals("UID")) { uid = true; command = atom(); } if (command.equals("AUTHENTICATE")) { login(astring(), astring()); } @@ -246,63 +242,63 @@ public class IMAP extends MessageProtocol { else if (command.equals("LOGOUT")) { logout(); conn.close(); return false; } else if (command.equals("RENAME")) rename(mailbox(), atom()); else if (command.equals("APPEND")) append(mailbox(), token()); - //else if (command.equals("EXAMINE")) examine(mailbox()); FIXME + else if (command.equals("EXAMINE")) select(astring(), true); + else if (command.equals("SELECT")) select(astring(), false); else if (command.equals("COPY")) copy(set(), mailbox()); else if (command.equals("DELETE")) delete(mailbox()); - //else if (command.equals("CREATE")) create(mailbox()); FIXME + else if (command.equals("CHECK")) check(); + else if (command.equals("CREATE")) create(astring()); else if (command.equals("STORE")) store(set(), atom(), l()); else if (command.equals("FETCH")) fetch(set(), token()); else if (command.equals("STATUS")) status(mailbox(), l()); - else throw new Bad("unrecognized command \"" + command + "\""); + else throw new Exn.Bad("unrecognized command \"" + command + "\""); } } - static String quotify(String s){return s==null?"NIL":"\""+s.replaceAll("\\\\","\\\\").replaceAll("\"","\\\\\"")+"\"";} - static String quotify(Date d) { throw new Error("not implemented"); } - static String address(Address a) {return"("+quotify(a.description)+" NIL "+quotify(a.user)+" "+quotify(a.host)+")"; } - public static String addressList(Object a) { - if (a == null) return "NIL"; - if (a instanceof Address) return "("+address((Address)a)+")"; - Address[] aa = (Address[])a; - StringBuffer ret = new StringBuffer(); - ret.append("("); - for(int i=0; i