La tOiLeB
#!/bin/sh
# the next line restarts using tclsh \
exec wish "$0" "$@"
#
# Partie client de l'outil d'exploitation
#
# Eric BURGHARD 28/12/2001

package require templates 1.0
package require BWidget 1.3.1
package require dp 4.0

# charge les données de configuration locales du client
source clicfg.tcl
proc NodeSelected { tree node } {
	# redirige la procédure de selection d'un noeud vers la procédure de selection de l'objet associé
	global of1 mf1
	
	# récupère l'objet associé au noeud
	set inst [$tree itemcget $node -data]
	
	# vide la barre des buttons
	set frame [$of1 getframe]
	foreach widget [winfo children $frame] {
	 destroy $widget
	}
	# affichage de l'inspector lié à l'objet
	$inst Inspector $frame
	
	# vide la barre des indicateurs
	foreach widget [winfo children $mf1.status.indf] {
	 destroy $widget
	}
	# affiche la barre d'états lié à l'objet
	foreach lib_i [$inst Stat] {
	 $mf1 addindicator -text "$lib_i"
	}
	
	# appelle la procédure de selection lié à l'objet
	Node CurrentNode $inst
	$inst Select
}
proc NodeOpened node {
	# redirige la procédure d'ouverture d'un noeud vers la procédure d'ouverture de l'objet associé
	global t1
	
	# récupère l'objet associé au noeud
	set inst [$t1 itemcget $node -data]
	
	# appelle la procédure de selection
	$inst Open
}
proc NodeClosed node {
	# redirige la procédure de fermeture d'un noeud vers la procédure de fermeture de l'objet associé
	global t1
	
	# récupère l'objet associé au noeud
	set inst [$t1 itemcget $node -data]
	
	# appelle la procédure de selection de l'objet
	$inst Close
}
# Node est la superclasse de tous les elements de l'arbre d'exploitation
TClass subclass Node

Node Templates IntrTemplate

Node private currentnode ""

Node classmethod CurrentNode {inst} {
 set [privatevar Node currentnode] $inst
}

# constructeur de noeuds
# -> label: label du noeud
#    type: [static|dynamic]
#
Node method init {label type} {
 $object private label $label
 $object private type $type
 $object private tree ""
 $object private node ""
 $object private opened 0
 
 return [super init]
}

Node method destroy {} {
 return [super destroy]
}

# méthode pour insérer une instance de type Node dans un arbre Bwidget::Tree
# <- tree: instance BWidget::Tree
#    parent: position 
#    kind: {static, dynamic}, type d'initialisation
#
Node method InitTree {tree parent kind} {
 $object SetNode $tree $parent
 $object InsertChildren $kind
}

Node method InsertChildren {kind} {
 private $object tree type

 # l'objet ne doit pas etre une feuille et son type doit etre conforme au type de l'initialisation 
 if {(! [$object IsTerminal]) && "$type" == "$kind"} {
  foreach child_i [$object Children] {
   # appel récursif à InitTree pour chaque descendant. L'initialisation dynamique se fait étape par étape
   $child_i InitTree $tree [$object Node] static
  }
 }
}

# méthode qui retourne la liste des descendants a initialiser dans l'arbre
# <- racine: racine de l'arbre à partir de laquelle les descendants seront rajoutés
#
Node method Children {} {
}

# méthode permettant de creer un ensemble de widgets pour controler le noeud
# -> chemin du container dans la hierachie des widgets
#
Node method Inspector {cont} {}

# méthode énumératrice d'états
# <- liste d'états a rajouter dans la barre
#
Node method Stat {} {
 private $object tree node opened
 
 set stat ""
 if {$opened} {
  set stat [list "[llength [$tree nodes $node]] éléments"]
 }
 return $stat
}

# méthode appellée a la sélection du noeud
#
Node method Select {} {}

# méthode appellée à l'ouverture du noeud (Initialisation dynamique de la branche)
#
Node method Open {} {
 private $object type opened

 if {$type == "dynamic"} {
  $object InsertChildren dynamic
 }
 set opened 1
}

