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 Mailbox 28 29 @description : 30 Aggège des objets Mail, conteneurs de 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 : 03/02/05 38 - Portage en actionscript 2 pour le 39 compile time type checking 40 - fonction sort modifiée en utilisant l'activation object 41 pour l'accès aux variables locales d'une fonction interne. 42 ------------------------------------------- 43 */ 44 45 import org.omus.util.EventDispatcher; 46 import org.omus.util.iObservable; 47 import org.omus.util._Error; 48 import org.omus.util._Class; 49 50 import org.omus.msg.MessageHandler; 51 import org.omus.msg.iMessageHandler; 52 import org.omus.msg.Mail; 53 import org.omus.msg.Message; 54 import org.omus.msg.MessageRouter; 55 import org.omus.msg.Envelope; 56 import org.omus.msg.EnvelopeFactory; 57 58 import org.omus.data.Table; 59 import org.omus.data.TableDefinition; 60 61 import org.omus.core.User; 62 63 /** 64 * Cette classe gère des objets Mail. 65 * Chaque client a deux mailBox : outBox and inBox. 66 * La référence à celles-ci s'obtient via User. 67 * <p> 68 * Evénements auxquels s'abonner : 69 * <ul> 70 * <li>onLoad(box:Mailbox) Généré lorsque tous les mails sont chargés. 71 * _param box Référence à la boîte. 72 * </li><li>onNewMail(box:Mailbox) Généré lorsqu'un nouveau Mail est reçu par le serveur. Il faut invoquer load pour le charger. 73 * _param box Référence à la boîte. 74 * </li><li>onRemoveAll(box:Mailbox) Généré lorsque tous les Mails ont été supprimés. 75 * _param box Référence à la boîte. 76 * </li><li>onError(error:_Error) Erreur survenue au chargement ou suppression de tous les mails. 77 * _param box Référence à la boîte. 78 * </li></ul></p> 79 * Cette classe est aggrémentée par composition des méthodes des sources d'événements (EventDispatcher). 80 * Elle est aggrémentée par composition de la classe MessageHandler. 81 * 82 * @see org.omus.util.EventDispatcher 83 * @see org.omus.util.iObservable 84 * @see org.omus.msg.MessageHandler 85 * @see org.omus.msg.iMessageHandler 86 * 87 * @see org.omus.core.User#getInBox 88 * @see org.omus.core.User#getOutBox 89 * 90 * @author Jens Halm copyright http://www.spicefactory.org/ 91 * @author erixtekila copyleft http://www.v-i-a.net 92 * @version 1.2.0 93 */ 94 class org.omus.msg.Mailbox implements iObservable, iMessageHandler 95 { 96 //-------------------- 97 // PROPRIETES 98 //-------------------- 99 /** 100 * Inbox ou Outbox 101 */ 102 public var type:String; 103 104 /** 105 * Classement des messages. 106 */ 107 private var order:Array; 108 109 /** 110 * Nombre de mail total. 111 */ 112 private var total:Number; 113 114 /** 115 * Nombre de mail non lus. 116 */ 117 public var unread:Number; 118 119 /** 120 * TODO 121 */ 122 private var maxMsgID:Number; 123 124 /** 125 * Nombre de mail déjà chargés. 126 */ 127 private var loaded:Number; 128 129 /** 130 * Dernier identifiant de Mail de la liste. 131 */ 132 private var msgTable:Table; 133 134 /** 135 * Indexation des identifiants de mail. 136 */ 137 private var idMap:Object; 138 139 /** 140 * Référence au système de génération d'événements. 141 */ 142 private var _eventSource:EventDispatcher; 143 144 /** 145 * Référence à la classe MessageHandler; 146 */ 147 private var _messageHandler:MessageHandler; 148 149 //-------------------- 150 // CONSTRUCTEUR 151 //-------------------- 152 /** 153 * L'objet Mailbox dispose des méthodes d'EventDispatcher 154 * et de celles de MessageHandler par composition. 155 * 156 * @param type Type de boîte : "in" / "out". 157 * @see org.omus.util.EventDispatcher 158 * @see org.omus.util.iObservable 159 * @see org.omus.msg.MessageHandler 160 * @see org.omus.msg.iMessageHandler 161 */ 162 public function Mailbox (type:String) 163 { 164 // Composition avec EventDispatcher 165 _eventSource = new EventDispatcher(); 166 // Composition avec MessageHandler 167 _messageHandler = new MessageHandler(); 168 169 // Initialisation des événements 170 _messageHandler.initMessageHandler(this); 171 172 // Propriétés 173 this.type = type; 174 // Classement par défaut 175 order = ["dt", false]; 176 177 // Callbacks des envois de messages. 178 addHandler("loadHeaders","handleLoadHeaders"); 179 addHandler("removeAll","handleRemoveAll"); 180 addHandler("newMail","handleNewMail"); // inBox only 181 addHandler("markMail","handleMarkMail"); // outBox only 182 183 // trace(this+ " installé."); 184 } 185 186 187 //-------------------- 188 // METHODES PUBLIQUES 189 //-------------------- 190 /** 191 * Utilisé dans un contexte littéral 192 * @return Une chaine définissant l'objet 193 */ 194 public function toString():String 195 { 196 var s = "[Objet Mailbox]"; 197 s += "\norg.omus.Mailbox:\n=============\ntype = " + type; 198 s += "\nmails total: " + total; 199 s += "\nmails unread: " + unread; 200 s += "\nmails loaded: " + loaded; 201 return s; 202 } 203 204 /** 205 * Initialisation d'une boîte aux lettres. 206 * 207 * @param totalMail Nombre de mail maximal. 208 * @param unreadMail Nombre de mail non lus. 209 */ 210 public function init (totalMail:Number, unreadMail:Number):Void 211 { 212 total = totalMail; 213 unread = unreadMail; 214 maxMsgID = 0; 215 loaded = 0; 216 217 if (total > 0) 218 { 219 msgTable = null; 220 } else 221 { 222 var def = new TableDefinition(); 223 def.addColumn("msgID", "int"); 224 def.addColumn("username", "string"); 225 def.addColumn("subject", "string"); 226 def.addColumn("dt", "date"); 227 def.addColumn("readFlag", "boolean"); 228 msgTable = new Table(def); 229 } 230 idMap = new Object(); 231 } 232 233 /** 234 * Renvoie le type de la boîte. 235 * 236 * @return Le type de boîte : "outBox" ou "inBox" 237 */ 238 public function getType ():String 239 { 240 return type + "Box"; 241 } 242 243 /** 244 * Renvoie le nombre total de mails de la boîte. 245 * 246 * @return Le nombre toal de mail présents. 247 */ 248 public function getTotal ():Number 249 { 250 return total; 251 } 252 253 /** 254 * Renvoie le nombre de mails non lus. 255 * 256 * @return Nombre de messages non lus. 257 */ 258 public function getUnread ():Number 259 { 260 return unread; 261 } 262 263 /** 264 * Renvoie un nombre de Mail chargés. 265 * 266 * @return Une quantité de mails chargés. 267 */ 268 public function getLoaded ():Number 269 { 270 return loaded; 271 } 272 273 /** 274 * Renvoie le mail selon son index. 275 * Par défaut, ils sont classés par date. o correspond au plus ancien Mail. 276 * 277 * @param index Identifiant du message. 278 * @return Une révérence à Mail. 279 * @see org.omus.msg.Mail 280 */ 281 public function getMail (index:Number):Mail 282 { 283 var row = msgTable.getRow(index); 284 if (row == null) return null; 285 return idMap["m" + row.msgID]; 286 } 287 288 /** 289 * Charge tous les Mails valables. 290 * Génère une événement onLoad aux observateurs. 291 */ 292 public function load ():Void 293 { 294 if (loaded >= total) 295 { 296 fireEvent("info", "onLoad", this); 297 return; 298 } 299 // Chargement lancé. 300 var msg = new Message("loadHeaders"); 301 var attach = msg.getAttachment(); 302 attach.box = type; 303 attach.msgID = maxMsgID; 304 // TODO : Accès Singleton 305 var envFactory = EnvelopeFactory.getInstance(); 306 var env = envFactory.getOutgoing(msg, "mailbox"); 307 // TODO : Accès Singleton 308 var msgRouter = MessageRouter.getInstance(); 309 msgRouter.handleOutgoing(env, this, "load", arguments, null); 310 } 311 312 /** 313 * Supprime tous les messages de la boîte courante. 314 */ 315 public function removeAll ():Void 316 { 317 var msg = new Message("removeAll"); 318 var attach = msg.getAttachment(); 319 attach.box = type; 320 // TODO : Accès Singleton 321 var envFactory = EnvelopeFactory.getInstance(); 322 var env = envFactory.getOutgoing(msg, "mailbox"); 323 // TODO : Accès Singleton 324 var msgRouter = MessageRouter.getInstance(); 325 msgRouter.handleOutgoing(env, this, "removeAll", arguments, null); 326 } 327 328 /** 329 * Classe les mails par date. 330 * 331 * @return ascending true si classement par ordre croissant. 332 */ 333 public function sortByDate (ascending:Boolean):Void 334 { 335 // TODO : Accès Singleton 336 var clazz = _Class.getInstance(); 337 if (! clazz.checkArguments("org.omus.Mailbox.sortByDate", [[ascending, "boolean", true]])) return; 338 sort("dt", ascending); 339 } 340 341 /** 342 * Classe les malis par envoyeur. 343 * 344 * @param ascending true si classmeent par ordre croissant. 345 */ 346 public function sortBySender (ascending:Boolean):Void 347 { 348 // TODO : Accès Singleton 349 var clazz = _Class.getInstance(); 350 if (! clazz.checkArguments("org.omus.Mailbox.sortBySender", [[ascending, "boolean", true]])) return; 351 sort("username",ascending); 352 } 353 354 /** 355 * Classe les mails par sujet. 356 * 357 * @param ascending true si classement dans l'ordre croissant. 358 */ 359 public function sortBySubject (ascending:Boolean):Void 360 { 361 // TODO : Accès Singleton 362 var clazz = _Class.getInstance(); 363 if (! clazz.checkArguments("org.omus.Mailbox.sortBySubject", [[ascending, "boolean", true]])) return; 364 sort("subject", ascending); 365 } 366 367 /** 368 * Supprime une mail de la boîte courante. 369 * 370 * @param mail Référence à l'objet Mail à supprimer. 371 * @param msgID Identifiant du Mail. 372 */ 373 public function _removeMail (mail:Mail, msgID:Number):Void 374 { 375 delete idMap["m" + msgID]; 376 377 var tb = msgTable; 378 var cnt = tb.size(); 379 for (var i = 0; i < cnt; i++) 380 { 381 if (tb.getRow(i).msgID == msgID) 382 { 383 tb.removeRow(i); 384 break; 385 } 386 } 387 388 loaded--; 389 total--; 390 if (mail.isUnread()) unread--; 391 } 392 393 /** 394 * Rajoute un Mail à la boîte courante. 395 * 396 * @param mail Référence à l'objet Mail à supprimer. 397 * @param msgID Identifiant du Mail. 398 */ 399 public function addMail (mail:Mail, msgID:Number):Void 400 { 401 // TODO : Pourquoi pas après if(loaded < total) ? 402 total++; 403 unread++; 404 if (loaded < total) return; 405 406 idMap["m" + msgID] = mail; 407 msgTable.addRow(mail.row); 408 409 // Reclasse tous les messages. 410 sort(order[0], order[1]); 411 loaded++; 412 } 413 414 //*** Implémentation de iObservable ***\ 415 /** 416 * Notifie les observateurs d'un événement. 417 * 418 * @param logLevel Une chaine caractérisant le niveau de logging de l'information. 419 * @param eventName Nom de l'événement. 420 * @param arg1 [option] Autant de paramètres de voulu. 421 */ 422 private function fireEvent (logLevel:String, eventName:String):Void 423 { 424 _eventSource.fireEvent.apply (_eventSource, arguments); 425 } 426 427 /** 428 * Ajoute un nouvel observateur. 429 * 430 * @param listener Référence de l'observateur. 431 * @return Un booléen indiquant la réussite de l'opération. 432 */ 433 public function addListener (listener:Object):Boolean 434 { 435 return _eventSource.addListener(listener); 436 } 437 438 /** 439 * Supprime un observateur. 440 * 441 * @param listener Référence de l'observateur. 442 * @return Un booléen indiquant la réussite de l'opération. 443 */ 444 public function removeListener (listener:Object):Boolean 445 { 446 return _eventSource.removeListener(listener); 447 } 448 449 /** 450 * Supprime tous les abonnés. 451 */ 452 public function removeAllListeners ():Void 453 { 454 _eventSource.removeAllListeners(); 455 } 456 457 /** 458 * Retourne le nombre d'observateurs. 459 * 460 * @return Le nombre d'observateurs enregistrés. 461 */ 462 public function countListeners ():Number 463 { 464 return _eventSource.countListeners(); 465 } 466 467 468 //*** Implémentation de iMessageHandler ***\\ 469 /** 470 * Active la gestion d'un type de message par accusé de réception 471 * en fonction du contenu de son enveloppe. 472 * 473 * @param env Une référence à l'enveloppe. 474 */ 475 public function handleMessage (env:Envelope):Void 476 { 477 _messageHandler.handleMessage(env); 478 } 479 480 /** 481 * Rajoute un gestionnaire chargé d'intercepter 482 * la réponse du serveur suite à un message soumis. 483 * Forme d'accusé de réception (callback). 484 * 485 * @param subject Le type de message. 486 * @param methodName Le nom de l'événement gérant un type de message. 487 */ 488 public function addHandler (subject:String, methodName:String):Void 489 { 490 _messageHandler.addHandler (subject, methodName); 491 } 492 493 494 // Callbacks des messges Message avec accusés de réception 495 /** 496 * Gestionnaire de l'accusé de réception du message de chargement des entêtes de Mail. 497 * Génère un événement onLoad ou onError aux observateurs. 498 * 499 * @param env Enveloppe du message retourné. 500 */ 501 private function handleLoadHeaders (env:Envelope):Void 502 { 503 var attach = env.getMessage().getAttachment(); 504 var errCode = attach.error; 505 if (errCode == "ok") 506 { 507 var table = attach.tables.result; 508 if (msgTable == null) 509 { 510 msgTable = table; 511 } else 512 { 513 msgTable.addAllRows(table); 514 } 515 sort(order[0], order[1]); 516 517 var cnt = table.size(); 518 var map = idMap; 519 var row:Object; 520 var mail:Mail; 521 var id:Number; 522 for (var i = 0; i < cnt; i++) 523 { 524 row = table.getRow(i); 525 id = row.msgID; 526 if (id > maxMsgID) maxMsgID = id; 527 mail = new Mail(""); 528 mail.init(this, row); 529 map["m" + row.msgID] = mail; 530 } 531 532 loaded = msgTable.size(); 533 if (total < loaded) 534 { 535 // some newMail messages have been lost 536 unread += (loaded - total); 537 total = loaded; 538 // Logs internes 539 _global.oregano.iLog.error("clj-069"); 540 } 541 fireEvent("info", "onLoad", this); 542 } else 543 { 544 var err = new _Error(errCode, "load", new Array()); 545 fireEvent("error", "onError", this, err); 546 } 547 } 548 549 /** 550 * Gestionnaire de l'accusé de réception du message de suppression des Mails. 551 * Génère un événement onRemoveAll ou onError aux observateurs. 552 * 553 * @param env Enveloppe du message retourné. 554 */ 555 private function handleRemoveAll (env:Envelope):Void 556 { 557 var errCode = env.getMessage().getAttachment().error; 558 if (errCode == "ok") 559 { 560 init(0,0); 561 fireEvent("info", "onRemoveAll", this); 562 } else 563 { 564 var err = new _Error(errCode, "removeAll", new Array()); 565 fireEvent("error", "onError", this, err); 566 } 567 } 568 569 /** 570 * Gestionnaire de l'accusé de réception du message d'ajout d'un nouveau Mail. 571 * inBox only 572 * Génère un événement onNewMail aux observateurs. 573 * 574 * @param env Enveloppe du message retourné. 575 */ 576 private function handleNewMail (env:Envelope):Void 577 { 578 total++; 579 unread++; 580 fireEvent("info", "onNewMail", this); 581 } 582 583 /** 584 * Gestionnaire de l'accusé de réception du message d'ajout d'un nouveau Mail. 585 * outBox only 586 * Génère un événement onNewMail aux observateurs. 587 * 588 * @param env Enveloppe du message retourné. 589 */ 590 private function handleMarkMail (env:Envelope):Void 591 { 592 var msgID = env.getMessage().getAttachment().msgID; 593 var mail = idMap["m" + msgID]; 594 if (mail != undefined) mail.handleMessage(env); 595 } 596 597 // Fin des callbacks des messges Message avec accusés de réception 598 599 600 //-------------------- 601 // METHODES PRIVEES 602 //-------------------- 603 /** 604 * Fonction général de classement des mails. 605 * 606 * @param propName Nom de la catégorie. 607 * @param asc true si classement par ordre croissant. 608 */ 609 private function sort (propName:String, asc:Boolean):Void 610 { 611 // TODO : Suppression des membres statiques au profit de l'utilisation de l'activation object. 612 // org.omus.Mailbox.propName = propName; 613 // org.omus.Mailbox.asc = asc; 614 order = [propName, asc]; 615 if (msgTable == null) return; 616 617 // fonction de tri 618 var func = function (row1,row2) 619 { 620 var p1 = row1[propName]; 621 var p2 = row2[propName]; 622 if (p1 == p2) return 0; 623 var bool = (p1 < p2); 624 if ((bool && asc) || (! bool && ! asc)) return -1; 625 return 1; 626 }; 627 628 msgTable.rowList.sort(func); 629 msgTable.rowIDMap = null; 630 } 631 632 //-------------------- 633 // METHODES STATIQUES 634 //-------------------- 635 /** 636 * Utilisé dans un contexte littéral 637 * 638 * @return Une chaine définissant l'objet. 639 */ 640 public static function toLog():String 641 { 642 return "[Objet Mailbox]"; 643 } 644 645 /** 646 * Gestionnaire d'accusé de réception émanant directement de MessageRouter 647 * et chargé de redistribuer les messages entre les propriétés d'un groupe ou d'un utilisateur. 648 * TODO : Compileur MMC 2004 n'accepte pas une méthode de classe et d'instance ayant le même nom. 649 * 650 * @param env Enveloppe du message. 651 * @see org.omus.msg.MessageRouter#handleIncoming 652 */ 653 public static function handleIncomingMessage (env:Envelope):Void 654 { 655 var subj = env.getMessage().getSubject(); 656 // TODO : Accès Singleton 657 var user = User.getInstance(); 658 if (subj == "newMail") 659 { 660 user.getInBox().handleMessage(env); 661 } else if (subj == "markMail") 662 { 663 user.getOutBox().handleMessage(env); 664 } else 665 { 666 _global.org.omus.msgRouter.unknownMsgType(env); 667 } 668 } 669 670 } 671