# 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