# méthode appellée à la fermeture d'un noeud (Vider la branche si son contenu est dynamique)
#
Node method Close {} {
 private $object type opened

 # detruit tous les descendants pour une branche de type "dynamic"
 if {$type == "dynamic"} {
  $object DeleteChildren
 }
 set opened 0
}

# méthode appellée pour supprimer tous les objets descendants de $object dans $tree 
#
Node method DeleteChildren {} {
 private $object tree

 foreach node_i [$tree nodes [$object Node]] {
  # récupère l'objet associé au noeud
  set inst [$tree itemcget $node_i -data]
  # Efface récursivement l'arbre (parcours en profondeur)
  $inst DeleteChildren
  # détruit l'instance
  $inst destroy
  # efface le noeud de l'arbre
  $tree delete $node_i
 }
}

# méthode determinant si le noeud a des descendants dans l'arbre
# <- [0,1]
Node method IsTerminal {} {
 # noeud terminal par défaut
 return 1
}

Node method Label {} {
 return [$object private label]
}

# méthode permettant de lier $object à une position dans un arbre $tree
# -> tree: instance de BWidget::Tree
#    parent: position dans l'arbre $tree
#
Node method SetNode {t parent} {
 private $object tree node

 set tree $t
 # Nomme l'objet dans l'arbre à partir du nom du père $args et du nombre de ses descendants directs
 set node $parent.[llength [$tree nodes $parent]]
 $tree insert end $parent $node -drawcross [expr {[$object IsTerminal] ? "never" : "allways"}] \
                                -text [$object Label] \
                                -data $object
 return $node
}

# accésseur à la variable node
#
Node method Node {} {
 return [$object private node]
}

# méthode retournant le père du noeud
#
Node method Parent {} {
 set node [$object Node]
 set idx [string last . $node]
 incr idx -1
 return [string range $node 0 $idx] 
}

# méthode pour ajouter une barre de bouttons dans le container $cont
# -> cont: conteneur
#    libproc: libellé boutton, procédure, (*)
#
Node method AddButtonBar {cont libproc} {
 set i 0
 foreach {lib_i proc_i} $libproc {
  button $cont.b$i -text $lib_i -command $proc_i
  pack $cont.b$i -fill x -padx 2 -pady 2
  incr i
 }
}
Node subclass Site

# Un object Site est lié à un objet Host
Site method init {label host} {
 $object private host $host
 return [super init $label static]
}

Site method Children {} {
 # Les descendants sont les bases a gérer dans l'arbre
 private $object host

 set res ""
 set i 0
 foreach {base_sid_i site_i} [$host RPC GetSites] {
  lappend res [Base new $object.$i $base_sid_i $base_sid_i $site_i $host]
  incr i
 }
 return $res
}

Site method Inspector {cont} {
 # créer la liste des opérations possibles pour les noeuds de type site
 private $object host

 if {[$host IsConnected]} {
  return [$object AddButtonBar $cont [list "Tout traiter" "$object DoAll" "Planifier" "$object PlanAll"]]
 } else {
  return [$object AddButtonBar $cont [list "Se connecter" "$host Connect"]]
 }
}

Site method IsTerminal {} {
 return 0
}
Node subclass Bals

Bals method init {label base host} {
 $object private base $base 
 $object private host $host
 return [super init $label static]
}

Bals method Children {} {
 # retourne la liste des types des boites aux lettres
 private $object base host

 set base_sid [$base GetSID]
 return [list \
  [BalsDep new $object.0 départ [$host RPC GetVal BALDEP $base_sid] $host {}] \
  [BalRec new $object.1 arrivée [$host RPC GetVal BALREC $base_sid] $host {}] \
 ]
}

Bals method Inspector {cont} {
 # retourne la liste des opérations possibles pour les noeuds de type boite aux lettres
 private $object base

 return [$object AddButtonBar $cont [list constituer "$object Constitution" integrer "$object Integration" purger "$object Purge"]]
}

