ScolaSync  1.0
ownedUsbDisk.py
Aller à la documentation de ce fichier.
00001 # -*- coding: utf-8 -*-    
00002 #       $Id: ownedUsbDisk.py 47 2011-06-13 10:20:14Z georgesk $ 
00003 
00004 licence={}
00005 licence['en']="""
00006     file ownedUsbDisk.py
00007     this file is part of the project scolasync
00008     
00009     Copyright (C) 2010 Georges Khaznadar <georgesk@ofset.org>
00010 
00011     This program is free software: you can redistribute it and/or modify
00012     it under the terms of the GNU General Public License as published by
00013     the Free Software Foundation, either version3 of the License, or
00014     (at your option) any later version.
00015 
00016     This program is distributed in the hope that it will be useful,
00017     but WITHOUT ANY WARRANTY; without even the implied warranty of
00018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019     GNU General Public License for more details.
00020 
00021     You should have received a copy of the GNU General Public License
00022     along with this program.  If not, see <http://www.gnu.org/licenses/>.
00023 """
00024 
00025 
00026 import usbDisk, db
00027 import os.path, dbus, subprocess, time
00028 from PyQt4.QtCore import *
00029 from PyQt4.QtGui import *
00030 from globaldef import markFileName
00031 
00032 """
00033 liste statique pour éviter de demander chaque seconde le nom d'un
00034 propriétaire de clé si on n'a pas souhaité le donner.
00035 """
00036 
00037 ##
00038 # 
00039 #     édition de la base de données
00040 #     @param owd une instance de ownedUsbDisk
00041 #     @param student nom de propriétaire pour la clé. Chaîne vide par défaut.
00042 #     
00043 def editRecord(owd, student=""):
00044     newStudent, ok = QInputDialog.getText(None,
00045                                           u"Choix du propriétaire",
00046                                           u"Nouveau nom du propriétaire de la clé",
00047                                           text=student
00048                                           )
00049     if ok:
00050         newStudent=u"%s" %newStudent
00051         db.writeStudent(owd.stickid, owd.getFatUuid(), owd.tattoo(), newStudent)
00052 
00053 ##
00054 # 
00055 #     une classe qui ajoute un nom de propriétaire aux disque USB,
00056 #     et qui en même temps ajoute des particularités selon le nom du
00057 #     vendeur et le modèle.
00058 #     
00059 class uDisk(usbDisk.uDisk,QObject):
00060     ##
00061     # 
00062     #         @param path un chemin dans le système dbus
00063     #         @param bus un objet dbus.BusSystem
00064     #         @param checkable vrai si on fera usage de self.selected
00065     #         
00066     def __init__(self, path, bus, checkable=False):
00067         usbDisk.uDisk.__init__(self,path, bus, checkable)
00068         QObject.__init__(self)
00069         self.owner="" # le propriétaire est déterminé plus tard
00070         self.vendor=self.getProp("drive-vendor")
00071         self.model=self.getProp("drive-model")
00072         self.visibleDirs=self.readQuirks()
00073 
00074     ##
00075     # 
00076     #         @return un identifiant unique, composé du nom du propriétaire
00077     #         suivi du tatouage
00078     #         
00079     def uniqueId(self):
00080         return "%s~%s" %(self.owner, self.tattoo())
00081 
00082     ##
00083     # 
00084     #         Renvoie un tatouage présent sur la clé, quitte à le créer.
00085     #         @result un tatouage, supposément unique.
00086     #         
00087     def tattoo(self):
00088         ff=self.getFirstFat()
00089         if ff:
00090             fatPath=ff.ensureMounted()
00091             tattooFileName=os.path.join(fatPath,".scolasync-tattoo")
00092             if os.path.exists(tattooFileName):
00093                 tattoo_=open(tattooFileName,"r").read()
00094                 # on vérifie par acquis de conscience, qu'il n'existe pas
00095                 # un tatouage identique dans la base de données
00096                 # s'il est déjà présent : on le change. Il faudrait
00097                 # probablement aussi prévenir le prof !!!
00098                 if tattoo_ in db.tattooList():
00099                     tattoo_="%12.2f" %time.time()
00100                     time.sleep(0.05)
00101             else:
00102                 tattoo_="%12.2f" %time.time()
00103                 time.sleep(0.05)
00104                 outfile=open(tattooFileName,"w")
00105                 outfile.write(tattoo_)
00106                 outfile.close()
00107             return tattoo_
00108         else:
00109             return ""
00110     
00111     ##
00112     # 
00113     #         Lit un dictionnaire indexé par le noms de vendeurs et les noms de modèle
00114     #         pour associer à ces modèles particuliers un répertoire visible.
00115     #         voir la fonction visibleDir. Ce dictionnaire est dans le fichier
00116     #         /usr/share/scolasync/marques.py ou dans ${HOME}/.scolasync/marques.py,
00117     #         (sous Linux) cette dernière place étant prépondérante.
00118     #         
00119     def readQuirks (self):
00120         f1="/usr/share/scolasync/marques.py"
00121         f2=os.path.expanduser(markFileName)
00122         if os.path.exists(f2):
00123             f=f2
00124         else:
00125             f=f1
00126         result=eval(open(f,"r").read())
00127         return result
00128         
00129     ##
00130     # 
00131     #         Renvoie le répertoire particulier de la partition qui sera visible
00132     #         quand le baladeur est utilisé par son interface utilisateur. Ce
00133     #         répertoire peut varier selon les vendeurs et les modèles.
00134     #         
00135     def visibleDir(self):
00136         k=self.vendor+":"+self.model
00137         if k in self.visibleDirs.keys():
00138             return self.visibleDirs[k]
00139         else:
00140             return "."
00141 
00142     ##
00143     # 
00144     #         Méthode statique
00145     #         renvoie des titres pour les items obtenus par __getitem__
00146     #         la deuxième colonne sera toujours le propriétaire
00147     #         @param checkable vrai si le premier en-tête correspond à une colonne de cases à cocher
00148     #         @param locale la locale, pour traduire les titres
00149     #         @return une liste de titres de colonnes
00150     #         
00151     def headers(checkable=False,locale="C"):
00152         result=usbDisk.uDisk.headers(checkable, locale)
00153         ownerProp=QApplication.translate("uDisk","owner",None, QApplication.UnicodeUTF8)
00154         result.insert(1,ownerProp)
00155         return result
00156 
00157     ##
00158     # 
00159     #         renvoie un nom de propriétaire dans tous les cas.
00160     #         
00161     def ownerByDb(self):
00162         if self.owner != "":
00163             return self.owner
00164         else:
00165             s=db.readStudent(self.stickid, self.getFatUuid(), self.tattoo())
00166             if s != None:
00167                 self.owner=s
00168                 return s
00169             else:
00170                 return QApplication.translate("Dialog","inconnu",None, QApplication.UnicodeUTF8)
00171 
00172     ##
00173     # 
00174     #         renvoie un élément de listage de données internes au disque
00175     #         Fait en sorte que la deuxième colonne soit toujours le propriétaire
00176     #         @param n un nombre
00177     #         @param checkable vrai si on doit renvoyer une propriété supplémentaire pour n==0
00178     #         @return si n==-1, renvoie self ; si checkable est vrai, renvoie un élément si n>0, et le drapeau self.selected si n==0 ; sinon un élément de façon ordinaire. Les noms des éléments sont dans la liste self.itemNames
00179     #         
00180     def __getitem__(self,n):
00181         propListe=usbDisk.uDisk.headers()
00182         if n == -1:
00183             return self # pour accéder à toutes les données d'une partition
00184         if self.checkable:
00185             if n==0:
00186                 return self.selected
00187             elif n==1:
00188                 return self.ownerByDb()
00189             elif n==2:
00190                 return self.unNumberProp(0)
00191             else:
00192                 return self.unNumberProp(n-1)
00193         else:
00194             if n==0:
00195                 return self.unNumberProp(0)
00196             elif n==1:
00197                 return self.ownerByDb()
00198             else:
00199                 return self.unNumberProp(n)
00200     
00201     
00202     headers = staticmethod(headers)
00203 
00204     ##
00205     # 
00206     #         Demande un nom de propriétaire si celui-ci n'est pas encore défini
00207     #         pour cette clé USB
00208     #         @return un nom de propriétaire si c'est un disque, sinon None
00209     #         
00210     def ensureOwner(self):
00211         if self.getProp("device-is-drive") and self.isUsbDisk():
00212             if not db.knowsId(self.stickid, self.getFatUuid(), self.tattoo()) :
00213                 prompt=QApplication.translate("Dialog","La cle %1<br>n'est pas identifiee, donnez le nom du proprietaire",None, QApplication.UnicodeUTF8).arg(self.stickid)
00214                 text,ok = QInputDialog.getText(None,
00215                                                QApplication.translate("Dialog","Entrer un nom",None, QApplication.UnicodeUTF8),
00216                                                prompt)
00217                 if ok and len(text)>0:
00218                     db.writeStudent(self.stickid, self.getFatUuid(), self.tattoo(), u"%s" %text.toUtf8())
00219         return db.readStudent(self.stickid, self.getFatUuid(), self.tattoo())
00220         
00221 ##
00222 # 
00223 #     Une classe qui fournit une collection de disques USB connectés,
00224 #     avec leurs propriétaires. On a répliqué le code de la classe parente,
00225 #     ne sachant pas si le contructeur prendrait les uDisks dans le module
00226 #     courant ou dans le module parent. Pour éviter les confusion il faudrait
00227 #     peut-être faire une classe abstraite Available
00228 #     
00229 class Available(usbDisk.Available):
00230     ##
00231     # 
00232     #         @param checkable : vrai si on veut pouvoir cocher les disques de la
00233     #           collection. Faux par défaut.
00234     #         @param access définit le type d'accès souhaité. Par défaut, c'est "disk"
00235     #           c'est à dire qu'on veut la liste des disques USB. Autres valeurs
00236     #           possibles : "firstFat" pour les premières partitions vfat.
00237     #         
00238     def __init__(self, checkable=False, access="disk"):
00239         self.checkable=checkable
00240         self.access=access
00241         self.bus = dbus.SystemBus()
00242         proxy = self.bus.get_object("org.freedesktop.UDisks", 
00243                                     "/org/freedesktop/UDisks")
00244         iface = dbus.Interface(proxy, "org.freedesktop.UDisks")
00245         self.disks={}
00246         self.enumDev=iface.EnumerateDevices()
00247         ### récupération des disques usb dans le dictionnaire self.disks
00248         for path in self.enumDev:
00249             ud=uDisk(path, self.bus, checkable)
00250             if ud.isUsbDisk():
00251                 self.disks[ud]=[]
00252                 # cas des disques sans partitions
00253                 if bool(ud.getProp("device-is-partition-table")) == False:
00254                     # la propriété "device-is-partition-table" est fausse,
00255                     # probablement qu'il y a un système de fichiers
00256                     self.disks[ud].append(ud)
00257         ### une deuxième passe pour récupérer et associer les partitions
00258         for path in self.enumDev:
00259             ud=uDisk(path, self.bus, checkable)
00260             for d in self.disks.keys():
00261                 if ud.master() == d.path:
00262                     self.disks[d].append(ud)
00263         ### on s'assure que chaque disque a bien un propriétaire
00264         ### sinon on le demande
00265         self.getFirstFats() # premier passage, pour repérer chaque partition FAT
00266         for d in self.disks.keys():
00267             d.owner=d.ensureOwner()
00268         ### on fabrique la liste des premières partitions FAT,
00269         ### en positionnant les attributs de propriétaire
00270         self.firstFats = self.getFirstFats(setOwners=True)
00271         ### on monte les partitions si nécessaire
00272         if self.access=="firstFat":
00273             for p in self.firstFats:
00274                 p.ensureMounted()
00275 
 Tout Classes Espaces de nommage Fichiers Fonctions Variables