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 - 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 Mail
    28   
    29  	@description :
    30  	Messages pesistants. 
    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 : 04/02/05
    38  			- Portage en actionscript 2 pour le
    39  			compile time type checking
    40  			- Pas de return dans un constructeur.
    41  			- Utilisation de l'accès Singleton aux classes User
    42   -------------------------------------------
    43   */
    44  
    45  import org.omus.util.EventDispatcher;
    46  import org.omus.util.iObservable;
    47  import org.omus.util._Error;
    48  
    49  import org.omus.msg.MessageHandler;
    50  import org.omus.msg.iMessageHandler;
    51  import org.omus.msg.Envelope;
    52  import org.omus.msg.EnvelopeFactory;
    53  import org.omus.msg.Mailbox;
    54  import org.omus.msg.Message;
    55  import org.omus.msg.MessageRouter;
    56  
    57  import org.omus.util._Class;
    58  
    59  import org.omus.core.User;
    60  
    61  /**
    62   *	Cette classe gère des objets Mail.
    63   *	Chaque client a deux mailBox : outBox and inBox.
    64   *	La référence à celles-ci s'obtient via User.
    65   *	<p>
    66   *	Evénements auxquels s'abonner :
    67   *	<ul>
    68   *	<li>onSend(mail:Mail)						Généré lorsqu'un Mail a été soumis correctement.
    69   *												_param mail		Copie du Mail envoyé.
    70   *	</li><li>onLoadAttachment(mail:Mail)		Généré lorsque le fichier joint du Mail est fini de charger.
    71   *												_param mail		Copie du Mail envoyé.
    72   *	</li><li>onMark(mail:Mail)					Généré lorsque l'état de lecture du message a été modifié.
    73   *												_param mail		Copie du Mail envoyé.
    74   *	</li><li>onRemove(mail:Mail)				Généré lorsque le mùessage a été supprimé de sa boîte.
    75   *												_param mail		Copie du Mail envoyé.
    76   *	</li><li>onError(mail:Mail, error:_Error)	Généré lors d'une erreur de modification de l'état du Mail.
    77   *												_param mail		Copie du Mail envoyé.
    78   *												_param error		Erreur.
    79   *	</li></ul></p>
    80   *	Cette classe est aggrémentée par composition des méthodes des sources d'événements (EventDispatcher).
    81   *	Elle est aggrémentée par composition de la classe MessageHandler.
    82   *
    83   *	@see org.omus.util.EventDispatcher
    84   *	@see org.omus.util.iObservable
    85   *	@see org.omus.msg.MessageHandler
    86   *	@see org.omus.msg.iMessageHandler
    87   *
    88   *	@see org.omus.core.User#getInBox
    89   *	@see org.omus.core.User#getOutBox
    90   *
    91   *	@author Jens Halm copyright http://www.spicefactory.org/
    92   *	@author erixtekila copyleft http://www.v-i-a.net 
    93   *	@version 1.2.0
    94   */
    95  class org.omus.msg.Mail implements iObservable, iMessageHandler
    96  {
    97  	//--------------------
    98  	// PROPRIETES
    99  	//--------------------
   100  	/**
   101  	 *	Type de boîte contenant le message courant.
   102  	 */
   103  	private var box:Mailbox;
   104  	
   105  	/**
   106  	 *	Conteneur des données du message courant.
   107  	 */
   108  	public var row:Object;
   109  	
   110  	/**
   111  	 *	Conteneur des informations liées au message courant.
   112  	 *	Les objets Mail n'ont pas de body, tout message doit donc être attaché.
   113  	 *	Tous les objets valides du framework peuvent être joints.
   114  	 */
   115  	private var attach:Object;
   116  	
   117  	/**
   118  	 *	Référence au système de génération d'événements.
   119  	 */
   120  	private var _eventSource:EventDispatcher;
   121  	
   122  	/**
   123  	 *	Référence à la classe MessageHandler;
   124  	 */
   125  	private var _messageHandler:MessageHandler;
   126  	
   127  	//--------------------
   128  	// CONSTRUCTEUR
   129  	//--------------------
   130  	/**
   131  	 *	L'objet Mail dispose des méthodes d'EventDispatcher
   132  	 *	et de celles de MessageHandler par composition.
   133  	 *
   134  	 *	@param subj			Sujet du mail.
   135  	 *	@see org.omus.util.EventDispatcher
   136  	 *	@see org.omus.util.iObservable
   137  	 *	@see org.omus.msg.MessageHandler
   138  	 *	@see org.omus.msg.iMessageHandler
   139  	 */
   140  	public function Mail (subj:String) 
   141  	{
   142  		// Composition avec EventDispatcher
   143  		_eventSource = new EventDispatcher();
   144  		// Composition avec MessageHandler
   145  		_messageHandler = new MessageHandler();
   146  		
   147  		// Initialisation des événements
   148  		_messageHandler.initMessageHandler(this);
   149  		
   150  		// Propriétés
   151  		// TODO : Accès Singleton
   152  		var clazz = _Class.getInstance();
   153  		// TODO : Constructeur sans return. if (! _global.org.omus.clazz.checkArguments("new org.omus.Mail",[[subj,"string",true]])) return;
   154  		if (clazz.checkArguments("new org.omus.Mail", [[subj, "string", true]]))
   155  		{
   156  			box = null;
   157  			row = new Object();
   158  			// Contenu du Mail
   159  			row.subject = subj;
   160  			row.dt = new Date();
   161  			row.readFlag = false;
   162  			row.username = null;
   163  			attach = new Object();
   164  
   165  			// Callbacks des envois de messages.
   166  			addHandler("loadMail","handleLoad");
   167  			addHandler("removeMail","handleRemove");
   168  			addHandler("markMail","handleMark");
   169  			addHandler("sendMail","handleSend");
   170  		}
   171  		
   172  		// trace(this+ " installé.");
   173  	}
   174  	
   175  	
   176  	//--------------------
   177  	// METHODES PUBLIQUES
   178  	//--------------------
   179  	/**
   180  	 *	Utilisé dans un contexte littéral
   181  	 *	@return	Une chaine définissant l'objet
   182  	 */
   183  	public function toString():String
   184  	{
   185  		var s = "[Objet Mailbox]";
   186  		s += "\norg.omus.Mail:\n==========\nmsgID = " + row.msgID;
   187  		s += "\nmailbox = " + getMailbox().getType();
   188  		s += "\nsubject = " + getSubject();
   189  		s += "\nsender = " + getSender();
   190  		s += "\nrecipient = " + getRecipient();
   191  		s += "\ndate = " + getDate();
   192  		s += "\nunread = " + isUnread();
   193  		s += "\nattachment = ";
   194  			if (attach == null)
   195  			{
   196  				s += "not loaded";
   197  			} else
   198  			{
   199  				s+= org.omus.util.Log.formatObject(attach, 1);
   200  			}
   201  		return s;
   202  	}
   203  	
   204  	/**
   205  	 *	Initailisation d'un message.
   206  	 */
   207  	public function init (box:Mailbox, row:Object):Void
   208  	{
   209  		this.box = box;
   210  		this.row = row;
   211  		attach = null;
   212  	}
   213  	
   214  	/**
   215  	 *	Renvoie la boîte de réception du message courant.
   216  	 *
   217  	 *	@return		Une référence à Mailbox entrante ou sortante.
   218  	 */
   219  	public function getMailbox ():Mailbox
   220  	{
   221  		return box;
   222  	}
   223  	
   224  	/**
   225  	 *	Renvoie le sujet du message courant.
   226  	 *
   227  	 *	@return		Le sujet sous forme de chaîne.
   228  	 */
   229  	public function getSubject ():String
   230  	{
   231  		return row.subject;
   232  	}
   233  	
   234  	/**
   235  	 *	Renvoie l'envoyeur du message courant.
   236  	 *
   237  	 *	@return		Le nom du membre.
   238  	 */
   239  	public function getSender ():String
   240  	{
   241  		// TODO : Utilise l'accès Singleton à User
   242  		var user = User.getInstance();
   243  		if (box == user.getOutBox() || box == null) 
   244  		{
   245  			return user.getName();
   246  		} else
   247  		{
   248  			return row.username;
   249  		}
   250  	}
   251  	
   252  	/**
   253  	 *	Renvoie le destinataire du message courant.
   254  	 *
   255  	 *	@return			Le nom de l'utilisateur destinataire.
   256  	 */
   257  	public function getRecipient ():String
   258  	{
   259  		// TODO : Utilise l'accès Singleton à User
   260  		var user = User.getInstance();
   261  		if (box == user.getInBox()) 
   262  		{
   263  			return user.getName();
   264  		} else
   265  		{
   266  			return row.username;
   267  		}
   268  	}
   269  	
   270  	/**
   271  	 *	Renvoie le message joint comprenant notamment le body du message.
   272  	 *	Celui-ci se chargera à la demande avec la méthode loadAttachment.
   273  	 *
   274  	 *	@return		L'attachement joint au message courant. Tous les types du framework Oregano sont permis.
   275  	 *	@see org.omus.msg.Mail#loadAttachment
   276  	 */
   277  	public function getAttachment ():Object
   278  	{
   279  		return attach;
   280  	}
   281  
   282  	/**
   283  	 *	Renvoie la date d'envoi du message courant.
   284  	 *
   285  	 *	@return		Une date d'envoi.
   286  	 */
   287  	public function getDate ():Date
   288  	{
   289  		return row.dt;
   290  	}
   291  
   292  	/**
   293  	 *	Renvoie l'état de lecture du message courant.
   294  	 *
   295  	 *	@return		true si le message n'est pas lu.
   296  	 */
   297  	public function isUnread ():Boolean
   298  	{
   299  		return ! row.readFlag;
   300  	}
   301  	
   302  	/**
   303  	 *	Renseigne l'état de chargment de l'attachement du message courant. 
   304  	 *
   305  	 *	@return		true si l'attachement est chargé sur le poste client.
   306  	 */
   307  	public function isLoaded ():Boolean
   308  	{
   309  		return (attach != null);
   310  	}
   311  	
   312  	/**
   313  	 *	Envoi du message courant.
   314  	 *	Une copie est placée automatiquement dans l'outBox.
   315  	 *
   316  	 *	@param recipient		Le nom du destinataire.
   317  	 */
   318  	public function send (recipient:String):Void
   319  	{
   320  		// TODO : Accès Singleton
   321  		var clazz = _Class.getInstance();
   322  		if (! clazz.checkArguments("send", [[recipient, "string", true]])) return;
   323  		
   324  		// Message
   325  		var msg:Message = new Message("sendMail");
   326  		var attach = msg.getAttachment();
   327  		attach.username = recipient;
   328  		attach.subject = row.subject;
   329  		attach.message = this.attach;
   330  		
   331  		// TODO : Accès Singleton
   332  		var envFactory:EnvelopeFactory = EnvelopeFactory.getInstance();
   333  		var env = envFactory.getOutgoing(msg,"mailbox");
   334  		//  TODO : Accès Singleton
   335  		var msgRouter:MessageRouter = MessageRouter.getInstance();
   336  		msgRouter.handleOutgoing(env, this, "send", arguments, null);
   337  	}
   338  	
   339  	/**
   340  	 *	Charge le message joint du Mail courant.
   341  	 */
   342  	public function loadAttachment ():Void
   343  	{
   344  		if (box == null)
   345  		{
   346  			// Logs internes
   347  			_global.oregano.iLog.error("clj-043", "");
   348  			return;
   349  		}
   350  		var env = getMessage("loadMail");
   351  		//  TODO : Accès Singleton
   352  		var msgRouter = MessageRouter.getInstance();
   353  		msgRouter.handleOutgoing(env, this, "send", arguments, null);
   354  	}
   355  	
   356  	/**
   357  	 *	Supprime ce message de la boîte auquel il appartient.
   358  	 */
   359  	public function remove ():Void
   360  	{
   361  		if (box == null)
   362  		{
   363  			// Logs internes
   364  			_global.oregano.iLog.error("clj-044","");
   365  			return;
   366  		}
   367  		var env = getMessage("removeMail");
   368  		//  TODO : Accès Singleton
   369  		var msgRouter = MessageRouter.getInstance();
   370  		msgRouter.handleOutgoing(env, this, "remove", arguments, null);
   371  	}
   372  	
   373  	/**
   374  	 *	Signale le message comme lu / non lu.
   375  	 *
   376  	 *	@param asRead		true si lu, false pour non lu.
   377  	 */
   378  	public function mark (asRead:Boolean):Void
   379  	{
   380  		// TODO : Accès Singleton
   381  		var clazz = _Class.getInstance();
   382  		if (! clazz.checkArguments("mark", [[asRead, "boolean", true]])) return;
   383  		
   384  		if (box == null)
   385  		{
   386  			// Logs internes
   387  			_global.oregano.iLog.error("clj-045", "");
   388  			return;
   389  		}
   390  		var env = getMessage("markMail");
   391  		env.getMessage().getAttachment().asRead = asRead;
   392  		// TODO : Accès Singleton.
   393  		var msgRouter = MessageRouter.getInstance();
   394  		msgRouter.handleOutgoing(env, this, "mark", arguments, null);
   395  	}
   396  	
   397  	//*** Implémentation de iObservable ***\
   398  	/**
   399  	 *	Notifie les observateurs d'un événement.
   400  	 *
   401  	 *	@param logLevel Une chaine caractérisant le niveau de logging de l'information.
   402  	 *	@param eventName Nom de l'événement.
   403  	 *	@param arg1		[option] Autant de paramêtres de voulu.
   404  	 */
   405  	private function fireEvent (logLevel:String, eventName:String):Void
   406  	{
   407  		_eventSource.fireEvent.apply (_eventSource, arguments);
   408  	}
   409  	
   410  	/**
   411  	 *	Ajoute un nouvel observateur.
   412  	 * 
   413  	 *	@param		listener Référence de l'observateur.
   414  	 *	@return Un booléen indiquant la réussite de l'opération.
   415  	 */
   416  	public function addListener (listener:Object):Boolean
   417  	{
   418  		return _eventSource.addListener(listener);
   419  	}
   420  	
   421  	/**
   422  	 *	Supprime un observateur.
   423  	 *
   424  	 *	@param		listener Référence de l'observateur.
   425  	 *	@return Un booléen indiquant la réussite de l'opération.
   426  	 */
   427  	public function removeListener (listener:Object):Boolean
   428  	{
   429  		return _eventSource.removeListener(listener);
   430  	}
   431  	
   432  	/**
   433  	 *	Supprime tous les abonnés.
   434  	 */
   435  	public function removeAllListeners ():Void
   436  	{
   437  		_eventSource.removeAllListeners();
   438  	}
   439  	
   440  	/**
   441  	 *	Retourne le nombre d'observateurs.
   442  	 *
   443  	 *	@return Le nombre d'observateurs enregistrés.
   444  	 */
   445  	public function countListeners ():Number
   446  	{
   447  		return _eventSource.countListeners();
   448  	}
   449  	
   450  	
   451  	//*** Implémentation de iMessageHandler ***\\
   452  	/**
   453  	 *	Active la gestion d'un type de message par accusé de réception
   454  	 *	en fonction du contenu de son enveloppe.
   455  	 *
   456  	 * @param env		Une référence à l'enveloppe.
   457  	 */
   458  	public function handleMessage (env:Envelope):Void
   459  	{
   460  		_messageHandler.handleMessage(env);
   461  	}
   462  	
   463  	/**
   464  	 *	Rajoute un gestionnaire chargé d'intercepter 
   465  	 *	la réponse du serveur suite à un message soumis.
   466  	 *	Forme d'accusé de réception (callback).
   467  	 *
   468  	 *	@param		subject Le type de message.
   469  	 *	@param		methodName Le nom de l'événement gérant un type de message. 
   470  	 */
   471  	public function addHandler (subject:String, methodName:String):Void
   472  	{
   473  		_messageHandler.addHandler (subject, methodName);
   474  	}
   475  
   476  		
   477  	// Callbacks des messges Message avec accusés de réception
   478  	/**
   479  	 *	Gestionnaire de l'accusé de réception du message de la soumission du Mail.
   480  	 *	Génère un événement onSend ou onError aux observateurs.
   481  	 *
   482  	 *	@param env		Enveloppe du message retourné.
   483  	 */
   484  	private function handleSend (env:Envelope):Void
   485  	{
   486  		var attach = env.getMessage().getAttachment();
   487  		var errCode = attach.error;
   488  		if (errCode == "ok") 
   489  		{
   490  			var newMail = new Mail("");
   491  			var newRow = {
   492  							subject:row.subject,
   493  							username:attach.username,
   494  							dt:attach.dt,
   495  							msgID:attach.msgID,
   496  							readFlag:false
   497  						};
   498  			// TODO : Accès Singleton
   499  			var user = User.getInstance();
   500  			newMail.init(user.getOutBox(), newRow);
   501  			user.getOutBox().addMail(newMail, newMail.row.msgID);
   502  			// Broadcast
   503  			fireEvent("info", "onSend", newMail);
   504  		} else 
   505  		{
   506  			var err = new _Error(errCode, "send", new Array());
   507  			// Broadcast
   508  			fireEvent("error", "onError", this, err);
   509  		}
   510  	}
   511  	
   512  	/**
   513  	 *	Gestionnaire de l'accusé de réception du message de réception du fichier joint.
   514  	 *	Génère un événement onLoadAttachment ou onError aux observateurs.
   515  	 *
   516  	 *	@param env		Enveloppe du message retourné.
   517  	 */
   518  	private function handleLoad (env:Envelope):Void
   519  	{
   520  		var attach = env.getMessage().getAttachment();
   521  		var errCode = attach.error;
   522  		if (errCode == "ok")
   523  		{
   524  			var t = attach.tables.result;
   525  			this.attach = t.getRow(0).message;
   526  			//this.attach = attach.fields.message;
   527  			// Broadcast
   528  			fireEvent("info", "onLoadAttachment", this);
   529  			attach = null;
   530  		} else
   531  		{
   532  			var err = new _Error(errCode, "loadAttachment", new Array());
   533  			// Broadcast
   534  			this.fireEvent("error","onError",this,err);
   535  		}
   536  	}
   537  	
   538  	
   539  	/**
   540  	 *	Gestionnaire de l'accusé de réception du message de suppresion du message de la boîte.
   541  	 *	Génère un événement onRemove ou onError aux observateurs.
   542  	 *
   543  	 *	@param env		Enveloppe du message retourné.
   544  	 */
   545  	private function handleRemove (env:Envelope):Void
   546  	{
   547  		var attach = env.getMessage().getAttachment();
   548  		var errCode = attach.error;
   549  		if (errCode == "ok")
   550  		{
   551  			box._removeMail(this, row.msgID);
   552  			box = null;
   553  			// Broadcast
   554  			fireEvent("info", "onRemove", this);
   555  		} else 
   556  		{
   557  			var err = new _Error(errCode, "remove", new Array());
   558  			// Broadcsat
   559  			fireEvent("error", "onError", this, err);
   560  		}
   561  	}
   562  	
   563  	/**
   564  	 *	Gestionnaire de l'accusé de réception du message de modification de statut de lecture.
   565  	 *	Génère un événement onMark ou onError aux observateurs.
   566  	 *
   567  	 *	@param env		Enveloppe du message retourné.
   568  	 */
   569  	private function handleMark (env:Envelope):Void
   570  	{
   571  		var attach = env.getMessage().getAttachment();
   572  		var errCode = attach.error;
   573  		var asRead:Boolean;
   574  		if (box.getType() == "outBox") 
   575  		{
   576  			asRead = attach.asRead;
   577  		} else 
   578  		{
   579  			//  TODO : Accès Singleton
   580  			var msgRouter = MessageRouter.getInstance();
   581  			asRead = msgRouter.getCache(env.getID(), "args")[0];
   582  		}
   583  		if (errCode == "ok") 
   584  		{
   585  			var old = row.readFlag;
   586  			if (old && ! asRead) 
   587  			{
   588  				box.unread++;
   589  			} else if (! old && asRead)
   590  			{
   591  				box.unread--;
   592  			} else
   593  			{
   594  				return;
   595  			}
   596  			row.readFlag = asRead;
   597  			// Broadcast
   598  			fireEvent("info", "onMark", this);
   599  		} else 
   600  		{
   601  			var err = new _Error(errCode, "mark", [asRead]);
   602  			// Broadcast
   603  			fireEvent("error", "onError", this, err);
   604  		}
   605  	}
   606  	// Fin des callbacks des messges Message avec accusés de réception
   607  
   608  	
   609  	//--------------------
   610  	// METHODES PRIVEES
   611  	//--------------------
   612  	/**
   613  	 *	Modifie l'état du message courant.
   614  	 *
   615  	 *	@param subject		Etat du message à modifier : removeMail…
   616  	 *	@return				Enveloppe du message à synchoniser avec le serveur.
   617  	 */
   618  	private function getMessage (subject:String):Envelope
   619  	{
   620  		var msg = new Message(subject);
   621  		var attach = msg.getAttachment();
   622  		attach.box = box.type;
   623  		attach.msgID = row.msgID;
   624  		
   625  		// TODO : Accès Singleton
   626  		var envFactory = EnvelopeFactory.getInstance();
   627  		return envFactory.getOutgoing(msg, "mailbox");
   628  	}
   629  	
   630  	//--------------------
   631  	// METHODES STATIQUES
   632  	//--------------------
   633  	/**
   634  	 *	Utilisé dans un contexte littéral
   635  	 *
   636  	 *	@return Une chaine définissant l'objet.
   637  	 */
   638  	public static function toLog():String
   639  	{
   640  		return "[Objet Mail]";
   641  	}
   642  
   643  }
   644