Bals method IsTerminal {} {
 return 0
}
Node subclass Listeners

Listeners method init {label base host} {
 $object private base $base
 $object private host $host
 return [super init $label static]
}

Listeners method Children {} {
 # retourne la liste des listeners pour une base
 private $object base host

 set base_sid [$base GetSID]
 return [list \
  [Listener new $object.0 ${base_sid}_l1 ${base_sid}_l1 $host] \
  [Listener new $object.1 ${base_sid}_l2 ${base_sid}_l2 $host] \
 ]
}

Listeners method Inspector {cont} {
 # retourne la liste des opérations possibles pour les noeuds de type regroupement de listeners
 private $object base host
 
 return [$object AddButtonBar $cont [list lancer "$object RunLists" arreter "$object StopLists"]]
}

Listeners method IsTerminal {} {
 return 0
}
Node subclass Exploitation

Exploitation method init {label base host} {
 $object private base $base 
 $object private host $host
 return [super init $label static]
}

Exploitation method Children {} {
 # retourne la liste des types des boites aux lettres
 private $object base host

 set base_sid [$base GetSID]
 Exploit new $object.0 exploit $base $host
 Prints new $object.1 imprimés [$host RPC GetVal PRINTS $base_sid] $host {}
 
# $object.0 Register

 return [list \
  $object.0 \
  $object.1 \
 ]
}

Exploitation method Inspector {cont} {
 # retourne la liste des opérations possibles pour les noeuds de type boite aux lettres
 private $object base

 return [$object AddButtonBar $cont [list constituer "$object Constitution" integrer "$object Integration" purger "$object Purge"]]
}

Exploitation method IsTerminal {} {
 return 0
}
# Classe des services (executable lancé par l'exploit susceptible de générer des sorties écran)
# les sorties sont redirigées vers une zone appropriée de l'interface graphique
# les sous-classe doivent surcharger Run
#
Node subclass Service

Service Templates IdxTemplate

# méthode de classe permettant d'envoyer toutes les secondes des messages Flash à toutes les instances
# de toutes les sous-classes de Service
# <- handler after
#
Service classmethod Flash {} {
 foreach obj_i [[super info class] allchildren] {
  $obj_i Flash
 }
 # recommence toutes les secondes
 return [after 1000 Service Flash]
}

Service method init {label id host} {
 $object private id $id
 $object private host $host
 $object private activity 0

 return [super init $label static]
}

Service method destroy {} {
 return [super destroy]
}

Service method Inspector {cont} {
 # retourne la liste des opérations possibles pour les noeuds de type Service
 private $object id host

 if {[$host RPC [$object info class] IsRunning $id]} {
  set switch "arreter"
 } else {
  set switch "démarrer"
 }

 return [$object AddButtonBar $cont [list $switch "$object Switch"]]
}

# méthode qui retourne les états a afficher pour le service
#
Service method Stat {} {
 private $object id host

 set stat [super Stat]
 if {[$host RPC [$object info class] IsRunning $id]} {
  lappend stat "actif"
 } else {
  lappend stat "arreté"
 }
 return $stat
}

# méthode a surcharger qui lance le service sur le serveur en asynchrone
# l'activité du service nous arrive sur la connexion d'écoute sous la forme
# log {$objet} {données}
#
Service method RunA {} {
 private $object id host

 # lance le service identifié par la meme clef sur le serveur
 $host RPC [$object info class] RunA $id
}

# méthode permettant de parametrer un effet visuel répétitif (1s) sur le noeud
#
Service method Flash {} {
 private $object tree node activity

 set c [$tree itemcget $node -fill]
 if {$c != "black"} {
  $tree itemconfigure $node -fill black
 } else {
   $tree itemconfigure $node -fill [expr {$activity ? "green" : "red"}]
 }
}
Service subclass Base

Base method init {label base_sid site host} {
 $object private base_sid $base_sid
 $object private site $site
 $object private host $host
 return [super init $label $base_sid $host]
}

