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     #         renvoie un identifiant unique.
00077     #         reprend l'Uuid hérité de la classe parente, mais y ajoute
00078     #         un nombre supplémentaire, éventuellement placé par "tatouage"
00079     #         sur la clé.
00080     #         @return un identifiant supposément unique
00081     #         
00082     def uniqueId(self):
00083         return "%s~%s" %(self.getFatUuid(), self.tattoo())
00084 
00085     ##
00086     # 
00087     #         Renvoie un tatouage présent sur la clé, quitte à le créer.
00088     #         @result un tatouage, supposément unique.
00089     #         
00090     def tattoo(self):
00091         fatPath=self.getFirstFat().ensureMounted()
00092         tattooFileName=os.path.join(fatPath,".scolasync-tattoo")
00093         if os.path.exists(tattooFileName):
00094             tattoo_=open(tattooFileName,"r").read()
00095             # on vérifie par acquis de conscience, qu'il n'existe pas
00096             # un tatouage identique dans la base de données
00097             # s'il est déjà présent : on le change. Il faudrait
00098             # probablement aussi prévenir le prof !!!
00099             if tattoo_ in db.tattooList():
00100                 tattoo_="%12.2f" %time.time()
00101                 time.sleep(0.05)
00102         else:
00103             tattoo_="%12.2f" %time.time()
00104             time.sleep(0.05)
00105             outfile=open(tattooFileName,"w")
00106             outfile.write(tattoo_)
00107             outfile.close()
00108         return tattoo_
00109     
00110     ##
00111     # 
00112     #         Lit un dictionnaire indexé par le noms de vendeurs et les noms de modèle
00113     #         pour associer à ces modèles particuliers un répertoire visible.
00114     #         voir la fonction visibleDir. Ce dictionnaire est dans le fichier
00115     #         /usr/share/scolasync/marques.py ou dans ${HOME}/.scolasync/marques.py,
00116     #         (sous Linux) cette dernière place étant prépondérante.
00117     #         
00118     def readQuirks (self):
00119         f1="/usr/share/scolasync/marques.py"
00120         f2=os.path.expanduser(markFileName)
00121         if os.path.exists(f2):
00122             f=f2
00123         else:
00124             f=f1
00125         result=eval(open(f,"r").read())
00126         return result
00127         
00128     ##
00129     # 
00130     #         Renvoie le répertoire particulier de la partition qui sera visible
00131     #         quand le baladeur est utilisé par son interface utilisateur. Ce
00132     #         répertoire peut varier selon les vendeurs et les modèles.
00133     #         
00134     def visibleDir(self):
00135         k=self.vendor+":"+self.model
00136         if k in self.visibleDirs.keys():
00137             return self.visibleDirs[k]
00138         else:
00139             return "."
00140 
00141     ##
00142     # 
00143     #         Méthode statique
00144     #         renvoie des titres pour les items obtenus par __getitem__
00145     #         la deuxième colonne sera toujours le propriétaire
00146     #         @param checkable vrai si le premier en-tête correspond à une colonne de cases à cocher
00147     #         @param locale la locale, pour traduire les titres
00148     #         @return une liste de titres de colonnes
00149     #         
00150     def headers(checkable=False,locale="C"):
00151         result=usbDisk.uDisk.headers(checkable, locale)
00152         ownerProp=QApplication.translate("uDisk","owner",None, QApplication.UnicodeUTF8)
00153         result.insert(1,ownerProp)
00154         return result
00155 
00156     ##
00157     # 
00158     #         renvoie un nom de propriétaire dans tous les cas.
00159     #         
00160     def ownerByDb(self):
00161         if self.owner != "":
00162             return self.owner
00163         else:
00164             s=db.readStudent(self.stickid, self.getFatUuid(), self.tattoo())
00165             if s != None:
00166                 self.owner=s
00167                 return s
00168             else:
00169                 return QApplication.translate("Dialog","inconnu",None, QApplication.UnicodeUTF8)
00170 
00171     ##
00172     # 
00173     #         renvoie un élément de listage de données internes au disque
00174     #         Fait en sorte que la deuxième colonne soit toujours le propriétaire
00175     #         @param n un nombre
00176     #         @param checkable vrai si on doit renvoyer une propriété supplémentaire pour n==0
00177     #         @return si checkable est vrai, 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
00178     #         
00179     def __getitem__(self,n):
00180         propListe=usbDisk.uDisk.headers()
00181         if self.checkable:
00182             if n==0:
00183                 return self.selected
00184             elif n==1:
00185                 return self.ownerByDb()
00186             elif n==2:
00187                 return self.unNumberProp(0)
00188             else:
00189                 return self.unNumberProp(n-1)
00190         else:
00191             if n==0:
00192                 return self.unNumberProp(0)
00193             elif n==1:
00194                 return self.ownerByDb()
00195             else:
00196                 return self.unNumberProp(n)
00197     
00198     
00199     headers = staticmethod(headers)
00200 
00201     ##
00202     # 
00203     #         Demande un nom de propriétaire si celui-ci n'est pas encore défini
00204     #         pour cette clé USB
00205     #         @return un nom de propriétaire si c'est un disque, sinon None
00206     #         
00207     def ensureOwner(self):
00208         if self.getProp("device-is-drive") and self.isUsbDisk():
00209             if not db.knowsId(self.stickid, self.getFatUuid(), self.tattoo()) :
00210                 prompt=QApplication.translate("Dialog","La cle %1<br>n'est pas identifiee, donnez le nom du proprietaire",None, QApplication.UnicodeUTF8).arg(self.stickid)
00211                 text,ok = QInputDialog.getText(None,
00212                                                QApplication.translate("Dialog","Entrer un nom",None, QApplication.UnicodeUTF8),
00213                                                prompt)
00214                 if ok and len(text)>0:
00215                     db.writeStudent(self.stickid, self.getFatUuid(), self.tattoo(), u"%s" %text.toUtf8())
00216         return db.readStudent(self.stickid, self.getFatUuid(), self.tattoo())
00217         
00218 ##
00219 # 
00220 #     Une classe qui fournit une collection de disques USB connectés,
00221 #     avec leurs propriétaires. On a répliqué le code de la classe parente,
00222 #     ne sachant pas si le contructeur prendrait les uDisks dans le module
00223 #     courant ou dans le module parent. Pour éviter les confusion il faudrait
00224 #     peut-être faire une classe abstraite Available
00225 #     
00226 class Available(usbDisk.Available):
00227     ##
00228     # 
00229     #         @param checkable : vrai si on veut pouvoir cocher les disques de la
00230     #           collection. Faux par défaut.
00231     #         @param access définit le type d'accès souhaité. Par défaut, c'est "disk"
00232     #           c'est à dire qu'on veut la liste des disques USB. Autres valeurs
00233     #           possibles : "firstFat" pour les premières partitions vfat.
00234     #         
00235     def __init__(self, checkable=False, access="disk"):
00236         self.checkable=checkable
00237         self.access=access
00238         self.bus = dbus.SystemBus()
00239         proxy = self.bus.get_object("org.freedesktop.UDisks", 
00240                                     "/org/freedesktop/UDisks")
00241         iface = dbus.Interface(proxy, "org.freedesktop.UDisks")
00242         self.disks={}
00243         self.enumDev=iface.EnumerateDevices()
00244         ### récupération des disques usb dans le dictionnaire self.disks
00245         for path in self.enumDev:
00246             ud=uDisk(path, self.bus, checkable)
00247             if ud.isUsbDisk():
00248                 self.disks[ud]=[]
00249                 # cas des disques sans partitions
00250                 if bool(ud.getProp("device-is-partition-table")) == False:
00251                     # la propriété "device-is-partition-table" est fausse,
00252                     # probablement qu'il y a un système de fichiers
00253                     self.disks[ud].append(ud)
00254         ### une deuxième passe pour récupérer et associer les partitions
00255         for path in self.enumDev:
00256             ud=uDisk(path, self.bus, checkable)
00257             for d in self.disks.keys():
00258                 if ud.master() == d.path:
00259                     self.disks[d].append(ud)
00260         ### on fabrique la liste des premières partitions FAT
00261         self.firstFats = self.getFirstFats()
00262         ### on monte les partitions si nécessaire
00263         if self.access=="firstFat":
00264             for p in self.firstFats:
00265                 p.ensureMounted()
00266         ### on s'assure que chaque disque a bien un propriétaire
00267         ### sinon on le demande
00268         for d in self.disks.keys():
00269             d.owner=d.ensureOwner()
00270     
00271 
 Tout Classes Espaces de nommage Fichiers Fonctions Variables