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