Base method Children {} {
 # retourne la liste des fonctionalités a gérer par bases
 private $object base_sid host

 Listeners new $object.0 listeners $object $host
 Scrut new $object.1 scrutateur $object $host
 Exploitation new $object.2 exploitation $object $host
 Bals new $object.3 boites $object $host
 Sauvegardes new $object.4 sauvegardes [$host RPC GetVal SAUV $base_sid] $host {}
 Traces new $object.5 traces [$host RPC GetVal BATCH_LOG $base_sid] $host {}

 $object.1 Register
 
 return [list \
  $object.0 \
  $object.1 \
  $object.2 \
  $object.3 \
  $object.4 \
  $object.5 \
 ]
}

Base method Inspector {cont} {
 # retourne la liste des opérations possibles pour les noeuds de type base
 private $object base_sid site host

 if {[$host RPC [$object info class] IsRunning $base_sid]} {
  set switch "arreter"
 } else {
  set switch "démarrer"
 }
 return [$object AddButtonBar $cont [list $switch "$object Switch" "lancer les traitements" "$object Exploit"]]
}

Base method IsTerminal {} {
 return 0
}

# accésseur à la variable base_sid
Base method GetSID {} {
 return [$object private base_sid]
}

# ! bug du package Class. super représente $objet du type de sa superclasse au lieu de repésenter
# $objet du type la classe de la méthode dans laquelle super apparait 
Base method Stat {} {
 return [super Stat]
}
Service subclass Listener

Listener method init {label lis host} {
 $object private host $host
 return [super init $label $lis $host]
}

# ! bug du package Class. super représente $objet du type de sa superclasse au lieu de repésenter
# $objet du type la classe de la méthode dans laquelle super apparait 
Listener method Stat {} {
 return [super Stat]
}
Service subclass ServiceLog

ServiceLog private currentlog ""

ServiceLog method init {label id host} {
 $object private sock ""
 $object private log ""
 return [super init $label $id $host]
}

ServiceLog method destroy {} {
 $object Unregister
 return [super destroy]
}

# méthode pour s'enregistrer auprès du serveur de manière à recevoir l'activité
# du service
#
ServiceLog method Register {} {
 private $object id host sock

 if {$sock == ""} {
  set sock [$host UserConnect "SERVICE [$object info class] $id" $object ShowLog]
 }
}

ServiceLog method Unregister {} {
 private $object sock host

 if {$sock != ""} {
  $host UserDisconnect $sock
 }
}

ServiceLog method Disconnected {_sock} {
 puts "$object Disconnected"
 set 
}

ServiceLog method Inspector {cont} {
 # retourne la liste des opérations possibles pour les noeuds de type service
 private $object id host

 if {! [$host RPC [$object info class] IsRunning $id]} {
  return [$object AddButtonBar $cont [list démarrer "$object RunA"]]
 }
}

ServiceLog method Select {} {
 private $object log
 private ServiceLog currentlog
 global txt2

 # efface le contenu de la fenetre
 if {$currentlog != "$object"} {
  $txt2 config -state normal
  $txt2 delete 1.0 end
  foreach line $log {
   $txt2 insert end $line\n
  }
  $txt2 config -state disabled
  set currentlog $object
 }
}

# méthode permettant l'affichage de l'activité des taches lancées sur
# sur le serveur en asynchrone dans la zone prévue à cet effet
# -> message a afficher
#
ServiceLog method ShowLog {msg} {
 private $object log
 private ServiceLog currentlog
 global txt2

 lappend log $msg
 # afficher si le log est visile
 if {$currentlog == "$object"} {
  $txt2 config -state normal 
  $txt2 insert end $msg\n
  $txt2 config -state disabled
 }
}

# ! bug du package Class. super représente $objet du type de sa superclasse au lieu de repésenter
# $objet du type la classe de la méthode dans laquelle super apparait 
ServiceLog method Stat {} {
 return [super Stat]
}
ServiceLog subclass Scrut

