Pascal Peridont 19 лет назад
Родитель
Сommit
1e4ee9c7ae

+ 0 - 52
std/mtwin/mail/Tools.hx

@@ -302,56 +302,4 @@ class Tools {
 
 	}
 
-	public static function imapRangeString( r : ImapRange ) : String {
-		return switch( r ){
-			case Single(i): Std.string(i);
-			case Range(s,e): Std.string(s)+":"+Std.string(e);
-			case Composite(l):
-				var t = new List<String>();
-				for( e in l )
-					t.add(imapRangeString(e));
-				t.join(",");
-		}
-	}
-
-	public static function imapSectionString( a : Array<ImapSection> ) : String{
-		var r = new List();
-		
-		if( a == null || a.length < 1 )
-			return "";
-		
-		for( s in a ){
-			r.add( switch( s ){
-				case Flags: "FLAGS";
-				case Uid: "UID";
-				case BodyStructure: "BODYSTRUCTURE";
-				case Envelope: "ENVELOPE";
-				case InternalDate: "INTERNALDATE";
-				case Body(ss): "BODY["+imapBodySectionString(ss)+"]";
-				case BodyPeek(ss): "BODY.PEEK["+imapBodySectionString(ss)+"]";
-					
-			});
-		}
-		return "("+r.join(" ")+")";
-	}
-
-	static function imapBodySectionString( ss : ImapBodySection ){
-		if( ss == null )
-			return "";
-
-		return switch( ss ){
-			case Text: "TEXT";
-			case Header: "HEADER";
-			case Mime: "MIME";
-			case SubSection(id,nss):
-				var t = imapBodySectionString(nss);
-				if( id == null || id == "" ) 
-					t;
-				else if( t == "" )
-					id;
-				else
-					id+"."+t;
-		}
-	}
-
 }

+ 16 - 16
std/mtwin/mail/ImapBodyStructure.hx → std/mtwin/mail/imap/BodyStructure.hx

@@ -22,21 +22,21 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  * DAMAGE.
  */
-package mtwin.mail;
+package mtwin.mail.imap;
 
