removed strict need to passing a connection or jid to the constructor of a stream.

tong [09-11-22 03:35]
removed strict need to passing a connection or jid to the constructor of a stream.
Filename
jabber/JID.hx
jabber/Stream.hx
jabber/client/SASLAuthentication.hx
jabber/client/Stream.hx
jabber/component/Stream.hx
diff --git a/jabber/JID.hx b/jabber/JID.hx
index ced6561..b0ae3e7 100644
--- a/jabber/JID.hx
+++ b/jabber/JID.hx
@@ -17,8 +17,6 @@
 */
 package jabber;

-import jabber.JIDUtil;
-
 /**
 	An XMPP address (JID).<br/>
 	A JID is made up of a node (generally a username), a domain, and a resource.<br/>
@@ -36,29 +34,33 @@ class JID {

 	public static inline var MAX_PART_SIZE = 1023;

-	public var node(default,null) : String;
-    public var domain(default,null) : String;
+	//public var node(default,null) : String;
+	public var node : String;
+    //public var domain(default,null) : String;
+    public var domain : String;
     public var resource : String;
     /** JID without resource */
 	public var bare(getBare,null) : String;

 	public function new( str : String ) {
-
-		if( !JIDUtil.isValid( str ) )
-			throw "Invalid JID: "+str;
-
-		this.node = JIDUtil.parseNode( str );
-		this.domain = JIDUtil.parseDomain( str );
-		this.resource = JIDUtil.parseResource( str );
+		if( str != null ) {
+			if( !JIDUtil.isValid( str ) )
+				throw "Invalid JID: "+str;
+
+			this.node = JIDUtil.parseNode( str );
+			this.domain = JIDUtil.parseDomain( str );
+			this.resource = JIDUtil.parseResource( str );
+		}
 	}

 	function getBare() : String {
-		return node+"@"+domain;
+		return ( node == null || domain == null ) ? null : node+"@"+domain;
 	}

 	public function toString() : String {
 		var j = getBare();
-		return ( resource == null ) ? j : j += "/"+resource;
+		if( j == null ) return null;
+		return ( resource == null ) ? j : j+="/"+resource;
 	}

 }
diff --git a/jabber/Stream.hx b/jabber/Stream.hx
index eec6e74..7d7b6dc 100644
--- a/jabber/Stream.hx
+++ b/jabber/Stream.hx
@@ -17,7 +17,6 @@
 */
 package jabber;

-import jabber.Stream;
 import jabber.stream.Connection;
 import jabber.stream.TPacketInterceptor;
 import jabber.stream.PacketCollector;