Scrut method init {label base host} {
 return [super init $label [$base GetSID] $host]
}

# méthode pour lancer le scrutateur en asynchrone sur le serveur
#
Scrut method RunA {} {
 private $object host id

 $object ShowLog "lancement du scrutateur $id"
 return [super RunA]
}

# ! bug du package Class. super représente $objet du type de sa superclasse au lieu de repésenter
# $objet du type la classe de la méthode dans laquelle super apparait 
Scrut method Stat {} {
 return [super Stat]
}
ServiceLog subclass Exploit

Exploit method init {label base host} {
 return [super init $label [$base GetSID] $host]
}

# méthode pour lancer l'exploitation en asynchrone sur le serveur
#
Exploit method RunA {} {
 private $object host id

 $object ShowLog "lancement des traitements sur $id"
 return [super RunA]
}

# méthode pour attirer l'attention sur l'etat de l'exploitation
#
Exploit method Flash {} {
 private $object tree node activity

 # ne clignoter que si l'exploit est active
 if {$activity} {
  super Flash
 }
}

# ! bug du package Class. super représente $objet du type de sa superclasse au lieu de repésenter
# $objet du type la classe de la méthode dans laquelle super apparait 
Exploit method Stat {} {
 return [super Stat]
}
# Classe des noeuds de type Fichier (leur contenu s'affiche dynamiquement à l'ouverture du
# noeud dans l'arbre, si c'est un répertoire)
#
Node subclass File

# variable comptant le nombre de fenetre de visualisation ouvertes
File private winbr 0

File classmethod Stat {host path} {
 return [$host RPC Stat $path]
}

File method init {label path host stget} {
 $object private path $path
 $object private host $host
 $object private txt1 ""
 $object private sock ""
 $object private stget [expr {$stget != {} ? $stget : [File Stat $host $path]}]
 return [super init $label dynamic]
}

File method Children {} {
 private $object path host
 
 # retourne le contenu des répertoires
 if {[$object Type] == "directory"} {
  set i 0
  set res ""
  foreach file_i [$host RPC GetDirContents $path] {
   set child_i [$object NewChild $object.$i $file_i]
   if {$child_i != ""} {
    lappend res $child_i
   }
   incr i
  }
  return $res
 }
}

# méthode qui retourne un objet représentant le fichier $file a rajouter dans les descendants,
# et {} pour ne rien rajouter
# -> path: chemin absolu du fichier
#    name: nom de l'objet a instancier
# <- object instancié de classe File ou descendante | {}
#
File method NewChild {name path} {
 private $object host

 # par défaut, instancie tous les descendants comme étant de type File
 return [new File $name [file tail $path] $path $host]
}

File method Type {} {
 private $object stget
 
 array set st $stget
 return $st(type)
}

File method Disconnected {_sock} {
 puts "$object Disconnected"
 set [privatevar $object sock] ""
}

# méthode permettant de visualiser le fichier representé par $object dans une fenetre
#
File method Watch {} {
 private $object path label host txt1 sock
 private File winbr

 set win [toplevel .t$winbr]
 incr winbr
 eval [subst {
  wm protocol $win WM_DELETE_WINDOW {
   # effacer l'association de l'objet avec la fenetre de visualisation
   set txt1 ""
   # fermer la connexion (ne pas évaluer [])
   $host UserDisconnect \[$object GetSock\]
   # ferme la fenetre
   destroy $win
  }\
 }]
 wm title $win $label

 set sw1 [ScrolledWindow $win.sw1 -auto vertical -scrollbar both]
 pack $sw1 -expand true -fill both -side top
 set txt1 [text [$sw1 getframe].txt1 -state disabled -wrap none]
 $sw1 setwidget $txt1

 # envoie l'ordre de lecture de fichier sur le serveur
 set sock [$host UserConnect "GET $path" $object View]
}

# méthode permettant de télécharger le fichier
# -> chemin de destination
#
File method Download {dest} {
 private $object sock

 set sock
}

