package org.ibex.mail.protocol;
import org.ibex.io.*;
import org.ibex.jinetd.Listener;
+import org.ibex.jinetd.Worker;
import org.ibex.net.*;
import org.ibex.mail.*;
import org.ibex.util.*;
// FEATURE: STARTTLS
// FEATURE: asynchronous client notifications (need to re-read RFC)
-public class IMAP implements Listener {
-
- public void accept(Connection c) {
- Log.error(this, "IMAP got a connection!");
- new Listener().handleRequest(c);
- c.close();
- }
+public class IMAP {
public IMAP() { }
public static final float version = (float)0.1;
public void delete(String m0) { delete(mailbox(m0,false)); }
public void delete(Mailbox m) { if (!m.equals(inbox)) m.destroy(false); else throw new Bad("can't delete inbox"); }
public void create(String m) { mailbox(m, true); }
- public void append(String m,int f,Date a,String b){mailbox(m,false).add(new Message(null,null,b,a),f|Mailbox.Flag.RECENT);}
+ public void append(String m,int f,Date a,String b) { try {
+ mailbox(m,false).add(new Message(null,null,b,a),f|Mailbox.Flag.RECENT);
+ } catch (Message.Malformed e) { throw new No(e.getMessage()); } }
public void check() { }
public void noop() { }
public void logout() { }
}
public void fetch(Query q, int spec, String[] headers, int start, int end, boolean uid) {
for(Mailbox.Iterator it = selected().iterator(q); it.next(); ) {
- client.fetch(it.num(), it.flags(), it.cur().size(), it.cur(), it.uid());
+ Message message = ((spec & (BODYSTRUCTURE | ENVELOPE | INTERNALDATE | FIELDS | FIELDSNOT | RFC822 |
+ RFC822TEXT | RFC822SIZE | HEADERNOT | HEADER)) != 0) ? it.cur() : null;
+ int size = message == null ? 0 : message.size();
+ client.fetch(it.num(), it.flags(), size, message, it.uid());
it.recent(false);
}
}
void newline() { parser.newline(); }
Query query() { return parser.query(); }
public void handleRequest(Connection conn) {
- parser = new Parser(conn);
this.conn = conn;
+ parser = new Parser(conn);
api = new IMAP.MailboxWrapper(new Main.BogusAuthenticator(), this);
conn.setTimeout(30 * 60 * 1000);
println("* OK " + conn.vhost + " " + IMAP.class.getName() + " IMAP4rev1 [RFC3501] v" + version + " server ready");
for(String tag = null;; newline()) try {
- conn.out.flush();
+ conn.flush();
boolean uid = false;
tag = null; Parser.Token tok = token(); if (tok == null) return; tag = tok.astring();
String command = token().atom();
}
println(tag+" OK "+command+" Completed. " +
(commandKey == LOGIN ? ("[CAPABILITY "+Printer.join(" ", api.capability())+"]") : ""));
- } catch (Server.Bad b) { println(tag==null ? "* BAD Invalid tag":(tag + " Bad " + b.toString())); b.printStackTrace();
- } catch (Server.No n) { println(tag==null?"* BAD Invalid tag":(tag+" No " + n.toString())); n.printStackTrace(); }
+ } catch (Server.Bad b) { println(tag==null ? "* BAD Invalid tag":(tag + " Bad " + b.toString())); Log.warn(this,b);
+ } catch (Server.No n) { println(tag==null?"* BAD Invalid tag":(tag+" No " + n.toString())); Log.warn(this,n); }
}
private Parser.Token[] lastfetch = null; // hack
private void fetch(Object o, Parser.Token[] t, int num, int flags, int size, boolean uid, int muid) {
Query q = o instanceof Query ? (Query)o : null;
Message m = o instanceof Message ? (Message)o : null;
- boolean e = m != null;
+ boolean e = q == null;
lastfetch = t;
int spec = 0; // spec; see constants for flags
private static final int SEARCH = 25; static { commands.put("SEARCH", new Integer(SEARCH)); }
}
- public static class Parser extends Stream.In {
+ public static class Parser {
private Stream stream;
- public Parser(Stream from) { super(from.in); this.stream = from; }
- public char peekc() { int i = read(); unread(((char)i)+""); return (char)i; }
- public char getc() { return (char)read(); }
+ public Parser(Stream from) { this.stream = from; }
public Token token(String s) { return new Token(s); }
protected Query query() {
String s = null;
}
public void newline() {
- while (peekc() == '\r' || peekc() == '\n' || peekc() == ' ') {
- for(char c = peekc(); c == ' ';) { getc(); c = peekc(); };
- for(char c = peekc(); c == '\r' || c == '\n';) { getc(); c = peekc(); };
+ while (stream.peekc() == '\r' || stream.peekc() == '\n' || stream.peekc() == ' ') {
+ for(char c = stream.peekc(); c == ' ';) { stream.getc(); c = stream.peekc(); };
+ for(char c = stream.peekc(); c == '\r' || c == '\n';) { stream.getc(); c = stream.peekc(); };
}
}
public Token token(boolean freak) {
Vec toks = new Vec();
StringBuffer sb = new StringBuffer();
- char c = getc(); while (c == ' ') c = getc();
+ char c = stream.getc(); while (c == ' ') c = stream.getc();
if (c == '\r' || c == '\n') { if (freak) bad("unexpected end of line"); return null; }
else if (c == '{') {
- while(peekc() != '}') sb.append(getc());
- stream.out.println("+ Ready when you are...");
+ while(stream.peekc() != '}') sb.append(stream.getc());
+ stream.println("+ Ready when you are...");
int octets = Integer.parseInt(sb.toString());
- while(peekc() == ' ') getc(); // whitespace
- while (getc() != '\n' && getc() != '\r') { }
+ while(stream.peekc() == ' ') stream.getc(); // whitespace
+ while (stream.getc() != '\n' && stream.getc() != '\r') { }
byte[] bytes = new byte[octets];
- read(bytes, 0, bytes.length);
+ stream.read(bytes, 0, bytes.length);
return new Token(new String(bytes), true);
} else if (c == '\"') {
while(true) {
- c = getc();
- if (c == '\\') sb.append(getc());
+ c = stream.getc();
+ if (c == '\\') sb.append(stream.getc());
else if (c == '\"') break;
else sb.append(c);
}
} else while(true) {
sb.append(c);
- c = peekc();
+ c = stream.peekc();
if (c == ' ' || c == '\"' || c == '(' || c == ')' || c == '[' || c == ']' ||
c == '{' || c == '\n' || c == '\r')
return new Token(sb.toString(), false);
- getc();
+ stream.getc();
}
}
}