/* * Copyright (C) 2003-2007 * Nick Velloff * Derrick Grigg * Sean Voisen * Sean Treadway * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ package org.jivesoftware.xiff.core { import org.jivesoftware.xiff.util.SocketConn; import flash.errors.IOError; import flash.events.ProgressEvent; import flash.events.Event; import flash.events.IOErrorEvent; import org.jivesoftware.xiff.events.*; import flash.events.SecurityErrorEvent; import flash.xml.XMLDocument; import flash.xml.XMLNode; import org.jivesoftware.xiff.util.SocketDataEvent; /** * A child of XMPPConnection, this class makes use of the * Flash AVM2 binary socket instead of the older XMLSocket. * This gets rid of issues related to the XMLSocket's appending * of a null-byte to all outgoing data. * * @see org.jivesoftware.xiff.core.XMPPConnection */ public class XMPPSocketConnection extends XMPPConnection { private var _incompleteRawXML: String = ''; protected var binarySocket:SocketConn; public function XMPPSocketConnection() { super(); configureSocket(); } private function configureSocket():void { binarySocket = new SocketConn(); binarySocket.addEventListener(Event.CLOSE, socketClosed); binarySocket.addEventListener(Event.CONNECT, socketConnected); binarySocket.addEventListener(IOErrorEvent.IO_ERROR, onIOError); binarySocket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityError); binarySocket.addEventListener(SocketDataEvent.SOCKET_DATA_RECEIVED, bSocketReceivedData); } override protected function sendXML( someData:* ):void { // Data is untyped because it could be a string or XML binarySocket.sendString(someData); var event:OutgoingDataEvent = new OutgoingDataEvent(); event.data = someData; dispatchEvent( event ); } override public function disconnect():void { if( isActive() ) { sendXML( closingStreamTag ); binarySocket.close(); active = false; loggedIn = false; var event:DisconnectionEvent = new DisconnectionEvent(); dispatchEvent(event); } } override public function connect( streamType:String = "terminatedStandard" ):Boolean { active = false; loggedIn = false; // Stream type lets user set opening/closing tag - some servers (jadc2s) prefer to the standard // switch( streamType ) { case "flash": openingStreamTag = ""; closingStreamTag = ""; break; case "terminatedFlash": openingStreamTag = ""; closingStreamTag = ""; break; case "standard": openingStreamTag = ""; closingStreamTag = ""; break; case "terminatedStandard": default: openingStreamTag = ""; closingStreamTag = ""; break; } binarySocket.connect( server, port ); return true; } protected function bSocketReceivedData( ev:SocketDataEvent ):void { var rawXML:String = _incompleteRawXML + ev.data as String; // parseXML is more strict in AS3 so we must check for the presence of flash:stream // the unterminated tag should be in the first string of xml data retured from the server if (!_expireTagSearch) { var pattern:RegExp = new RegExp(""); _expireTagSearch = true; } } if (!_expireTagSearch) { var pattern2:RegExp = new RegExp(""); _expireTagSearch = true; } } var xmlData:XMLDocument = new XMLDocument(); xmlData.ignoreWhite = this.ignoreWhite; //error handling to catch incomplete xml strings that have //been truncated by the socket try{ var isComplete: Boolean = true; xmlData.parseXML( rawXML ); _incompleteRawXML = ''; } catch(err:Error){ isComplete = false; _incompleteRawXML += ev.data as String;//concatenate the raw xml to the previous xml } if (isComplete){ var event:IncomingDataEvent = new IncomingDataEvent(); event.data = xmlData; dispatchEvent( event ); for (var i:int = 0; i