# méthode permettant de visualiser des données dans la fenetre ouverte
# préalablement par un appel à Watch
# -> données
#
File method View {data} {
 private $object txt1

 if {$txt1 != ""} {
  $txt1 config -state normal
  $txt1 insert end $data\n
  $txt1 config -state disabled
 }
}

File method IsTerminal {} {
 # tout fichier qui n'est pas un répertoire est un noeud terminal de l'arbre
 return [expr {[$object Type] != "directory"}]
}

File method Inspector {cont} {
 if {[$object Type] == "file"} {
  return [$object AddButtonBar $cont [list Visualiser "$object Watch"]]
 }
}

File method Stat {} {
 private $object stget

 set stat [super Stat]
 array set st $stget
 if {$st(type) == "file"} {
  lappend stat "taille $st(size)" "date [clock format $st(mtime) -format {%d/%m/%Y %H:%M}]"
 }
 return $stat
}

File method GetSock {} {
 return [$object private sock] 
}

File subclass BalsDep

BalsDep method NewChild {name path} {
 private $object host

 set stget [File Stat $host $path]
 array set child_st $stget
 if {$child_st(type) == "directory"} {
  return [BalDep new $name [file tail $path] $path $host $stget]
 }
}

BalsDep method Inspector {cont} {
 private $object path host

 # retourne la liste des opérations possibles pour les noeuds de type liste destinataires depeche
 return [$object AddButtonBar $cont [list Migrer "$object Migration"]]
}

BalsDep method IsTerminal {} {
 return 0
}

# ! bug du package Class. super représente $objet du type de sa superclasse au lieu de repésenter
# $objet du type la classe de la méthode dans laquelle super apparait 
BalsDep method Stat {} {
 return [super Stat]
}
File subclass Depeches

Depeches method NewChild {name path} {
 private $object host

 set stget [File Stat $host $path]
 array set child_st $stget
 if {$child_st(type) == "file"} { 
  return [Depeche new $name [file tail $path] $path $host $stget]
 }
}

Depeches method IsTerminal {} {
 return 0
}

# ! bug du package Class. super représente $objet du type de sa superclasse au lieu de repésenter
# $objet du type la classe de la méthode dans laquelle super apparait 
Depeches method Stat {} {
 return [super Stat]
}
Depeches subclass BalRec

BalRec method Inspector {cont} {
 # retourne la liste des opérations possibles pour les noeuds de type boite de reception
 private $object path host

 return [$object AddButtonBar $cont [list intégrer "$object Integration"]]
}

# ! bug du package Class. super représente $objet du type de sa superclasse au lieu de repésenter
# $objet du type la classe de la méthode dans laquelle super apparait 
BalRec method Stat {} {
 return [super Stat]
}
Depeches subclass BalDep

BalDep method Inspector {cont} {
 # retourne la liste des opérations possibles pour les noeuds de type boite d'emission
 private $object path host

 return [$object AddButtonBar $cont [list constituer "$object Constitution" Migrer "$object Migration"]]
}

# ! bug du package Class. super représente $objet du type de sa superclasse au lieu de repésenter
# $objet du type la classe de la méthode dans laquelle super apparait 
BalDep method Stat {} {
 return [super Stat]
}
File subclass Depeche

# ! bug du package Class. super représente $objet du type de sa superclasse au lieu de repésenter
# $objet du type la classe de la méthode dans laquelle super apparait 
Depeche method Stat {} {
 return [super Stat]
}
File subclass Sauvegardes

Sauvegardes method NewChild {name path} {
 private $object host

 set stget [File Stat $host $path]
 array set child_st $stget
 if {$child_st(type) == "file" && [string match "*.tar.gz" $path]} { 
  return [Sauvegarde new $name [file tail $path] $path $host $stget]
 }
}

Sauvegardes method Inspector {cont} {
 private $object path host

 # retourne la liste des opérations possibles pour les noeuds de type regroupement de sauvegardes
 return [$object AddButtonBar $cont [list sauvegarder "$object RunSauv"]]
}