@@ -73,31 +72,31 @@ class Stream {
 	public var jidstr(getJIDStr,null) : String;
 	public var server(default,null) : Server;
 	public var features(default,null) : StreamFeatures;
-	/** Indicates if the version number of the XMPP stream ("1.0") should get added to the stream opening XML element */
-	public var version : Bool;
-	//TODO
+	public var version : Bool; //Indicates if the version number of the XMPP stream ("1.0") should get added to the stream opening XML element.
 	//public var dataFilters : List<TDataFilter>;
 	//public var dataInterceptors : List<TDataInterceptor>;

-	var collectors : List<PacketCollector>; // public var collectors : Array<TPacketCollector>;
-	var interceptors : List<TPacketInterceptor>; // public var interceptors : Array<TPacketCollector>;
+	var collectors : List<PacketCollector>; // public var packetCollectors : Array<TPacketCollector>;
+	var interceptors : List<TPacketInterceptor>; // public var packetInterceptors : Array<TPacketCollector>;
 	var isBOSH : Bool;
 	var numPacketsSent : Int;
+	//var numPacketsRecieved : Int;

-	function new( cnx : Connection ) {
-		if( cnx == null )
-			throw "Stream connection is null";
-		collectors = new List();
-		interceptors = new List();
+	function new( ?cnx : Connection ) {
+//		if( cnx == null )
+//			throw "Stream connection is null";
+		status = StreamStatus.closed;
 		server = { features : new Hash() };
 		features = new StreamFeatures();
 		version = true;
-		status = StreamStatus.closed;
+		collectors = new List();
+		interceptors = new List();
 		isBOSH = false;
 		numPacketsSent = 0;
-		setConnection( cnx );
 		//dataFilters = new List();
 		//dataInterceptors = new List();
+		if( cnx != null )
+			setConnection( cnx );
 	}

 	function getJIDStr() : String {
@@ -119,7 +118,7 @@ class Stream {
 			cnx.onData = processData;
 			cnx.onError = errorHandler;
 		}
-		isBOSH = ( Type.getClassName( Type.getClass( c ) ) == "jabber.BOSHConnection" );
+		isBOSH = ( Type.getClassName( Type.getClass( cnx ) ) == "jabber.BOSHConnection" );
 		return cnx;
 	}

@@ -137,10 +136,12 @@ class Stream {
 	/**
 		Request to open the XMPP stream.
 	*/
+	//TODO public function open( ?jid : String ) : Bool {
 	public function open() : Bool {
 //		if( status == StreamStatus.open ) return false;
 		if( !cnx.connected ) cnx.connect()
 		else connectHandler();
+		//( cnx.connected ) ? connectHandler() : cnx.connect();
 		return true;
 	}

@@ -154,7 +155,7 @@ class Stream {
 		}
 		if( disconnect )
 			cnx.disconnect();
-		handleClose();
+		closeHandler();
 	}

 	/**
@@ -186,7 +187,6 @@ class Stream {
 	}

 	/*
-	/*
 		TODO Send raw bytes data.
 	*/
 	/*
@@ -216,6 +216,7 @@ class Stream {
 	{
 		if( iq.id == null )
 			iq.id = nextID();
+		//iq.from = jidstr;
 		var c : PacketCollector = null;
 		if( handler != null ) {
 			c = new PacketCollector( [cast new PacketIDFilter( iq.id )], handler, permanent, timeout, block );
@@ -291,23 +292,28 @@ class Stream {

 	/**
 	*/
+	//TODO remove pos/length value
+	//public function processData( buf : haxe.io.Bytes ) : Bool {
 	public function processData( buf : haxe.io.Bytes, bufpos : Int, buflen : Int ) : Int {
 		if( status == StreamStatus.closed )
 			return -1;
 		//TODO .. data filters
-		var t = buf.readString( bufpos, buflen );
+		//
+		var t : String = buf.readString( bufpos, buflen );
+		//TODO
 		if( xmpp.Stream.REGEXP_CLOSE.match( t ) ) {
 			close( true );
 			return -1;
 		}
+		//TODO
 		if( xmpp.Stream.REGEXP_ERROR.match( t ) ) {
 		//if( ~/stream:error/.match( t ) ) {
 			var err : xmpp.StreamError = null;
 			try {
 				err = xmpp.StreamError.parse( Xml.parse( t ) );
 			} catch( e : Dynamic ) {
-				onClose( "Invalid stream:error" );
-				close();
+				onClose( "Invalid XMPP stream "+e );
+				close( true );
 				return -1;
 			}
 			onClose( err );
@@ -320,18 +326,22 @@ class Stream {
 		case pending :
 			return processStreamInit( XmlUtil.removeXmlHeader( t ), buflen );
 		case open :
+
 			// HACK flash/js Xml bug !
 			#if (flash||js)
+			if(  t.charAt( 0 ) != "<" || t.charAt( t.length-1 ) != ">" ) {
+				return 0;
+			}
+			/*
 			if( !StringTools.startsWith(t,"<") || !StringTools.endsWith(t, ">") ) {
 				if( !REG_HACK.match( t ) ) {
-				//if( !StringTools.startsWith(t,"<") || !StringTools.endsWith(t, ">") ) {
 					#if JABBER_DEBUG
 					trace( "Invalid XML " );
 					#end
 					return 0;
 				}
-
 			}
+			*/
 			#end
 			// filter data here ?
 			var x : Xml = null;
@@ -349,9 +359,11 @@ class Stream {
 		return 0;
 	}

+	//HACK
 	#if (flash||js)
-	static inline var REG_HACK = ~/(.+)(\/[a-zA-Z-]*)>$/;
+	//static inline var REG_HACK = ~/(.+)(\/[a-zA-Z-]*)>$/;
 	#end
+	//HACK

 	/**
 		Inject incoming XML data to handle.<br/>
@@ -373,12 +385,6 @@ class Stream {
 	*/
 	public function handlePacket( p : xmpp.Packet ) : Bool {
 		#if XMPP_DEBUG
-		/*
-		if( p.errors.length > 0 )
-			XMPPDebug.error( p.toString() );
-		else
-			XMPPDebug.inc( p.toString() );
-		*/
 		XMPPDebug.inc( p.toString() );
 		#end
 		var collected = false;
@@ -401,7 +407,7 @@ class Stream {
 		}
 		if( !collected ) {
 			#if JABBER_DEBUG
-			trace( Type.enumConstructor( p._type )+" packet not handled", "warn" );
+			trace( "incoming '"+Type.enumConstructor( p._type )+"' packet not handled ( "+p.from+" -> "+p.to+" )", "warn" );
 			#end
 			if( p._type == xmpp.PacketType.iq ) { // send a 'feature not implemented' response
 				var q : xmpp.IQ = cast p;
@@ -423,25 +429,25 @@ class Stream {
 	}
 	*/

-	function handleClose() {
+	function processStreamInit( t : String, buflen : Int ) : Int {
+		return throw "abstract";
+	}
+
+	function closeHandler() {
 		id = null;
 		numPacketsSent = 0;
 		onClose();
 	}

-	function processStreamInit( t : String, buflen : Int ) : Int {
-		return throw "abstract";//throw new error.AbstractError();
-	}
-
 	function connectHandler() {
 	}

-	function disconnectHandler() {
-		handleClose();
-	}
-
 	function errorHandler( m : Dynamic ) {
 		onClose( m );
 	}
+
+	function disconnectHandler() {
+		//? closeHandler();
+	}

 }
diff --git a/jabber/client/SASLAuthentication.hx b/jabber/client/SASLAuthentication.hx
index d48d7e4..d46f535 100644
--- a/jabber/client/SASLAuthentication.hx
+++ b/jabber/client/SASLAuthentication.hx
@@ -23,13 +23,11 @@ import xmpp.IQType;
 import xmpp.filter.PacketNameFilter;
 import xmpp.filter.FilterGroup;

-	//TODO use remaining mechanisms on fail (?)
-
 /**
-	Responsible for authenticating a client account using SASL, binding the resource to the connection
-	and establishing a session with the server.<br>
-	<a href="http://xmpp.org/rfcs/rfc3920.html#sasl">RFC3920-SASL</a><br>
-	<a href="http://xmpp.org/rfcs/rfc3920.html#bind">RFC3920-BIND</a><br>
+	Responsible for authenticating a client account using SASL,
+	binding the resource to the connection and establishing a session with the server.<br>
+	<a href="http://xmpp.org/rfcs/rfc3920.html#sasl">RFC3920-SASL</a><br/>
+	<a href="http://xmpp.org/rfcs/rfc3920.html#bind">RFC3920-BIND</a><br/>
 	http://www.ietf.org/mail-archive/web/isms/current/msg00063.html
 */
 class SASLAuthentication extends Authentication {
@@ -67,7 +65,8 @@ class SASLAuthentication extends Authentication {
 	public override function authenticate( password : String, ?resource : String ) : Bool {
 		this.resource = resource;
 		// update stream jid resource
-		stream.jid.resource = resource;
+		if( stream.jid != null && resource != null )
+			stream.jid.resource = resource;
 		// locate mechanism to use.
 		if( handshake.mechanism == null ) {
 			for( amechs in mechanisms ) {
@@ -87,9 +86,6 @@ class SASLAuthentication extends Authentication {
 			#end
 			return false;
 		}
-		//#if JABBER_DEBUG
-		//trace( "Used SASL mechanism: "+handshake.mechanism.id, "info" );
-		//#end
 		// collect failures
 		var f = new FilterGroup();
 		f.add( new PacketNameFilter( ~/failure/ ) ); //?
@@ -109,6 +105,7 @@ class SASLAuthentication extends Authentication {
 		c_challenge = new PacketCollector( [cast new PacketNameFilter( ~/challenge/ )], handleSASLChallenge, true );
 		stream.addCollector( c_challenge );
 		// send init auth
+		//trace("############## "+stream.jid );
 		var t = handshake.mechanism.createAuthenticationText( stream.jid.node, stream.jid.domain, password );
 		if( t != null ) t = util.Base64.encode( t );
 		return stream.sendData( xmpp.SASL.createAuthXml( handshake.mechanism.id, t ).toString() ) != null;
@@ -127,10 +124,8 @@ class SASLAuthentication extends Authentication {
 	}

 	function handleSASLSuccess( p : xmpp.Packet ) {
-		// remove the challenge collector
-		removeSASLCollectors();
-		// relay the stream open event
-		onStreamOpenHandler = stream.onOpen;
+		removeSASLCollectors(); // remove the challenge collector
+		onStreamOpenHandler = stream.onOpen; // relay the stream open event
 		stream.onOpen = handleStreamOpen;
 		onNegotiated();
 		//stream.version = false;
@@ -143,7 +138,7 @@ class SASLAuthentication extends Authentication {
 		//onStreamOpenHandler = null;
 		if( stream.server.features.exists( "bind" ) ) { // bind the resource
 			var iq = new IQ( IQType.set );
-			iq.x = new xmpp.Bind( resource );
+			iq.x = new xmpp.Bind( ( handshake.mechanism.id == "ANONYMOUS" ) ? null : resource );
 			stream.sendIQ( iq, handleBind );
 		} else {
 			onSuccess(); // TODO ?
@@ -160,6 +155,11 @@ class SASLAuthentication extends Authentication {
 				throw "Unexpected resource bound ?";
 			}
 			*/
+			//onBind();
+			var b = xmpp.Bind.parse( iq.x.toXml() );
+			var jid = new jabber.JID( b.jid );
+			stream.jid.node = jid.node;
+			stream.jid.resource = jid.resource;
 			if( stream.server.features.exists( "session" ) ) {
 				// init session
 				var iq = new IQ( IQType.set );
@@ -174,8 +174,11 @@ class SASLAuthentication extends Authentication {

 	function handleSession( iq : IQ ) {
 		switch( iq.type ) {
-		case result : onSuccess();
-		case error : onFail( new jabber.XMPPError( this, iq ) );
+		case result :
+			////onSession();
+			onSuccess();
+		case error :
+			onFail( new jabber.XMPPError( this, iq ) );
 		default : //#
 		}
 	}
diff --git a/jabber/client/Stream.hx b/jabber/client/Stream.hx
index 3465366..f251d5a 100644
--- a/jabber/client/Stream.hx
+++ b/jabber/client/Stream.hx
@@ -17,10 +17,12 @@
 */
 package jabber.client;

+import jabber.JID;
+import jabber.StreamStatus;
 import jabber.stream.Connection;

 /**
-	Base for client XMPP streams.<br/>
+	Client XMPP stream base.<br/>
 */
 class Stream extends jabber.Stream {

@@ -28,11 +30,12 @@ class Stream extends jabber.Stream {
 	public static inline var PORT_SECURE_STANDARD = 5223;
 	public static var defaultPort = PORT_STANDARD;

+	public var jid(default,setJID) : JID;
 	// public var tls(default,null) : Bool;
-	public var jid(default,null) : jabber.JID;

-	public function new( jid : jabber.JID, cnx : Connection,
-						 version : Bool = true ) {
+	public function new( ?jid : JID, ?cnx : Connection, ?version : Bool = true ) {
+		if( jid == null )
+			jid = new JID(null);
 		super( cnx );
 		this.jid = jid;
 		this.version = version;
@@ -43,12 +46,18 @@ class Stream extends jabber.Stream {
 		return jid.toString();
 	}

+	function setJID( j : JID ) : JID {
+		if( status != StreamStatus.closed )
+			throw "Cannot change JID on active stream";
+		return jid = j;
+	}
+
 	override function processStreamInit( t : String, buflen : Int ) : Int {
 		if( isBOSH ) {
 			var sx = Xml.parse( t ).firstElement();
 			var sf = sx.firstElement();
 			parseStreamFeatures( sf );
-			status = jabber.StreamStatus.open;
+			status = StreamStatus.open;
 			onOpen();
 			return buflen;
 		} else {
@@ -64,7 +73,7 @@ class Stream extends jabber.Stream {
 				var sx = Xml.parse( s ).firstElement();
 				id = sx.get( "id" );
 				if( !version ) {
-					status = jabber.StreamStatus.open;
+					status = StreamStatus.open;
 					onOpen();
 					return buflen;
 				}
@@ -75,7 +84,7 @@ class Stream extends jabber.Stream {
 				return -1;
 			}
 			if( !version ) {
-				status = jabber.StreamStatus.open;
+				status = StreamStatus.open;
 				onOpen();
 				return buflen;
 			}
@@ -89,7 +98,7 @@ class Stream extends jabber.Stream {
 				#if XMPP_DEBUG
 				jabber.XMPPDebug.inc( sfx.toString() );
 				#end
-				status = jabber.StreamStatus.open;
+				status = StreamStatus.open;
 				onOpen();
 				return buflen;
 			} catch( e : Dynamic ) {
@@ -101,7 +110,7 @@ class Stream extends jabber.Stream {
 	}

 	override function connectHandler() {
-		status = jabber.StreamStatus.pending;
+		status = StreamStatus.pending;
 		// TODO avoid HACK
 		if( !isBOSH ) {
 			sendData( xmpp.Stream.createOpenStream( xmpp.Stream.XMLNS_CLIENT, jid.domain, version, lang ) );
diff --git a/jabber/component/Stream.hx b/jabber/component/Stream.hx
index 7d26403..7747185 100644
--- a/jabber/component/Stream.hx
+++ b/jabber/component/Stream.hx
@@ -43,7 +43,7 @@ class Stream extends jabber.Stream {
 	/**  */
 	public var connected(default,null) : Bool;
 	/** */
-	public var items(default,null) : xmpp.disco.Items;
+	public var items(default,null) : xmpp.disco.Items; //TODO move into jabber.Stream? ( allowed by clients ? )
 	/** */
 	public var serviceListener(default,null) : ServiceDiscoveryListener;

@@ -68,6 +68,8 @@ class Stream extends jabber.Stream {
 	}

 	function getServiceName() : String {
+		if( subdomain == null || host == null )
+			return null;
 		return subdomain+"."+host;
 	}
ViewGit