-class ImapBodyStructure {
-	public var ctype0: String;
-	public var ctype1: String;
-	public var params : Hash<String>;
-	public var parts: List<ImapBodyStructure>;
+class BodyStructure {
+	public var ctype0(default,null): String;
+	public var ctype1(default,null): String;
+	public var params(default,null) : Hash<String>;
+	public var parts(default,null): List<BodyStructure>;
 
 	// single-part specific
-	public var id: String;
-	public var description : String;
-	public var encoding : String;
-	public var size : Int;
-	public var disposition : String;
-	public var dispositionParams : Hash<String>;
+	public var id(default,null): String;
+	public var description(default,null) : String;
+	public var encoding(default,null) : String;
+	public var size(default,null) : Int;
+	public var disposition(default,null) : String;
+	public var dispositionParams(default,null) : Hash<String>;
 
 	//
 	public var __length : Int;
@@ -47,7 +47,7 @@ class ImapBodyStructure {
 		params = new Hash();
 	}
 
-	public function getMainPart( ?level : Int, ?priority : Int, ?cpriority : Int ) : ImapBodyStructure {
+	public function getMainPart( ?level : Int, ?priority : Int, ?cpriority : Int ) : BodyStructure {
 		if( level == null ) level = 0;
 		if( priority == null ) priority = 0;
 		if( cpriority == null ) cpriority = 0;
@@ -86,7 +86,7 @@ class ImapBodyStructure {
 		return null;
 	}
 
-	public function listAttachment( ?level : Int ) : List<ImapBodyStructure> {
+	public function listAttachment( ?level : Int ) : List<BodyStructure> {
 		if( level == null ) level = 0;
 		var ret = new List();
 		if( ctype0 != "multipart" ){
@@ -103,12 +103,12 @@ class ImapBodyStructure {
 		return ret;
 	}
 
-	public static function parse( s : String, ?id : String ) : ImapBodyStructure{
+	public static function parse( s : String, ?id : String ) : BodyStructure{
 		if( id == null ) id = "";
 		var len = s.length;
 		var parCount = 0;
 		var p = 0;
-		var ret = new ImapBodyStructure();
+		var ret = new BodyStructure();
 		ret.imapId = id;
 		var addPart = function( p ){
 			ret.parts.add( p );

+ 71 - 133
std/mtwin/mail/Imap.hx → std/mtwin/mail/imap/Connection.hx

@@ -22,65 +22,36 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  * DAMAGE.
  */
-package mtwin.mail;
+package mtwin.mail.imap;
 
 import neko.Socket;
 import mtwin.mail.Exception;
+import mtwin.mail.imap.Tools;
 
-signature ImapMailbox = {
-	name: String,
-	flags: ImapFlags,
-	hasChildren: Bool
+enum FlagMode {
+	Add;
+	Remove;
+	Replace;
 }
 
-signature ImapFetchResponse = {
+signature FetchResponse = {
 	id: Int,
 	uid: Int,
 	bodyType: String,
 	body: String,
-	flags: ImapFlags,
-	structure: ImapBodyStructure,
+	flags: Flags,
+	structure: BodyStructure,
 	internalDate: String,
-	envelope: ImapEnvelope
-}
-
-signature ImapFlags = Array<String>
-
-enum ImapSection {
-	Flags;
-	Uid;
-	BodyStructure;
-	Envelope;
-	InternalDate;
-	Body(ss:ImapBodySection);
-	BodyPeek(ss:ImapBodySection);
+	envelope: Envelope
 }
 
-enum ImapBodySection {
-	Header;
-	Mime;
-	Text;
-	SubSection(id:String,ss:ImapBodySection);
-}
-
-enum ImapRange {
-	Single(i:Int);
-	Range(s:Int,e:Int);
-	Composite(l:Array<ImapRange>);
-}
-
-enum ImapFlagMode {
-	Add;
-	Remove;
-	Replace;
-}
-
-class Imap {
+class Connection {
 	public static var DEBUG = false;
-	public static var TIMEOUT = 5;
+	public static var TIMEOUT = 25;
 
 	var cnx : Socket;
 	var count : Int;
+	var selected : String;
 
 	static var REG_RESP = ~/(OK|NO|BAD) (\[([^\]]+)\] )?(([A-Z]{2,}) )? ?(.*)/;
 	static var REG_EXISTS = ~/^([0-9]+) EXISTS$/;
@@ -154,46 +125,56 @@ class Imap {
 	/**
 		List mailboxes that match pattern (all mailboxes if pattern is null)
 	**/
-	public function mailboxes( ?pattern : String ) : List<ImapMailbox> {
-		var r;
-		if( pattern == null ){
-			r = command("LIST","\".\" \"*\"");
-		}else{
-			r = command("LIST","\".\" \""+pattern+"\"");
-		}
+	public function mailboxes( ?pattern : String ) : List<Mailbox> {
+		if( pattern == null ) pattern = "*";
+
+		var r = command("LIST",quote(".")+" "+quote(pattern));
 		if( !r.success ){
 			throw BadResponse(r.response);
 		}
 
-		var ret = new List();
+		var hash = new Hash();
 		for( v in r.result ){
 			if( REG_LIST_RESP.match(v) ){	
 				var name = REG_LIST_RESP.matched(2);
 				var flags = REG_LIST_RESP.matched(1).split(" ");
 
-				var t = {name: name,flags: flags,hasChildren: false};
-
-				for( v in flags ){
-					if( v == "\\HasNoChildren" ){
-						t.hasChildren = false;
-					}else if( v == "\\HasChildren" ){
-						t.hasChildren = true;
-					}
-				}
-
-				ret.add(t);
+				var t = Mailbox.init( this, name, flags );
+				hash.set(name,t);
 			}
 		}
+
+		var ret = new List();
+		for( t in hash ){
+			var a = t.name.split(".");
+			a.pop();
+			var p = a.join(".");
+			if( p.length > 0 && hash.exists(p) ){
+				var par = hash.get(p);
+				par.children.add( t );
+				untyped t.parent = par;
+			}else
+				ret.add( t );
+		}
+
 		return ret;
 	}
 
+	public function getMailbox( name : String ){
+		return mailboxes(name).first();
+	}
+
 	/**
 		Select a mailbox
 	**/
 	public function select( mailbox : String ){
+		if( selected == mailbox ) return null;
+
 		var r = command("SELECT",quote(mailbox));
 		if( !r.success ) 
 			throw BadResponse(r.response);
+
+		selected = mailbox;
 		
 		var ret = {recent: 0,exists: 0,firstUnseen: null};
 		for( v in r.result ){
@@ -212,7 +193,7 @@ class Imap {
 	/**
 		Search for messages. Pattern syntax described in RFC 3501, section 6.4.4
 	**/
-	public function search( ?pattern : String, ?useUid : Bool ){
+	public function search( ?pattern : String, ?useUid : Bool ) : List<Int> {
 		if( pattern == null ) pattern = "ALL";
 		if( useUid == null ) useUid = false;
 
@@ -235,46 +216,40 @@ class Imap {
 		return l;
 	}
 
-	/**
-		Search for messages, fetch those found.
-	**/
-	public function fetchSearch( pattern : String, ?section : Array<ImapSection> ) : List<ImapFetchResponse>{
-		if( section == null ) section = [BodyPeek(null)];
-		var r = search(pattern);
-		if( r.length == 0 ) return new List();
-
-		var t = new Array<ImapRange>();
-		for( i in r ){
-			t.push(Single(i));
-		}
+	public function sort( criteria : String, ?pattern : String, ?charset : String, ?useUid : Bool ){
+		if( pattern == null ) pattern = "ALL";
+		if( useUid == null ) useUid = false;
+		if( charset == null ) charset = "US-ASCII";
 
-		return fetchRange( Composite(t), section );
-	}
+		var r = command(if( useUid) "UID SORT" else "SORT","("+criteria+") "+charset+" "+pattern);
+		if( !r.success ){
+			throw BadResponse(r.response);
+		}
 
-	/**
-		Fetch one message by its id ou uid
-	**/
-	public function fetchOne( id : Int, ?section : Array<ImapSection>, ?useUid : Bool ) {
-		if( section == null ) section = [BodyPeek(null)];
-		if( useUid == null ) useUid = false;
+		var l = new List();
 
-		var r = fetchRange( Single(id), section, useUid );
-		if( r.length != 1 ){
-			throw ImapFetchError(id);
+		for( v in r.result ){
+			if( StringTools.startsWith(v,"SORT ") ){
+				var t = v.substr(5,v.length-5).split(" ");
+				for( i in t ){
+					l.add( Std.parseInt(i) );
+				}
+			}
 		}
-		return r.first();
+
+		return l;
 	}
 
 	/**
 		Fetch messages from the currently selected mailbox.
 	**/
-	public function fetchRange( iRange: ImapRange, ?iSection : Array<ImapSection>, ?useUid : Bool ) : List<ImapFetchResponse>{
+	public function fetchRange( iRange: Collection, ?iSection : Array<Section>, ?useUid : Bool ) : List<FetchResponse>{
 		if( iRange == null ) return null;
 		if( iSection == null ) iSection = [Body(null)];
 		if( useUid == null ) useUid = false;
 
-		var range = Tools.imapRangeString(iRange);
-		var section = Tools.imapSectionString(iSection);
+		var range = Tools.collString(iRange);
+		var section = Tools.sectionString(iSection);
 
 		if( useUid )
 			command("UID FETCH",range+" "+section,false);
@@ -311,12 +286,12 @@ class Imap {
 					}else if( REG_FETCH_ENVELOPE.match( s ) ){
 						var t = REG_FETCH_ENVELOPE.matchedRight();
 						t = completeString(t);
-						o.envelope = ImapEnvelope.parse( t );
+						o.envelope = Envelope.parse( t );
 						s = StringTools.ltrim(t.substr(o.envelope.__length,t.length));
 					}else if( REG_FETCH_BODYSTRUCTURE.match( s ) ){
 						var t = REG_FETCH_BODYSTRUCTURE.matchedRight();
 						t = completeString(t);
-						o.structure = ImapBodyStructure.parse( t );
+						o.structure = BodyStructure.parse( t );
 						s = StringTools.ltrim(t.substr(o.structure.__length,t.length));
 					}else if( REG_FETCH_PART.match( s ) ){
 						var len = Std.parseInt(REG_FETCH_PART.matched(2));
@@ -349,7 +324,7 @@ class Imap {
 	/**
 		Append content as a new message at the end of mailbox.
 	**/
-	public function append( mailbox : String, content : String, ?flags : ImapFlags ){
+	public function append( mailbox : String, content : String, ?flags : Flags ){
 		var f = if( flags != null ) "("+flags.join(" ")+") " else "";
 		command("APPEND",quote(mailbox)+" "+f+"{"+content.length+"}",false);
 		cnx.write( content );
@@ -371,12 +346,12 @@ class Imap {
 	/**
 		Add, remove or replace flags on message(s) of the currently selected mailbox.
 	**/
-	public function flags( iRange : ImapRange, flags : ImapFlags, ?mode : ImapFlagMode, ?useUid : Bool, ?fetchResult : Bool ) : IntHash<Array<String>> {
+	public function storeFlags( iRange : Collection, flags : Flags, ?mode : FlagMode, ?useUid : Bool, ?fetchResult : Bool ) : IntHash<Array<String>> {
 		if( mode == null ) mode = Add;
 		if( fetchResult == null ) fetchResult = false;
 		if( useUid == null ) useUid = false;
 		
-		var range = Tools.imapRangeString(iRange);
+		var range = Tools.collString(iRange);
 		var elem = switch( mode ){
 			case Add: "+FLAGS";
 			case Remove: "-FLAGS";
@@ -429,51 +404,14 @@ class Imap {
 	/**
 		Copy message(s) from the currently selected mailbox to the end of an other mailbox.
 	**/
-	public function copy( iRange : ImapRange, toMailbox : String, ?useUid : Bool ){
+	public function copy( iRange : Collection, toMailbox : String, ?useUid : Bool ){
 		if( useUid == null ) useUid = false;
 
-		var range = Tools.imapRangeString(iRange);
+		var range = Tools.collString(iRange);
 		var r = command(if(useUid) "UID COPY" else "COPY",range+" "+quote(toMailbox));
 		if( !r.success ) throw BadResponse( r.response );
 	}
 
-	public function sort( criteria : String, ?pattern : String, ?charset : String, ?useUid : Bool ){
-		if( pattern == null ) pattern = "ALL";
-		if( useUid == null ) useUid = false;
-		if( charset == null ) charset = "US-ASCII";
-
-		var r = command(if( useUid) "UID SORT" else "SORT","("+criteria+") "+charset+" "+pattern);
-		if( !r.success ){
-			throw BadResponse(r.response);
-		}
-
-		var l = new List();
-
-		for( v in r.result ){
-			if( StringTools.startsWith(v,"SORT ") ){
-				var t = v.substr(5,v.length-5).split(" ");
-				for( i in t ){
-					l.add( Std.parseInt(i) );
-				}
-			}
-		}
-
-		return l;
-	}
-
-	public function fetchSort( criteria : String, ?pattern : String ,?section : Array<ImapSection> ) : List<ImapFetchResponse>{
-		if( section == null ) section = [BodyPeek(null)];
-		if( pattern == null ) pattern = "ALL";
-		var r = sort(criteria);
-		if( r.length == 0 ) return new List();
-
-		var t = new Array<ImapRange>();
-		for( i in r ){
-			t.push(Single(i));
-		}
-
-		return fetchRange( Composite(t), section );
-	}
 
 
 	/////

+ 13 - 13
std/mtwin/mail/ImapEnvelope.hx → std/mtwin/mail/imap/Envelope.hx

@@ -22,7 +22,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  * DAMAGE.
  */
-package mtwin.mail;
+package mtwin.mail.imap;
 
 import mtwin.mail.Exception;
 
@@ -31,18 +31,18 @@ signature Address = {
 	address: String
 }
 
-class ImapEnvelope {
+class Envelope {
 	public var __length : Int;
-	public var date : String;
-	public var subject : String;
-	public var from : List<Address>;
-	public var sender : List<Address>;
-	public var replyTo : List<Address>;
-	public var to : List<Address>;
-	public var cc : List<Address>;
-	public var bcc : List<Address>;
-	public var inReplyTo : String;
-	public var messageId : String;
+	public var date(default,null) : String;
+	public var subject(default,null) : String;
+	public var from(default,null) : List<Address>;
+	public var sender(default,null) : List<Address>;
+	public var replyTo(default,null) : List<Address>;
+	public var to(default,null) : List<Address>;
+	public var cc(default,null) : List<Address>;
+	public var bcc(default,null) : List<Address>;
+	public var inReplyTo(default,null) : String;
+	public var messageId(default,null) : String;
 
 	function new(){
 		
@@ -53,7 +53,7 @@ class ImapEnvelope {
 		var parCount = 0;
 		var p = 0;
 		var argPos = 0;
-		var ret = new ImapEnvelope();
+		var ret = new Envelope();
 		var tmp = {
 			alist: new List<Address>(),
 			buf: new Array<String>()

+ 158 - 0
std/mtwin/mail/imap/Mailbox.hx

@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2006, Motion-Twin
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MOTION-TWIN "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+/*
+signature ImapMailbox = {
+	name: String,
+	flags: ImapFlags,
+	hasChildren: Bool
+}
+*/
+package mtwin.mail.imap;
+
+import mtwin.mail.imap.Tools;
+
+class Mailbox {
+	static var PREFETCH_SECTION = [Section.Uid,Section.InternalDate,Section.Envelope,Section.BodyStructure,Section.Flags];
+
+	var cnx : Connection;
+	public var name(default,null) : String;
+	var flags : Flags;
+	public var children : List<Mailbox>;
+	var parent : Mailbox;
+
+	public var length(default,null) : Int;
+	public var firstUnseen(default,null) : Int;
+	public var recent(default,null) : Int;
+
+	public static function init( c : Connection, n : String, f : Flags ){
+		return new Mailbox( c,n,f );
+	}
+
+	function new( c, n, f ){
+		cnx = c;
+		name = n;
+		flags = f;
+		children = new List();
+	}
+
+	public function select(){
+		var r = cnx.select( name );
+		if( r != null ){
+			length = r.exists;
+			firstUnseen = r.firstUnseen;
+			recent = r.recent;
+		}
+		return cnx;
+	}
+
+	public function list( ?start : Int, ?end : Int, ?fPrefetch : Bool ){
+		select();
+
+		if( start == null ) start = 1;
+		if( end == null ) end = length;
+		if( fPrefetch == null ) fPrefetch = true;
+		
+		start = Std.int(Math.max(1,Math.min(length,start)));
+		end = Std.int(Math.max(1,Math.min(length,end)));
+		
+		var r = cnx.fetchRange( Range(start,end), if( fPrefetch ) PREFETCH_SECTION else [Uid] );
+		var ret = new List();
+		for( m in r ){
+			var t = Message.initUid(this,m.uid);
+			t.usePrefetch(m);
+			ret.add( t );
+		}
+		return ret;
+	}
+
+	public function get( uid : Int, ?fPrefetch : Bool ){
+		select();
+
+		if( fPrefetch == null ) fPrefetch = true;
+		
+		var ret = Message.initUid( this, uid );
+		if( fPrefetch ) prefetchOne( ret );
+		return ret;
+	}
+
+	public function prefetchOne( m : Message ){
+		var l = new List();
+		l.add( m );
+		prefetch(l);
+	}
+
+	public function prefetch( l : List<Message> ){
+		select();
+
+		var a = new Array();
+		var h = new IntHash();
+		for( m in l ){
+			a.push( Single(m.uid) );
+			h.set(m.uid,m);
+		}
+		var r = cnx.fetchRange( Composite(a), PREFETCH_SECTION, true );
+		for( e in r ){
+			h.get(e.uid).usePrefetch( e );
+		}
+	}
+
+	public function search( pattern : String, ?fPrefetch : Bool ){
+		select();
+
+		if( fPrefetch == null ) fPrefetch = true;
+		var r = cnx.search( pattern, true );
+		var ret = new List();
+		for( uid in r ){
+			ret.add( Message.initUid(this,uid) );
+		}
+		if( fPrefetch ) prefetch( ret );
+		return ret;
+	}
+
+	public function sort( criteria : String, ?pattern : String, ?charset : String, ?fPrefetch : Bool ){
+		select();
+
+		if( pattern == null ) pattern = "ALL";
+		if( charset == null ) charset = "US-ASCII";
+		if( fPrefetch == null ) fPrefetch = true;
+
+		var r = cnx.sort( criteria, pattern, charset, true );
+		var ret = new List();
+		for( uid in r ){
+			ret.add( Message.initUid(this,uid) );
+		}
+		if( fPrefetch ) prefetch( ret );
+		return ret;
+	}
+
+	public function expunge(){
+		select();
+		cnx.expunge();
+	}
+
+	public function add( content : String, ?flags : Flags ){
+		cnx.append( name, content, flags );
+	}
+}

+ 83 - 0
std/mtwin/mail/imap/Message.hx

@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2006, Motion-Twin
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MOTION-TWIN "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+package mtwin.mail.imap;
+
+import mtwin.mail.imap.Tools;
+import mtwin.mail.imap.Connection;
+
+class Message {
+	
+	var mailbox : Mailbox;
+	var id : Int;
+	public var uid(default,null) : Int;
+	var flags : Flags;
+	public var structure(default,null) : BodyStructure;
+	public var envelope(default,null) : Envelope;
+	public var internalDate(default,null) : String;
+
+	public static function initUid( mailbox : Mailbox, uid : Int ){
+		var m = new Message();
+		m.mailbox = mailbox;
+		m.uid = uid;
+		return m;
+	}
+
+	public function new(){
+	}
+
+	function select(){
+	}
+
+	public function usePrefetch( f : FetchResponse ){
+		id = f.id;
+		uid = f.uid;
+		flags = f.flags;
+		structure = f.structure;
+		envelope = f.envelope;
+		internalDate = f.internalDate;
+	}
+
+	public function getSection( s : BodySection, ?markAsReed : Bool ){
+		var cnx = mailbox.select();
+		if( markAsReed == null ) markAsReed = false;
+		
+		var r = cnx.fetchRange( Single(uid), [if( markAsReed ) Body(s) else BodyPeek(s)], true );
+		return r.first().body;
+	}
+
+	public function copyTo( mb : Mailbox ){
+		var cnx = mailbox.select();
+		cnx.copy( Single(uid), mb.name, true );
+	}
+
+	public function hasFlag( f : String ){
+		for( e in flags ){
+			if( e == f ) return true;
+		}
+		return false;
+	}
+
+
+}

+ 112 - 0
std/mtwin/mail/imap/Tools.hx

@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2006, Motion-Twin
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MOTION-TWIN "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+package mtwin.mail.imap;
+
+signature Flags = Array<String>
+
+enum Section {
+	Flags;
+	Uid;
+	BodyStructure;
+	Envelope;
+	InternalDate;
+	Body(ss:BodySection);
+	BodyPeek(ss:BodySection);
+}
+
+enum BodySection {
+	Header;
+	Mime;
+	Text;
+	SubSection(id:String,ss:BodySection);
+}
+
+enum Collection {
+	Single(i:Int);
+	Range(s:Int,e:Int);
+	Composite(l:Array<Collection>);
+}
+
+class Tools {
+	public static function listToColl( l : List<Int> ) : Collection {
+		var a = new Array();
+		for( e in l )
+			a.push( Single(e) );
+		return Composite(a);
+	}
+
+	public static function collString( r : Collection ) : String {
+		return switch( r ){
+			case Single(i): Std.string(i);
+			case Range(s,e): Std.string(s)+":"+Std.string(e);
+			case Composite(l):
+				var t = new List<String>();
+				for( e in l )
+					t.add(collString(e));
+				t.join(",");
+		}
+	}
+
+	public static function sectionString( a : Array<Section> ) : String{
+		var r = new List();
+		
+		if( a == null || a.length < 1 )
+			return "";
+		
+		for( s in a ){
+			r.add( switch( s ){
+				case Flags: "FLAGS";
+				case Uid: "UID";
+				case BodyStructure: "BODYSTRUCTURE";
+				case Envelope: "ENVELOPE";
+				case InternalDate: "INTERNALDATE";
+				case Body(ss): "BODY["+bodySectionString(ss)+"]";
+				case BodyPeek(ss): "BODY.PEEK["+bodySectionString(ss)+"]";
+					
+			});
+		}
+		return "("+r.join(" ")+")";
+	}
+
+	static function bodySectionString( ss : BodySection ){
+		if( ss == null )
+			return "";
+
+		return switch( ss ){
+			case Text: "TEXT";
+			case Header: "HEADER";
+			case Mime: "MIME";
+			case SubSection(id,nss):
+				var t = bodySectionString(nss);
+				if( id == null || id == "" ) 
+					t;
+				else if( t == "" )
+					id;
+				else
+					id+"."+t;
+		}
+	}
+
+}