Sauvegardes method IsTerminal {} {
 return 0
}

# ! bug du package Class. super représente $objet du type de sa superclasse au lieu de repésenter
# $objet du type la classe de la méthode dans laquelle super apparait 
Sauvegardes method Stat {} {
 return [super Stat]
}
File subclass Sauvegarde

Sauvegarde method init {label path host args} {
 return [super init $label "|tar tzvf $path" $host $args]
}

# ! bug du package Class. super représente $objet du type de sa superclasse au lieu de repésenter
# $objet du type la classe de la méthode dans laquelle super apparait 
Sauvegarde method Stat {} {
 return [super Stat]
}
File subclass Traces

Traces method NewChild {name path} {
 private $object host

 set stget [File Stat $host $path]
 array set child_st $stget
 if {$child_st(type) == "file"} { 
  return [Trace new $name [file tail $path] $path $host $stget]
 }
}

Traces method IsTerminal {} {
 return 0
}

# ! bug du package Class. super représente $objet du type de sa superclasse au lieu de repésenter
# $objet du type la classe de la méthode dans laquelle super apparait 
Traces method Stat {} {
 return [super Stat]
}
File subclass Trace

# ! bug du package Class. super représente $objet du type de sa superclasse au lieu de repésenter
# $objet du type la classe de la méthode dans laquelle super apparait 
Trace method Stat {} {
 return [super Stat]
}
File subclass Prints

Prints method NewChild {name path} {
 private $object host

 set stget [File Stat $host $path]
 array set child_st $stget
 if {$child_st(type) == "file"} { 
  return [Print new $name [file tail $path] $path $host $stget]
 }
}

Prints method IsTerminal {} {
 return 0
}

# ! bug du package Class. super représente $objet du type de sa superclasse au lieu de repésenter
# $objet du type la classe de la méthode dans laquelle super apparait 
Prints method Stat {} {
 return [super Stat]
}
File subclass Print

# ! bug du package Class. super représente $objet du type de sa superclasse au lieu de repésenter
# $objet du type la classe de la méthode dans laquelle super apparait 
Print method Stat {} {
 return [super Stat]
}
# caractérise une connection RPC à un serveur le port $port
TClass subclass Host
MClassTemplate Host

Host method init {host port} {
 $object private host $host
 $object private port $port
 $object private rpc ""
 $object private socks ""

 $object MClassInit
 return [super init]
}

Host method destroy {} {
 private $object socks

 $object MClassDestroy
 $object Disconnect
 foreach sock_i $socks {
  $object UserDisconnect $sock_i
 }
 return [super destroy]
}

# méthode pour établir une connection RPC au serveur
# -> type: quiet (connection sans message d'erreur)
#
Host method Connect {args} {
 private $object host port rpc

 # ouvre la connexion rpc
 set res [catch {set rpc [dp_MakeRPCClient $host $port]} msg]
 if {$args != "quiet"} {
  error $msg
 }
 return [expr {! $res}]
}

Host method Disconnect {} {
 if {[$object IsConnected]} {
  close [$object private rpc]
 }
}

# méthode pour établir une connexion Utilisateur au serveur
Host method UserConnect {cmd obj handle} {
 private $object socks host port

 # la connexion s'effectue sur le port rpc + 1
 set sock [socket $host [expr $port + 1]]
 fconfigure $sock -blocking 0 -buffering line
 fileevent $sock readable [list $object HandleUserData $sock $obj $handle]
# fileevent $sock writable [list puts $sock $cmd ; fileevent $sock writable {}]
 puts $sock $cmd
 lappend socks $sock
 return $sock
}

Host method HandleUserData {sock obj handle} {
 if {[eof $sock]} {
  $object UserDisconnect $sock
  $obj Disconnected $sock
 } else {
  $obj $handle [read $sock]
 }
}

