1  //!-- UTF8
     2  /*
     3  	Oregano Multiuser Server - Version 1.2.0 - January 4th, 2005
     4  
     5  	Web:  www.oregano-server.org
     6  	Mail: info@oregano-server.org
     7  
     8  	Copyright 2003 - 2004 Jens Halm / Cologne, Germany
     9  
    10      This library is free software; you can redistribute it and/or
    11      modify it under the terms of the GNU Lesser General Public
    12      License as published by the Free Software Foundation; either
    13      version 2.1 of the License, or (at your option) any later version.
    14  
    15      This library is distributed in the hope that it will be useful,
    16      but WITHOUT ANY WARRANTY; without even the implied warranty of
    17      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    18      Lesser General Public License for more details.
    19  
    20      You should have received a copy of the GNU Lesser General Public
    21      License along with this library; if not, write to the Free Software
    22      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    23  */
    24  
    25  /*
    26  -------------------------------------------
    27  	Classe Session
    28  
    29  	@description :
    30  	Singleton qui gère la connection  au socket.
    31  
    32  
    33  	@author Jens Halm copyright http://www.spicefactory.org/
    34  	@author erixtekila copyleft http://www.v-i-a.net  
    35  -------------------------------------------
    36  	version history :
    37  	1.2.0 : 29/12/04
    38  			- Portage en actionscript 2 pour le
    39  			compile time type checking
    40  			- Initialisation des globales et du resolver
    41  -------------------------------------------
    42  */
    43  
    44  import org.omus.core.*;
    45  //import org.omus.data.*
    46  //import org.omus.db.*
    47  import org.omus.msg.*;
    48  import org.omus.util.*;
    49  
    50  /**
    51   *	Classe est une enveloppe de la connection au serveur.
    52   *
    53   *	<p>
    54   *	Evénements auxquels s'abonner :
    55   *	<ul>
    56   *	<li>onLogin(data:Object)		Invoqué lors du succès de la connection.
    57   *									_param data	Un objet vide nécessitant l'ecriture d'un LoginExtension côté serveur.
    58   *	</li><li>onLogout(error:_Error)	Invoqué lors de la déconnection de l'utilisateur courant.
    59   *									_param data	Code d'erreur renvoyant la cause de la déconnection.
    60   *	</li><li>onRegister(data:Object)	Invoqué lors du succès de l'enregistrement de l'utilisateur.
    61   *									_param data	Un objet vide nécessitant l'ecriture d'un LoginExtension côté serveur.
    62   *	</li><li>onError(error:_Error)		Invoqué lors d'une erreur de traitement d'une de ces méthodes : login ou register.
    63   *	</li></ul>
    64   *	</p><p>
    65   *	Cette classe est implémentée en suivant le modèle Singleton.
    66   *	Un accès global à son instance est obtenu graçe à la méthode getInstance.
    67   *	Elle est aggrémentée par composition des méthodes des sources d'événements (EventDispatcher).
    68   *	Elle est aggrémentée par composition de la classe MessageHandler.
    69   *	</p>
    70   *	@see org.omus.util.EventDispatcher
    71   *	@see org.omus.util.iObservable
    72   *	@see org.omus.msg.MessageHandler
    73   *	@see org.omus.msg.iMessageHandler
    74   *
    75   *	@author Jens Halm copyright http://www.spicefactory.org/
    76   *	@author erixtekila copyleft http://www.v-i-a.net 
    77   *	@version 1.2.0
    78   */
    79  class org.omus.core.Session implements iObservable, iMessageHandler
    80  {
    81  	//--------------------
    82  	// PROPRIETES
    83  	//--------------------
    84  	/**
    85  	 *	Version du client à valider avec celle du serveur.
    86  	 *	Permet de valider une bonne utilisation du client. 
    87  	 */
    88  	public var versionID:String;
    89  	
    90  	/**
    91  	 *	Url du serveur.
    92  	 */
    93  	public var address:String;
    94  	
    95  	/**
    96  	 *	Port du socket.
    97  	 */
    98  	public var loginPort:Number;
    99  	
   100  	/**
   101  	 *	Autre port de connection en cas de l'utilsation en cluster.
   102  	 */
   103  	public var reconnectPort:Number;
   104  	
   105  	/**
   106  	 *	Référence au système de génération d'événements.
   107  	 */
   108  	private var _eventSource:EventDispatcher;
   109  	
   110  	/**
   111  	 *	Référence à la classe MessageHandler;
   112  	 */
   113  	private var _messageHandler:MessageHandler;
   114  	
   115  	/**
   116  	 *	Référence à l'objet Socket.
   117  	 */
   118  	private var socket:Socket;
   119  	
   120  	/**
   121  	 *	Utile en cas d'échec de connection au socket principal.
   122  	 */
   123  	private var oldSocket:XMLSocket;
   124  	
   125  	/**
   126  	 *	Utile en cas d'échec de connection au socket principal.
   127  	 */
   128  	private var recVer:Number;
   129  	
   130  	/**
   131  	 *	Référence à la fonction d'encodage du mot de passe.
   132  	 */
   133  	private var pwdEncoder:Function;
   134  	
   135  	/**
   136  	 *	Connection ouverte.
   137  	 */
   138  	private var online:Boolean;
   139  	
   140  	/**
   141  	 *	Processus de changement de groupe enclenché.
   142  	 */
   143  	public var changeGroup:Boolean;
   144  	
   145  	/**
   146  	 *	Donne l'état du login.
   147  	 */
   148  	private var loginMode:String;
   149  	
   150  	/**
   151  	 *	Conserve les informations de login pour la session
   152  	 *	sous la forme [utilisateur, password, mail].
   153  	 */
   154  	private var cache:Array;
   155  	
   156  	/**
   157  	 *	Les informations du client Flash.
   158  	 */
   159  	private var clientInfo:ClientInfo;
   160  	
   161  	
   162  	/**
   163  	 *	Référence à l'unique instance de la classe permise.
   164  	 */
   165  	private static var _instance:Session;
   166  	
   167  	
   168  	//--------------------
   169  	// CONSTRUCTEUR
   170  	//--------------------
   171  	/**
   172  	 *	L'objet Session dispose des méthodes d'EventDispatcher
   173  	 *	et de celles de MessageHandler par composition.
   174  	 *
   175  	 *	@see org.omus.util.EventDispatcher
   176  	 *	@see org.omus.util.iObservable
   177  	 *	@see org.omus.msg.MessageHandler
   178  	 *	@see org.omus.msg.iMessageHandler
   179  	 */
   180  	private function Session()
   181  	{		
   182  		// Composition avec EventDispatcher
   183  		_eventSource = new EventDispatcher();
   184  		// Composition avec MessageHandler
   185  		_messageHandler = new MessageHandler();
   186  		
   187  		// Initialisation des événements
   188  		_messageHandler.initMessageHandler(this);
   189  		
   190  		// Callbacks des envois de messages.
   191  		addHandler("encoding","handleEncoding");
   192  		addHandler("loginRequest","handleLoginRequest");
   193  		addHandler("login","handleConnect");
   194  		addHandler("register","handleConnect");
   195  		addHandler("logout","handleLogout");
   196  		addHandler("reconnect","handleReconnect");
   197  		addHandler("error","handleError");
   198  		// Réinitialise la connection
   199  		//!!! TODO : Suppression de reset pour mise dans init cat appelle MesageRouter qui apelle Session.getInstance…
   200  		// reset();
   201  		// TODO : Remplacement par tout ce qui ne gène pas dans reset ();
   202  		online = false;
   203  		changeGroup = false;
   204  		loginMode = null;
   205  		cache = null;
   206  		// Logs
   207  		Log.getInstance().clearCache();
   208  		// Logs internes 
   209  		_global.oregano.iLog.clearCache();
   210  		
   211  		pwdEncoder = null;
   212  		
   213  		// Ouvre la connection au socket.
   214  		createSocket();
   215  		
   216  		// ?? 
   217  		// <temporary>
   218  		recVer = 3;
   219  		
   220  		// trace(this+ " initialisé.");
   221  	}
   222  	
   223  	//--------------------
   224  	// METHODES PUBLIQUES
   225  	//--------------------
   226  	/**
   227  		*	Utilisé dans un contexte littéral
   228  		*	@return	Une chaine définissant l'objet
   229  		*/
   230  	public function toString():String
   231  	{
   232  		var s = "[Objet Session]";
   233  		s += "\norg.omus.session:";
   234  		s += "\nversionID = " + versionID;
   235  		s += "\nserver address = " + address;
   236  		s += "\nlogin port = " + loginPort;
   237  		s += "\nreconnect port = " + reconnectPort;
   238  		s += "\nconnected = " + isConnected();
   239  		return s;
   240  	}
   241  	
   242  	/**
   243  	 *	Remet les informations de session à zéro.
   244  	 */
   245  	public function reset ():Void
   246  	{
   247  		online = false;
   248  		changeGroup = false;
   249  		loginMode = null;
   250  		cache = null;
   251  		// TODO : Accès Singleton
   252  		var msgRouter = MessageRouter.getInstance();
   253  		msgRouter.clearCache();
   254  		// Logs
   255  		Log.getInstance().clearCache();
   256  		// Logs internes
   257  		_global.oregano.iLog.clearCache();
   258  	}
   259  	
   260  	/**
   261  	 *	Initialise la connection avec le serveur.
   262  	 *
   263  	 *	@param vers		Une chaine qui sera comparée à l'attribut versionID du fichier config.xml.
   264  	 *	@param addr		Une url valide sous forme "www.domaine.tld" ou IP.
   265  	 *	@param login	Le port du socket.
   266  	 *	@param	recon	Optionnel. Requis qu'en mode cluster.
   267  	 */
   268  	public function init (vers:String, addr:String, login:Number, recon:Number):Void
   269  	{
   270  		// Evite une reconnection
   271  		if (online)
   272  		{
   273  			// Logs internes
   274  			_global.oregano.iLog.error("clj-006","");
   275  			return;
   276  		}
   277  		
   278  		// Typage des arguments
   279  		// TODO : Accès Singleton
   280  		var clazz = _Class.getInstance();
   281  		var argCheck = [
   282  						[vers,"string",true],
   283  						[addr,"string",true],
   284  						[login,"number",true],
   285  						[recon,"number",false]
   286  						];
   287  		if (! clazz.checkArguments("org.omus.session.init", argCheck)) return;
   288  		reset();
   289  		
   290  		versionID = vers;
   291  		address = addr;
   292  		loginPort = login;
   293  		reconnectPort = recon;
   294  		
   295  		// trace(this+ " installé.");
   296  	}
   297  	
   298  	/**
   299  	 *	Spécifie une fonction d'encodage des mots de passe et méthodes enregistrées.
   300  	 *	Nécessite l'écriture d'une extension en java pour le décodage côté serveur.
   301  	 *	Exemple :
   302  	 *	<code>
   303  	 *	pwdEncoder = function (password, serverKey){
   304  	 *		var offset = parseInt(serverKey);
   305  	 *		var encoded = ""; 
   306  	 *		for (var i = 0; i < password.length; i++) {
   307  	 *			var num = password.charCodeAt(i) + offset;
   308  	 *			encoded += num + "-";
   309  	 *		}
   310  	 *		return encoded;
   311  	 *	}
   312  	 *	var session = org.omus.core.Session.getInstance();
   313  	 *	session.setPasswordEncoder(pwdEncoder);
   314  	 *	</code>
   315  	 *
   316  	 *	@param func		Fonction d'encodage.
   317  	 */
   318  	public function setPasswordEncoder (func:Function):Void
   319  	{
   320  		// TODO : Accès Singleton
   321  		var clazz = _Class.getInstance();
   322  		
   323  		if (! clazz.checkArguments("org.omus.session.setPasswordEncoder",[[func,"function",true]])) return;
   324  		pwdEncoder = func;
   325  	}
   326  	
   327  	/**
   328  	 *	Log un utilisateur déjà enregistré comme utilisateur.
   329  	 *	
   330  	 *	@param user		Login de l'utilisateur.
   331  	 *	@param pwd		Mot de passe.
   332  	 */
   333  	public function login (user:String, pwd:String):Void
   334  	{
   335  		// TODO : Accès Singleton
   336  		var clazz = _Class.getInstance();
   337  		if (! clazz.checkArguments("org.omus.session.login", [[user, "string", true], [pwd, "string", true]])) return;
   338  		// Enregistrement
   339  		cache = [user, pwd];
   340  		loginMode = "login";
   341  		// Etablit la connection au socket
   342  		connect(address, loginPort);
   343  	}
   344  	
   345  	/**
   346  	 *	Enregistre un nouvel utilisateur
   347  	 *
   348  	 *	@param user		Log utilisateur.
   349  	 *	@param pwd		Mot de passe.
   350  	 *	@param mail		Mail interne pour la réception de messages permanents.
   351  	 */
   352  	public function register (user:String, pwd:String, mail:String):Void
   353  	{
   354  		// TODO : Accès Singleton
   355  		var clazz = _Class.getInstance();
   356  		var argCheck = [[user,"string",true], [pwd,"string",true], [mail,"string",true]];
   357  		if (! clazz.checkArguments("org.omus.session.register", argCheck)) return;
   358  		// Enregistrement
   359  		cache = [user, pwd, mail];
   360  		loginMode = "register";
   361  		// Etablit la connection au socket.
   362  		connect(address, loginPort);
   363  	}
   364  	
   365  	/**
   366  	 *	Spécifie si l'utilisateur est connecté 
   367  	 *	ou si l'utilisateur est en train de changer de groupe. 
   368  	 */
   369  	public function isConnected ():Boolean
   370  	{
   371  		return (online && ! changeGroup);
   372  	}
   373  	
   374  	/**
   375  	 *	Cloture la connection au serveur.
   376  	 */
   377  	public function logout ():Void
   378  	{
   379  		// TODO : Accès Singleton
   380  		var envFactory = EnvelopeFactory.getInstance();
   381  		//!! Vérifier la réf. !!
   382  		var env = envFactory.getOutgoing(new Message(""),"logout");
   383  		// Message de sortie soumis au serveur.
   384  		sendMessage(env);
   385  	}
   386  	
   387  	
   388  	/**
   389  	 *	Soumet un message au serveur.
   390  	 *
   391  	 *	@param env		Enveloppe contenant le message
   392  	 */
   393  	public function sendMessage (env:Envelope):Void
   394  	{
   395  		if (! online)
   396  		{
   397  			if (env.getType() != "encoding" && (env.getType() != "session" || env.getMessage().getSubject() != loginMode))
   398  			{
   399  				// Logs internes
   400  				_global.oregano.iLog.error("clj-011","envelope = " + env);
   401  				return;
   402  			}
   403  		} else 
   404  		{
   405  			if (changeGroup)
   406  			{
   407  				// Logs internes
   408  				_global.oregano.iLog.error("clj-011","envelope = " + env);
   409  				return;
   410  			}
   411  		}
   412  		// Message encodé correctement pour le serveur
   413  		var str = env.getMarshalledString();
   414  		// Logs internes
   415  		if (_global.oregano.iLog.infoEnabled()) _global.oregano.iLog.logLocal("INFO","clj-012","str = " + str + "\nenvelope = " + env);
   416  		// Soumet
   417  		socket.send(str);
   418  	}
   419  	
   420  	//*** Implémentation de iObservable ***\
   421  	/**
   422  	 *	Notifie les observateurs d'un événement.
   423  	 *
   424  	 *	@param logLevel Une chaine caractérisant le niveau de logging de l'information.
   425  	 *	@param eventName Nom de l'événement.
   426  	 *	@param arg1		[option] Autant de paramêtres de voulu.
   427  	 */
   428  	private function fireEvent (logLevel:String, eventName:String):Void
   429  	{
   430  		_eventSource.fireEvent.apply (_eventSource, arguments);
   431  	}
   432  	
   433  	/**
   434  	 *	Ajoute un nouvel observateur.
   435  	 * 
   436  	 *	@param		listener Référence de l'observateur.
   437  	 *	@return Un booléen indiquant la réussite de l'opération.
   438  	 */
   439  	public function addListener (listener:Object):Boolean
   440  	{
   441  		return _eventSource.addListener(listener);
   442  	}
   443  		
   444  	/**
   445  	 *	Supprime un observateur.
   446  	 *
   447  	 *	@param		listener Référence de l'observateur.
   448  	 *	@return Un booléen indiquant la réussite de l'opération.
   449  	 */
   450  	public function removeListener (listener:Object):Boolean
   451  	{
   452  		return _eventSource.removeListener(listener);
   453  	}
   454  	
   455  	/**
   456  	 *	Supprime tous les abonnés.
   457  	 */
   458  	public function removeAllListeners ():Void
   459  	{
   460  		_eventSource.removeAllListeners();
   461  	}
   462  	
   463  	/**
   464  	 *	Retourne le nombre d'observateurs.
   465  	 *
   466  	 *	@return Le nombre d'observateurs enregistrés.
   467  	 */
   468  	public function countListeners ():Number
   469  	{
   470  		return _eventSource.countListeners();
   471  	}
   472  	
   473  	//*** Implémentation de iMessageHandler ***\\
   474  	/**
   475  	 *	Active la gestion d'un type de message en fonction du contenu de son enveloppe.
   476  	 *
   477  	 * @param env		Une référence à l'enveloppe.
   478  	 */
   479  	public function handleMessage (env:Envelope):Void
   480  	{
   481  		_messageHandler.handleMessage(env);
   482  	}
   483  	
   484  	/**
   485  	 *	Rajoute un gestionnaire chargé d'intercepter 
   486  	 *	la réponse du serveur suite à un message soumis.
   487  	 *
   488  	 *	@param		subject Le type de message.
   489  	 *	@param		methodName Le nom de l'événement gérant un type de message. 
   490  	 */
   491  	public function addHandler (subject:String, methodName:String):Void
   492  	{
   493  		_messageHandler.addHandler (subject, methodName);
   494  	}
   495  	
   496  	
   497  	//*** Gestionnaire des accusés de réception de Message ***\\
   498  	/**
   499  	 *	Gère l'accusé de réception du changement de type d'encodage des messages.
   500  	 *
   501  	 *	@param env		Référence à l'enveloppe.
   502  	 */
   503  	private function handleEncoding (env:Envelope):Void
   504  	{
   505  		var enc = (typeof(_global) == "object") ? "UTF-8" : "ISO-8859-1" ;
   506  		var msg = new Message(enc);
   507  		// TODO : Accès Singleton
   508  		var envFactory = EnvelopeFactory.getInstance();
   509  		sendMessage(envFactory.getOutgoing(msg, "encoding"));
   510  	}
   511  	
   512  	// 
   513  	/**
   514  	 *	Gère l'accusé de réception du message de login.
   515  	 *
   516  	 *	@param env		Référence à l'enveloppe soumise.
   517  	 */
   518  	private function handleLoginRequest (env:Envelope):Void
   519  	{
   520  		// clé d'encodage envoyée par le serveur
   521  		var sKey = env.getMessage().getAttachment().key;
   522  		var pwd:String;
   523  		// Recherche le mot de passe utilisateur.
   524  		// Encodé ou non côté serveur
   525  		if (sKey == undefined) {
   526  			// Mot de passe par défaut
   527  			pwd = cache[1];
   528  		} else {
   529  			if (pwdEncoder == null)
   530  			{
   531  				reset();
   532  				// Logs internes
   533  				_global.oregano.iLog.error("clj-013","");
   534  				return;
   535  			}
   536  			pwd = pwdEncoder(cache[1], sKey);
   537  		}
   538  		// Informations du message
   539  		var msg = new Message(loginMode);
   540  		var attach = msg.getAttachment();
   541  		attach.versionID = versionID;
   542  		attach.username = cache[0];
   543  		attach.pwd = pwd;
   544  		
   545  		// email
   546  		if (loginMode == "register") attach.email = cache[2];
   547  		
   548  		// new in version 1.1.0:
   549  		clientInfo = new ClientInfo();
   550  		clientInfo.insert(attach);
   551  		
   552  		// TODO : Accès Singleton
   553  		var envFactory = EnvelopeFactory.getInstance();
   554  		sendMessage(envFactory.getOutgoing(msg, "session"));
   555  	}
   556  	
   557  	/**
   558  	 *	Gère l'accusé de réception du changement de message de début de connection.
   559  	 *	Ici commence l'instanciation de toutes les classes utiles aux communications serveur.
   560  	 *	Génère un événement onLogin ou onRegister aux observateurs.
   561  	 *
   562  	 *	@param env		Référence à l'enveloppe.
   563  	 */
   564  	private function handleConnect (env:Envelope):Void
   565  	{
   566  		// Informations du message
   567  		var msg = env.getMessage();
   568  		var attach = msg.getAttachment();
   569  		// error doit provenir du serveur ?
   570  		var errCode = attach.error;
   571  		if (errCode == "ok")
   572  		{
   573  			online = true;
   574  			if (attach.machineID != undefined) clientInfo.save(attach.machineID); // new in version 1.1.0
   575  			// Logs
   576  			Log.getInstance().setLogLevel(attach.logLevel.dev);
   577  			// Logs internes
   578  			_global.oregano.iLog.setLogLevel(attach.logLevel.omus);
   579  			
   580  			// Nouvel utilisateur accès Singleton
   581  			var user = User.getInstance();
   582  			//!! TODO : Pour éviter une instanciation malencontreuse. !!
   583  			user["init"](attach.regInfo,
   584  						  attach.loginInfo,
   585  						  attach.userProps,
   586  						  attach.userPropConfig);
   587  			
   588  			// Nouveau groupe accès Singleton
   589  			var group = Group.getInstance(attach.groupPropConfig);
   590  			//!! TODO : Pour éviter une instanciation malencontreuse. !!
   591  			group["init"]("login",
   592  						  "login",
   593  						  attach.grpID,
   594  						  0,
   595  						  attach.groupProps,
   596  						  attach.extraPropConfig,
   597  						  null);
   598  			// Nouveau messager accès Singleton
   599  			_global.messenger = Messenger.getInstance();
   600  			// Les informations pratiques
   601  			_global.info = new Info();
   602  			// MessageRouter
   603  			// TODO : Accès Singleton.
   604  			var msgRouter = MessageRouter.getInstance();
   605  			//!! TODO : Pour éviter une instanciation malencontreuse. !!
   606  			msgRouter["init"]();
   607  			
   608  			// Login ou nouvel enregistrement 
   609  			var eventName = (this.loginMode == "login") ? "onLogin" : "onRegister" ;
   610  			// Broadcast
   611  			fireEvent("info", eventName, attach.extra);
   612  			// Logs internes
   613  			_global.oregano.iLog.sendCache();
   614  			// Logs
   615  			Log.getInstance().sendCache();
   616  		} else
   617  		{
   618  			cancelConnect(errCode);
   619  		}
   620  		loginMode = null;
   621  	}
   622  	
   623  	/**
   624  	 *	Gère l'accusé de réception du changement de message de connection à un nouveau socket.
   625  	 *	La connection a probablement échoué.
   626  	 *	Notamment lorsque le seveur est en mode cluster.
   627  	 *
   628  	 *	@param env		Référence à l'enveloppe du message. 
   629  	 */
   630  	private function handleReconnect (env:Envelope) {
   631  		if (typeof(reconnectPort) != "number")
   632  		{
   633  			// Logs internes
   634  			_global.oregano.iLog.warn("clj-066","");
   635  			return;
   636  		}
   637  		
   638  		var address = env.getMessage().getAttachment().address;
   639  		loginMode = "reconnect";
   640  		online = false;
   641  		// Changement de socket
   642  		socket.active = false;
   643  		oldSocket = socket;
   644  		
   645  		// Ferme le socket précédent.
   646  		if (recVer == 3) oldSocket.close();
   647  		// Connecte avec le sopcket alternatif
   648  		createSocket();
   649  		connect(address, reconnectPort);
   650  	}
   651  	
   652  	/**
   653  	 *	Gère le message de sortie de login.
   654  	 *	Génère un événement onLogout aux observateurs.
   655  	 *
   656  	 *	@param env		Référence à l'enveloppe.
   657  	 */
   658  	private function handleLogout (env:Envelope):Void
   659  	{
   660  		reset();
   661  		var errCode = env.getMessage().getAttachment().error;
   662  		var errObj = new _Error(errCode, "logout", new Array());
   663  		// Broadcast
   664  		fireEvent("warn", "onLogout", errObj);
   665  	}
   666  	
   667  	/**
   668  	 *	Gère les messages d'erreur.
   669  	 *
   670  	 *	@param env		Référence à l'enveloppe.
   671  	 */
   672  	private function handleError (env:Envelope):Void
   673  	{
   674  		// error vient du serveur ?
   675  		var errCode = env.getMessage().getAttachment().error;
   676  		changeGroup = false;
   677  		
   678  		if (! online)
   679  		{
   680  			if (loginMode == "reconnect")
   681  			{
   682  				connectionBroken();
   683  				return;
   684  			}
   685  			if (this.loginMode == "login" || this.loginMode == "register")
   686  			{
   687  				cancelConnect(errCode);
   688  				return;
   689  			}
   690  		}
   691  		var err = new _Error(errCode, null, null);
   692  		// Broadcast
   693  		fireEvent("error","onError", err);
   694  	}
   695  	// Fin des callbacks de Message
   696  	
   697  	/**
   698  	 *	Reconnection
   699  	 *	TODO : Ne semble pas utilisé.
   700  	 *
   701  	 *	@param address		Url de connection.
   702  	 */
   703  	public function reconnect (address:String):Void
   704  	{
   705  		createSocket();
   706  		connect(address, reconnectPort);
   707  		//!! TODO : Syntaxe. Pas de membre intID : clearInterval(this.intID);
   708  	}
   709  	
   710  	/**
   711  	 *	Gère le changement de groupe.
   712  	 */
   713  	public function handleChangeGroup ():Void
   714  	{
   715  		if (! online && recVer == 2) oldSocket.close();
   716  		changeGroup = false;
   717  		online = true;
   718  	}
   719  
   720  	//--------------------
   721  	// METHODES PRIVEES
   722  	//--------------------
   723  	// Object Socket
   724  	/**
   725  	 *	Gère l'initialisation de la connection au serveur distant.
   726  	 */
   727  	private function createSocket ():Void
   728  	{
   729  		socket = new Socket();
   730  		socket.active = true;
   731  		// Pour éviter une référence circulaire avec l'appel au Singleton (pas encore totalement initialisé)
   732  		var self = this;
   733  		
   734  		// Gestionnaires d'événement du socket
   735  		socket.onConnect = function (success) 
   736  		{
   737  			if (! success) 
   738  			{
   739  				// appel à l'activation object de la fonction englobante.
   740  				var ses = self;
   741  				// Conserve accès private
   742  				if (ses["loginMode"] == "reconnect")
   743  				{
   744  					ses ["connectionBroken"]();
   745  				}else
   746  				{
   747  					ses ["cancelConnect"]("ses-012");
   748  				}
   749  			}
   750  		};
   751  		
   752  		socket.onClose = function ()
   753  		{
   754  			// appel à l'activation object de la fonction englobante.
   755  			var session = self;
   756  			// accès private
   757  			if (this.active) session ["handleClosedSocket"]();
   758  		};
   759  		
   760  		socket.onData = function (str)
   761  		{
   762  			//trace("Données brutes du socket : "+str)
   763  			// appel à l'activation object de la fonction englobante.
   764  			var session = self;
   765  			// accès private
   766  			session ["handleData"](str);
   767  		};
   768  	}
   769  	
   770  	/**
   771  	 *	Gères la connection au serveur.
   772  	 */
   773  	private function connect (addr:String, port:Number):Void
   774  	{
   775  		// Tentative de reconnection
   776  		if (online && loginMode != "reconnect")
   777  		{
   778  			// Logs internes
   779  			_global.oregano.iLog.warn("clj-007","");
   780  			return;
   781  		}
   782  		// Mauvais typage des variables.
   783  		if (typeof(addr) != "string" || typeof(port) != "number")
   784  		{
   785  			// Logs internes
   786  			_global.oregano.iLog.warn("clj-065","");
   787  			return;
   788  		}
   789  		// La connection est-elle active ?
   790  		var ok = socket.connect(addr, port);
   791  		if (! ok)
   792  		{
   793  			// C'est désespéré
   794  			if (loginMode == "reconnect")
   795  			{
   796  				connectionBroken();
   797  			}else
   798  			{
   799  				// Pas de connection active
   800  				cancelConnect("ses-012");
   801  			}
   802  		}
   803  	}
   804  	
   805  	/**
   806  	 *	Connection interrompue.
   807  	 */
   808  	private function handleClosedSocket ():Void
   809  	{
   810  		if (online)
   811  		{
   812  			connectionBroken();
   813  		}else
   814  		{
   815  			// Logs internes
   816  			_global.oregano.iLog.logLocal("INFO","clj-008","");
   817  		}
   818  	}
   819  	
   820  	/**
   821  	 *	Pas de connection active.
   822  	  *	Génère un événement onError aux observateurs.
   823  	 *
   824  	 *	@param errCode		L'identifiant correspond à l'erreur.
   825  	 */
   826  	private function cancelConnect (errCode:String):Void
   827  	{
   828  		var err = new _Error(errCode, loginMode, cache);
   829  		trace(err instanceof _Error);
   830  		reset();
   831  		// Broadcast
   832  		fireEvent("error", "onError", err);
   833  	}
   834  	
   835  	/**
   836  	 *	Connection interrompue.
   837  	  *	Génère un événement onError aux observateurs.
   838  	 */
   839  	private function connectionBroken ():Void
   840  	{
   841  		var err = new _Error("lgt-007", null, null);
   842  		reset();
   843  		// Broadcast
   844  		fireEvent("error", "onLogout", err);
   845  	}
   846  	
   847  	/**
   848  	 *	Gère les messages du serveur.
   849  	 *
   850  	 *	@param str	Les données brutes provenant du serveur.	
   851  	 */
   852  	private function handleData (str:String):Void
   853  	{
   854  		if (str.substr(0, 13) == "#msgkeepAlive")
   855  		{
   856  			// Logs internes
   857  			if (_global.oregano.iLog.infoEnabled()) _global.oregano.iLog.logLocal("INFO", "clj-009", "");
   858  			// resoumet le contenu des données.
   859  			socket.send(str);
   860  			return;
   861  		}
   862  		// Nouvelle enveloppe
   863  		// TODO : Accès Singleton
   864  		var envFactory = EnvelopeFactory.getInstance();
   865  		var env = envFactory.getIncoming(str);
   866  		if (env == null) return;
   867  		// Logs internes
   868  		if (_global.oregano.iLog.infoEnabled()) _global.oregano.iLog.logLocal("INFO","clj-010","str = " + str + "\nenvelope = " + env);
   869  		// TODO : Accès Singleton
   870  		var msgRouter = MessageRouter.getInstance();
   871  		msgRouter.handleIncoming(env);
   872  	}
   873  
   874  	
   875  	//--------------------
   876  	// METHODES STATIQUES
   877  	//--------------------
   878  	/**
   879  	 *	Utilisé dans un contexte littéral
   880  	 *
   881  	 *	@return Une chaine définissant l'objet.
   882  	 */
   883  	public static function toLog():String
   884  	{
   885  		return "[Objet Session]";
   886  	}
   887  	
   888  	/**
   889  	 *	Accès global à la référence du Singleton
   890  	 *	@return	Une référence à la classe
   891  	 */
   892  	public static function getInstance():Session
   893  	{
   894  		if(_instance == undefined)
   895  		{
   896  			//*** Initialisation du framework ***//
   897  			trace("Oregano client version 1.2.0");
   898  			
   899  			// Logs (interne + user) crées par getInstance
   900  			Log.getInstance();
   901  			
   902  			// Initialisation des codes d'erreur.
   903  			org.omus.util._Error.initDescriptions();
   904  			
   905  			var resolver = function (propName) 
   906  			{
   907  				if (_global.org.omus.Log.enablePropLog)
   908  				{
   909  					_global.oregano.iLog.error("clj-001","object = " + this.constructor.toLog() + " - property name = " + propName);
   910  				}
   911  			};
   912  			var cl = [
   913  				org.omus.core.Session,
   914  				org.omus.core.Group,
   915  				org.omus.core.User,
   916  				org.omus.core.Info,
   917  				org.omus.core.Buddies,
   918  				org.omus.core.Locks,
   919  				org.omus.data.DataParser,
   920  				org.omus.data.DataTransformer,
   921  				org.omus.data.MarshalledProperties,
   922  				org.omus.data.Property,
   923  				org.omus.data.ObjectProperty,
   924  				org.omus.data.TableProperty,
   925  				org.omus.data.PropertyLoader,
   926  				org.omus.data.PropertySet,
   927  				org.omus.data.Table,
   928  				org.omus.data.TableBackup,
   929  				org.omus.data.TableDefinition,
   930  				org.omus.data.UpdateSequence,
   931  				org.omus.data.AddRow,
   932  				org.omus.data.ClearTable,
   933  				org.omus.data.RemoveRow,
   934  				org.omus.data.UpdateRow,
   935  				org.omus.db.DbResult,
   936  				org.omus.db.DbTransaction,
   937  				org.omus.db.DbTransactionPart,
   938  				org.omus.msg.Envelope,
   939  				org.omus.msg.EnvelopeFactory,
   940  				org.omus.msg.Mail,
   941  				org.omus.msg.Mailbox,
   942  				org.omus.msg.Message,
   943  				org.omus.msg.MessageRouter,
   944  				org.omus.msg.Messenger,
   945  				org.omus.msg.MessageFilter,
   946  				org.omus.util._Class,
   947  				org.omus.util.Log,
   948  				org.omus.util._Error,
   949  				org.omus.util.ClientInfo,
   950  				org.omus.util.EventDispatcher,
   951  				org.omus.util.EventSource
   952  				];
   953  			var len = cl.length;
   954  			for (var i = 0; i < len; i++) 
   955  			{
   956  				cl[i].prototype.__resolve = resolver;
   957  			}	
   958  			//*** Fin de l'initialisation ***//
   959  			
   960  			_instance = new Session();
   961  		}
   962  		return _instance;
   963  	}
   964  }
   965