ScolaSync  4.0
ownedUsbDisk.py
Aller à la documentation de ce fichier.
1 # -*- coding: utf-8 -*-
2 # $Id: ownedUsbDisk.py 47 2011-06-13 10:20:14Z georgesk $
3 
4 licence={}
5 licence['en']="""
6  file ownedUsbDisk.py
7  this file is part of the project scolasync
8 
9  Copyright (C) 2010 Georges Khaznadar <georgesk@ofset.org>
10 
11  This program is free software: you can redistribute it and/or modify
12  it under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version3 of the License, or
14  (at your option) any later version.
15 
16  This program is distributed in the hope that it will be useful,
17  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  GNU General Public License for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with this program. If not, see <http://www.gnu.org/licenses/>.
23 """
24 
25 import usbDisk2, db
26 import os.path, dbus, subprocess, time, random
27 from PyQt4.QtCore import *
28 from PyQt4.QtGui import *
29 from globaldef import markFileName
30 
31 """
32 liste statique pour éviter de demander chaque seconde le nom d'un
33 propriétaire de clé si on n'a pas souhaité le donner.
34 """
35 
36 ##
37 #
38 # Renvoie le tatouage pour un point de montage donné, quitte à le créer
39 # si nécessaire.
40 # @param mountPoint un point de montage de partition
41 # @return le tatouage
42 #
43 def tattooInDir(mountPoint):
44  tattooFileName = os.path.join(mountPoint,".scolasync-tattoo")
45  tattoo_=""
46  if os.path.exists(tattooFileName):
47  tattoo_=open(tattooFileName,"r").readlines()[0].strip()
48  if tattoo_ != "" :
49  # le tatouage existe déjà, on renvoie sa valeur
50  return tattoo_
51  else:
52  tattoo_="%12.2f" %time.time()
53  time.sleep(0.05)
54  # si on espace deux créations de tatouages de 50 millisecondes
55  # il est impossible d'avoir deux tatouages identiques générés
56  # par le même ordinateur. Les chances que ça arrive avec des
57  # ordinateurs distincts sont minimes
58  outfile=open(tattooFileName,"w")
59  outfile.write(tattoo_)
60  outfile.close()
61  # on renvoie le nouveau tatouage
62  return tattoo_
63 
64 ##
65 #
66 # édition de la base de données
67 # @param owd une instance de ownedUsbDisk
68 # @param hint chaîne vide par défaut. Peut être le nom de l'ancien propriétaire
69 #
70 def editRecord(owd, hint=""):
71  ud=owd.getFat()
72  title=QApplication.translate("Dialog", "Choix du propriétaire", None, QApplication.UnicodeUTF8)
73  prompt=QApplication.translate("Dialog", "Nouveau nom du propriétaire du baladeur", None, QApplication.UnicodeUTF8)
74  newStudent, ok = QInputDialog.getText(None, title, prompt, text=hint)
75  if ok:
76  newStudent="%s" %newStudent
77  assert (ud.parent) # ud est une partition de type vfat
78  db.writeStudent(ud.stickid, ud.uuid, ud.tattoo(), newStudent)
79 
80 ##
81 #
82 # une classe qui ajoute un nom de propriétaire aux disque USB,
83 # et qui en même temps ajoute des particularités selon le nom du
84 # vendeur et le modèle.
85 #
87  ##
88  #
89  # Le constructeur
90  # @param path un chemin comme '/org/freedesktop/UDisks2/block_devices/sdX'
91  # @param mp point de montage ('' par défaut)
92  # @param isUsb en général, vrai vu qu'on se s'intéressera qu'à des périphériques
93  # USB
94  # @param vendor indication de vendeur
95  # @param model indication de modèle
96  # @param parent périphérique parent (None par défaut)
97  # @param fstype type de système de fichiers
98  # @param serial numéro de série
99  # @param uuid identifiant donné au disque lors du formatage
100  # @param free taille de la zone libre pour l'écriture
101  # @param capacity taille du périphérique
102  # @param device pseudo-fichier pour l'accès au périphérique
103  # @param firstFat une instance de uDisk2, de type vfat parmi les partitions
104  # @param selected vrai/faux selon qu'on sélectionne ou non le périphérique (vrai par défaut)
105  #
106  def __init__(self, path, mp='', isUsb=False, vendor='', model='', parent=None,
107  fstype='', serial='', uuid='',
108  free=0, capacity=0, device='', firstFat=None, selected=True):
109  usbDisk2.uDisk2.__init__(self, path=path, mp=mp, isUsb=isUsb, vendor=vendor,
110  model=model, parent=parent, fstype=fstype, serial=serial,
111  uuid=uuid, free=free, capacity=capacity, device=device,
112  firstFat=firstFat, selected=selected)
113  QObject.__init__(self)
114  self.owner="" # le propriétaire est déterminé plus tard
116 
117  ##
118  #
119  # Renvoie le propriétaire
120  # @return le propriétaire de la clé
121  #
122  def getOwner(self):
123  return self.getFat().owner
124 
125  ##
126  #
127  # Renvoie à coup sûr la partition vfat d'un disque
128  # @return une instance uDisk2 représentant une partition vfat
129  #
130  def getFat(self):
131  if self.parent:
132  return self
133  else:
134  return self.firstFat
135 
136  ##
137  #
138  # Facilite l'accès aux propriétés intéressantes d'une instance
139  # @return une chaîne indentée avec les propriétés intéressantes, une par ligne
140  #
141  def valuableProperties(self,indent=4):
142  prefix="\n"+" "*indent
143  r=""
144  props=["mp", "parent", "fstype", "stickid", "uuid", "vendor", "model", "devStuff", "free", "capacity", "owner"]
145  for prop in props:
146  r+=prefix+"%s = %s" %(prop, getattr(self,prop))
147  return r
148 
149  ##
150  #
151  # @return un identifiant unique, composé du nom du propriétaire
152  # suivi du tatouage
153  #
154  def uniqueId(self):
155  return "%s~%s" %(self.owner, self.tattoo())
156 
157  ##
158  #
159  # Renvoie un tatouage présent sur la clé, quitte à le créer.
160  # @result un tatouage, supposément unique.
161  #
162  def tattoo(self):
163  ud=self.getFat()
164  if ud.mp:
165  return tattooInDir(ud.mp)
166  else:
167  return ""
168 
169  ##
170  #
171  # Lit un dictionnaire indexé par le noms de vendeurs et les noms de modèle
172  # pour associer à ces modèles particuliers un répertoire visible.
173  # voir la fonction visibleDir. Ce dictionnaire est dans le fichier
174  # /usr/share/scolasync/marques.py ou dans ${HOME}/.scolasync/marques.py,
175  # (sous Linux) cette dernière place étant prépondérante.
176  #
177  def readQuirks (self):
178  f1="/usr/share/scolasync/marques.py"
179  f2=os.path.expanduser(markFileName)
180  if os.path.exists(f2):
181  f=f2
182  else:
183  f=f1
184  result=eval(open(f,"r", encoding="utf-8").read())
185  return result
186 
187  ##
188  #
189  # Renvoie le répertoire particulier de la partition qui sera visible
190  # quand le baladeur est utilisé par son interface utilisateur. Ce
191  # répertoire peut varier selon les vendeurs et les modèles.
192  #
193  def visibleDir(self):
194  k=self.vendor+":"+self.model
195  if k in self.visibleDirs.keys():
196  return self.visibleDirs[k]
197  else:
198  return "."
199 
200  ##
201  #
202  # Méthode statique
203  # renvoie des titres pour les items obtenus par __getitem__
204  # la deuxième colonne sera toujours le propriétaire
205  # @param locale la locale, pour traduire les titres
206  # @return une liste de titres de colonnes
207  #
208  def headers(locale="C"):
209  result=usbDisk2.uDisk2.headers(locale)
210  ownerProp=QApplication.translate("uDisk","owner",None, QApplication.UnicodeUTF8)
211  result.insert(1,ownerProp)
212  return result
213 
214  ##
215  #
216  # renvoie un nom de propriétaire dans tous les cas.
217  #
218  def ownerByDb(self):
219  s=db.readStudent(self.stickid, self.uuid, self.tattoo())
220  if s != None:
221  return s
222  else:
223  return QApplication.translate("Dialog","inconnu",None, QApplication.UnicodeUTF8)
224 
225  ##
226  #
227  # renvoie un élément de listage de données internes au disque
228  # Fait en sorte que la deuxième colonne soit toujours le propriétaire
229  # @param n un nombre
230  # @return si n==-1, renvoie self ; renvoie un élément si n>0, et le drapeau self.selected si n==0. Les noms des éléments sont dans la liste self.itemNames
231  #
232  def __getitem__(self,n):
233  propListe=usbDisk2.uDisk2.headers()
234  if n == -1:
235  return self # pour accéder à toutes les données d'une partition
236  elif n==0:
237  return self.selected
238  elif n==1:
239  return self.ownerByDb()
240  else:
241  return self.unNumberProp(n)
242 
243 
244  headers = staticmethod(headers)
245 
246  ##
247  #
248  # Demande un nom de propriétaire si celui-ci n'est pas encore défini
249  # pour cette clé USB. Enregistre au passage le nom du propriétaire
250  # dans les instances du disque et de sa partiton vfat
251  # @param ownerDialog si vrai : fait dialogue interactif
252  # @return un nom de propriétaire
253  #
254  def ensureOwner(self, ownerDialog):
255  if self.parent and not self.mp : # partiton non montée
256  return
257  ud=self.getFat()
258  assert (ud.parent) # ud désigne une partition vfat
259  if not db.knowsId(ud.stickid, ud.uuid, ud.tattoo()) :
260  text=self.randomOwner(6)
261  if ownerDialog:
262  prompt=QApplication.translate("Dialog","La cle {id}<br>n'est pas identifiee, donnez le nom du proprietaire",None, QApplication.UnicodeUTF8).format(id=ud.stickid)
263  title=QApplication.translate("Dialog","Entrer un nom",None, QApplication.UnicodeUTF8)
264  text,ok = QInputDialog.getText(None, title, prompt)
265  db.writeStudent(ud.stickid, ud.uuid, ud.tattoo(), text)
266  o=db.readStudent(ud.stickid, ud.uuid, ud.tattoo())
267  self.owner=o
268  ud.owner=o
269  return o
270 
271  ##
272  #
273  # fabrique un texte aléatoire de longueur donnée
274  # @param length la longueur recherchée
275  # @return un texte pseudo-aléatoire
276  #
277  def randomOwner(self,length):
278  result="inconnu_"
279  for i in range(length):
280  result+=random.choice("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
281  return result
282 
283 ##
284 #
285 # Une classe qui fournit une collection de disques USB connectés,
286 # avec leurs propriétaires. Les propriétaires sont recensés juste
287 # avant le montage des partions FAT.
288 #
290 
291  ##
292  #
293  # Le constructeur est un proxy pour usbDisk.Available.__init__
294  # qui force la classe de disques à utiliser : en effet ici
295  # uDisk désigne ownedUsbDisk.uDisk
296  # @param access le mode d'accès : 'disk' ou 'firstFat'
297  # @param diskClass la classe d'objets à créer pour chaque disque
298  # @param ownerDialog vrai si on veut qu'il y ait un dialogue automatique
299  # pour déterminer le propriétaire des disques non reconnus
300  #
301  def __init__(self, access="disk", diskClass=uDisk2, ownerDialog=False):
302  self.ownerDialog=ownerDialog
303  usbDisk2.Available.__init__(self, access, diskClass)
304  # self.finishInit() # non! cette routine est déjà appelée par usbDisk2.Available.__init__
305 
306  ##
307  #
308  # Fin de l'initialisation : trouve les propriétaires des disques
309  # puis identifie les partitions FAT et les monte
310  #
311  def finishInit(self):
312  self.getFirstFats() # repère chaque partition FAT dans les instances des disques
313  for d in self.disks_ud():
314  d.owner=d.ensureOwner(self.ownerDialog)
315  self.mountFirstFats()
316 
317 
318 if __name__=="__main__":
319  from PyQt4.QtCore import *
320  from PyQt4.QtGui import *
321  import sys
323  def __init__(self):
324  QMainWindow.__init__(self)
325 
326  # The only thing in the app is a quit button
327  quitbutton = QPushButton('Examinez le terminal\nbranchez et débranchez des clés USB, puis\nQuittez', self)
328  QObject.connect(quitbutton, SIGNAL("clicked()"), self.close)
329  self.setCentralWidget(quitbutton)
330 
331  machin=Available()
332  print (machin)
333  def print_targets_if_modif(man, obj):
334  if machin.modified:
335  print([s.split("/")[-1] for s in machin.targets.keys()])
336  for t in machin.targets:
337  machin.targets[t].owner=machin.targets[t].ownerByDb()
338  print (machin.targets[t].owner,":", t)
339  machin.modified=False
340  machin.addHook('object-added', print_targets_if_modif)
341  machin.addHook('object-removed', print_targets_if_modif)
342 
343  app = QApplication(sys.argv)
344  main = MainWindow()
345  main.show()
346  sys.exit(app.exec_())
347 
def getOwner(self)
Renvoie le propriétaire.
def getFat(self)
Renvoie à coup sûr la partition vfat d'un disque.
def __init__
Le constructeur.
une classe pour représenter un disque ou une partition.
Definition: usbDisk2.py:396
def __init__
Le constructeur est un proxy pour usbDisk.Available.__init__ qui force la classe de disques à utilise...
Une classe qui fournit une collection de disques USB connectés, avec leurs propriétaires.
def readQuirks(self)
Lit un dictionnaire indexé par le noms de vendeurs et les noms de modèle pour associer à ces modèles ...
def print_targets_if_modif(man, obj)
def visibleDir(self)
Renvoie le répertoire particulier de la partition qui sera visible quand le baladeur est utilisé par ...
def __getitem__(self, n)
renvoie un élément de listage de données internes au disque Fait en sorte que la deuxième colonne soi...
def editRecord
édition de la base de données.
Definition: ownedUsbDisk.py:70
def finishInit(self)
Fin de l'initialisation : trouve les propriétaires des disques puis identifie les partitions FAT et l...
def ownerByDb(self)
renvoie un nom de propriétaire dans tous les cas.
def ensureOwner(self, ownerDialog)
Demande un nom de propriétaire si celui-ci n'est pas encore défini pour cette clé USB...
def randomOwner(self, length)
fabrique un texte aléatoire de longueur donnée
def getFirstFats(self)
Facilite l'accès aux partitions de type DOS-FAT, et a des effets de bord :
Definition: usbDisk2.py:759
def valuableProperties
Facilite l'accès aux propriétés intéressantes d'une instance.
def tattoo(self)
Renvoie un tatouage présent sur la clé, quitte à le créer.
une classe pour représenter la collection des disques USB connectés
Definition: usbDisk2.py:593
def tattooInDir(mountPoint)
Renvoie le tatouage pour un point de montage donné, quitte à le créer si nécessaire.
Definition: ownedUsbDisk.py:43
def unNumberProp(self, n)
retire le numéro des en-têtes pour en faire un nom de propriété valide pour interroger dbus ...
Definition: usbDisk2.py:530
def disks_ud(self)
Récolte les enregistrements de niveau supérieur de self.targets.
Definition: usbDisk2.py:676
une classe qui ajoute un nom de propriétaire aux disque USB, et qui en même temps ajoute des particul...
Definition: ownedUsbDisk.py:86
def mountFirstFats(self)
fabrique la liste des partitions FAT, monte les partitions FAT si elles ne le sont pas ...
Definition: usbDisk2.py:621