Host method UserDisconnect {sock} {
 private $object socks

 puts "UserDisconnect $sock \[$socks\]"
 set idx [lsearch -exact $socks $sock]
 if {$idx != -1} {
  fileevent $sock readable {}
  close $sock
  set socks [lreplace $socks $idx $idx]
 }
}

Host method RPC {args} {
 private $object rpc

 if {[$object IsConnected]} {
  return [eval dp_RPC $rpc $args]
 }
}

Host method RDO {args} {
 private $object rpc

 if {[$object IsConnected]} {
  return [eval dp_RDO $rpc $args]
 }
}

Host method IsConnected {} {
 private $object rpc

 return [expr {$rpc != ""}]
}
wm title . "Aster - Exploit"
wm geometry . 500x500+[expr int(([winfo screenheight .] - [winfo reqheight .])/ 2)]+[expr int(([winfo screenwidth .] - [winfo reqwidth .])/ 2)]
wm protocol . WM_DELETE_WINDOW {
 # ferme toutes les connections RPC
 foreach host_i [Host info children] {
  $host_i Disconnect
 }
 # desenregister les services
 foreach child_i [ServiceLog allchildren] {
  $child_i destroy
 }
 # ferme la fenetre
 destroy .
}

Service Flash
set descmenu {
    "&File" {} {} 0 {
        {command "&New"     {} "Create a new document"     {Ctrl n} -command Menu::new}
        {command "&Open..." {} "Open an existing document" {Ctrl o} -command Menu::open}
        {command "&Save"    open "Save the document" {Ctrl s} -command Menu::save}
        {cascad  "&Export"  {} export 0 {
            {command "Format &1" open "Export document to format 1" {} -command {Menu::export 1}}
            {command "Format &2" open "Export document to format 2" {} -command {Menu::export 2}}
        }}
        {separator}
        {cascad "&Recent files" {} recent 0 {}}
        {separator}
        {command "E&xit" {} "Exit the application" {} -command Menu::exit}
    }
    "&Options" {} {} 0 {
        {checkbutton "Toolbar" {} "Show/hide toolbar" {} 
            -variable Menu::_drawtoolbar
            -command  {$Menu::_mainframe showtoolbar toolbar $Menu::_drawtoolbar}
        }
    }
}

set mf1 [MainFrame .mf1 -menu $descmenu]
pack .mf1 -expand true -fill both


set pw2 [PanedWindow [$mf1 getframe].pw2 -side left]
pack [$mf1 getframe].pw2 -expand true -fill both
$pw2 add -minsize 100
$pw2 add -minsize 100 -weight 0
set pw1 [PanedWindow [$pw2 getframe 0].pw1 -side top]
pack [$pw2 getframe 0].pw1 -expand true -fill both
$pw1 add -minsize 100
$pw1 add -minsize 100
set sc1 [ScrolledWindow [$pw1 getframe 0].sc1 -auto both -relief ridge -scrollbar both]
pack [$pw1 getframe 0].sc1 -expand true -fill both -side left
set t1 [Tree [$sc1 getframe].t1 -closecmd NodeClosed -opencmd NodeOpened -selectcommand NodeSelected]
$sc1 setwidget $t1
set of1 [TitleFrame [$pw1 getframe 1].of1 -text Opérations]
pack [$pw1 getframe 1].of1 -expand true -fill both
set sc2 [ScrolledWindow [$pw2 getframe 1].sc2 -auto vertical -scrollbar both]
pack [$pw2 getframe 1].sc2 -expand true -fill both
# constuire la cellule texte pour afficher l'activité des scrutateurs

set txt2 [text [$sc2 getframe].txt2 -height 5 -state disabled -wrap none]
$sc2 setwidget $txt2
set currentlog ""
set i 0
foreach {lib_i host_i port_i} $libhostport {
 set rpchost [Host new $host_i $host_i $port_i]
 $rpchost Connect quiet
 # instanciation des racine représentants un ensemble de sites
 set site_i [Site new s$i $lib_i $rpchost]
 $site_i InitTree $t1 root static
 incr i
}