Show
Ignore:
Timestamp:
09/27/08 22:02:37 (16 years ago)
Author:
jerome
Message:

Removed unnecessary spaces at EOL.

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • pykota/trunk/bin/cupspykota

    r3411 r3413  
    99# the Free Software Foundation, either version 3 of the License, or 
    1010# (at your option) any later version. 
    11 #  
     11# 
    1212# This program is distributed in the hope that it will be useful, 
    1313# but WITHOUT ANY WARRANTY; without even the implied warranty of 
    1414# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
    1515# GNU General Public License for more details. 
    16 #  
     16# 
    1717# You should have received a copy of the GNU General Public License 
    1818# along with this program.  If not, see <http://www.gnu.org/licenses/>. 
     
    5151from pykota.accounter import openAccounter 
    5252from pykota import cups 
    53      
    54 class FakeObject :         
     53 
     54class FakeObject : 
    5555    """Fake object.""" 
    5656    def __init__(self, name) : 
    5757        """Fake init.""" 
    5858        self.Name = name 
    59          
    60 class FakePrinter(FakeObject) :         
     59 
     60class FakePrinter(FakeObject) : 
    6161    """Fake printer instance.""" 
    6262    pass 
    63      
    64 class FakeUser(FakeObject) :     
     63 
     64class FakeUser(FakeObject) : 
    6565    """Fake user instance.""" 
    6666    def __init__(self, name) : 
     
    6868        self.Email = name 
    6969        FakeObject.__init__(self, name) 
    70      
     70 
    7171class CUPSBackend(PyKotaTool) : 
    7272    """Base class for tools with no database access.""" 
     
    8383        self.lockfilename = None 
    8484        self.lockfile = None 
    85          
    86     def deferredInit(self) :     
     85 
     86    def deferredInit(self) : 
    8787        """Deferred initialization.""" 
    8888        PyKotaTool.deferredInit(self) 
     
    9191            username = self.effectiveUserName 
    9292            raise config.PyKotaConfigError, _("User %(username)s is not allowed to read ~pykota/pykotadmin.conf, you must check the permissions.") % locals() 
    93          
    94     def enableSigInt(self) :     
     93 
     94    def enableSigInt(self) : 
    9595        """Enables the SIGINT signal (which raises KeyboardInterrupt).""" 
    9696        signal.signal(signal.SIGINT, self.oldSigIntHandler) 
    97          
    98     def waitForLock(self) :     
     97 
     98    def waitForLock(self) : 
    9999        """Waits until we can acquire the lock file.""" 
    100100        self.logdebug("Waiting for lock %s to become available..." % self.lockfilename) 
     
    104104                # open the lock file, optionally creating it if needed. 
    105105                self.lockfile = open(self.lockfilename, "a+") 
    106                  
     106 
    107107                # we wait indefinitely for the lock to become available. 
    108108                # works over NFS too. 
    109109                fcntl.lockf(self.lockfile, fcntl.LOCK_EX) 
    110110                haslock = True 
    111                  
     111 
    112112                self.logdebug("Lock %s acquired." % self.lockfilename) 
    113                  
     113 
    114114                # Here we save the PID in the lock file, but we don't use 
    115115                # it, because the lock file may be in a directory shared 
     
    120120                self.lockfile.write(str(self.pid)) 
    121121                self.lockfile.flush() 
    122             except IOError, msg :             
     122            except IOError, msg : 
    123123                self.logdebug("I/O Error while waiting for lock %s : %s" % (self.lockfilename, msg)) 
    124124                time.sleep(0.25) 
    125                      
    126     def discoverOtherBackends(self) :     
     125 
     126    def discoverOtherBackends(self) : 
    127127        """Discovers the other CUPS backends. 
    128          
     128 
    129129           Executes each existing backend in turn in device enumeration mode. 
    130130           Returns the list of available backends. 
    131             
     131 
    132132           Unfortunately this method can't output any debug information 
    133133           to stdout or stderr, else CUPS considers that the device is 
     
    151151                    # process doesn't exist anymore 
    152152                    os.remove(lockfilename) 
    153              
     153 
    154154        if not os.path.exists(lockfilename) : 
    155155            lockfile = open(lockfilename, "w") 
     
    159159                                for b in os.listdir(directory) \ 
    160160                                    if os.access(os.path.join(directory, b), os.X_OK) \ 
    161                                         and (b != myname)]  
    162             for backend in allbackends :                             
     161                                        and (b != myname)] 
     162            for backend in allbackends : 
    163163                answer = os.popen(backend, "r") 
    164164                try : 
    165165                    devices = [line.strip() for line in answer.readlines()] 
    166                 except :     
     166                except : 
    167167                    devices = [] 
    168168                status = answer.close() 
    169169                if status is None : 
    170170                    for d in devices : 
    171                         # each line is of the form :  
     171                        # each line is of the form : 
    172172                        # 'xxxx xxxx "xxxx xxx" "xxxx xxx"' 
    173173                        # so we have to decompose it carefully 
     
    186186                        try : 
    187187                            (devicetype, device, name, fullname) = arguments 
    188                         except ValueError :     
     188                        except ValueError : 
    189189                            pass    # ignore this 'bizarre' device 
    190                         else :     
     190                        else : 
    191191                            if name.startswith('"') and name.endswith('"') : 
    192192                                name = name[1:-1] 
     
    202202                             % (self.myname, self.MyName, self.MyName)) 
    203203        return available 
    204                          
    205     def checkCUPSVersion(self) :                     
     204 
     205    def checkCUPSVersion(self) : 
    206206        """Checks if CUPS is not v1.3.4 or higher.""" 
    207207        fullversion = os.environ.get("SOFTWARE", "") 
     
    210210            try : 
    211211               (major, minor, release) = [int(p) for p in vnum.split(".")] 
    212             except ValueError :    
     212            except ValueError : 
    213213                pass 
    214             else :     
     214            else : 
    215215                return (major > 1) \ 
    216216                        or ((major == 1) and (minor > 3)) \ 
    217217                        or ((major == 1) and (minor == 3) and (release >= 4)) 
    218218        return False 
    219          
    220     def initBackendParameters(self) :     
     219 
     220    def initBackendParameters(self) : 
    221221        """Initializes the backend's attributes.""" 
    222         # check that the DEVICE_URI environment variable's value is  
     222        # check that the DEVICE_URI environment variable's value is 
    223223        # prefixed with self.myname otherwise don't touch it. 
    224         # If this is the case, we have to remove the prefix from  
    225         # the environment before launching the real backend  
     224        # If this is the case, we have to remove the prefix from 
     225        # the environment before launching the real backend 
    226226        self.logdebug("Initializing backend...") 
    227          
     227 
    228228        if not self.checkCUPSVersion() : 
    229229            self.printInfo("BEWARE : CUPS is too old. You should use CUPS v1.3.4 or higher.", "error") 
    230          
     230 
    231231        self.PrinterName = os.environ.get("PRINTER", "") 
    232232        directories = [ self.config.getPrinterDirectory(self.PrinterName), 
     
    240240            else : 
    241241                self.printInfo("Insufficient permissions to access to temporary directory %s" % direc, "warn") 
    242                  
     242 
    243243        self.Action = "ALLOW"   # job allowed by default 
    244244        self.Reason = None 
     
    247247            if copies < 1 : 
    248248                raise ValueError 
    249         except (ValueError, TypeError) :     
     249        except (ValueError, TypeError) : 
    250250            self.logdebug("Invalid number of copies '%s', using 1 instead." % sys.argv[4]) 
    251251            copies = 1 
    252252        if len(sys.argv) == 7 : 
    253253            fname = sys.argv[6] # read job's datas from file 
    254         else :     
    255             fname = None        # read job's datas from stdin             
    256              
     254        else : 
     255            fname = None        # read job's datas from stdin 
     256 
    257257        self.Ticket = cups.JobTicket(sys.argv[1].strip(), self.PrinterName, \ 
    258258                                     copies, fname, sys.argv[5].strip()) 
    259         self.UserName = self.Ticket.OriginatingUserName                              
    260                                       
     259        self.UserName = self.Ticket.OriginatingUserName 
     260 
    261261        self.DataFile = (os.path.join(self.Directory, "%s-%s-%s-%s" % \ 
    262262                   (self.myname, self.PrinterName, self.UserName, self.Ticket.JobId))).encode(sys.getfilesystemencoding(), "replace") 
    263          
     263 
    264264        muststartwith = "%s:" % self.myname 
    265265        device_uri = os.environ.get("DEVICE_URI", "") 
     
    268268            device_uri = fulldevice_uri[len(muststartwith):] 
    269269            for i in range(2) : 
    270                 if device_uri.startswith("/") :   
     270                if device_uri.startswith("/") : 
    271271                    device_uri = device_uri[1:] 
    272272        try : 
    273             (backend, destination) = device_uri.split(":", 1)  
    274         except ValueError :     
     273            (backend, destination) = device_uri.split(":", 1) 
     274        except ValueError : 
    275275            if not device_uri : 
    276276                self.logdebug("Not attached to an existing print queue.") 
    277277                backend = "" 
    278278                printerhostname = "" 
    279             else :     
     279            else : 
    280280                raise PyKotaToolError, "Invalid DEVICE_URI : %s\n" % device_uri 
    281         else :         
     281        else : 
    282282            if backend == "hp" : 
    283283                try : 
    284284                    printerhostname = destination.split("=")[1] # hp:/net/HP_LaserJet_8000_Series?ip=192.168.100.100 
    285                 except IndexError :     
     285                except IndexError : 
    286286                    self.logdebug("Unsupported hplip URI %s" % device_uri) 
    287                     printerhostname = ""  
    288             else :     
     287                    printerhostname = "" 
     288            else : 
    289289                while destination.startswith("/") : 
    290290                    destination = destination[1:] 
    291                 checkauth = destination.split("@", 1)     
     291                checkauth = destination.split("@", 1) 
    292292                if len(checkauth) == 2 : 
    293293                    destination = checkauth[1] 
    294294                printerhostname = destination.split("/")[0].split(":")[0] 
    295              
    296         self.PrinterHostName = printerhostname     
     295 
     296        self.PrinterHostName = printerhostname 
    297297        self.RealBackend = backend 
    298298        self.DeviceURI = device_uri 
    299          
     299 
    300300        if self.Ticket.BillingCode is None : 
    301301            self.OriginalJobBillingCode = None 
    302         else :     
     302        else : 
    303303            self.OriginalJobBillingCode = self.Ticket.BillingCode[:] 
    304              
     304 
    305305        baselockfilename = self.DeviceURI.replace("/", ".") 
    306306        baselockfilename = baselockfilename.replace(":", ".") 
     
    309309        baselockfilename = baselockfilename.replace("@", ".") 
    310310        self.lockfilename = os.path.join(self.Directory, "%s-%s..LCK" % (self.myname, baselockfilename)) 
    311          
     311 
    312312        self.logdebug("Backend : %s" % self.RealBackend) 
    313313        self.logdebug("DeviceURI : %s" % self.DeviceURI) 
     
    319319        self.logdebug("Copies : %s" % self.Ticket.Copies) 
    320320        self.logdebug("Options : %s" % self.Ticket.Options) 
    321         self.logdebug("Directory : %s" % self.Directory)  
     321        self.logdebug("Directory : %s" % self.Directory) 
    322322        self.logdebug("DataFile : %s" % self.DataFile) 
    323323        self.logdebug("JobBillingCode : %s" % self.Ticket.BillingCode) 
    324324        self.logdebug("JobOriginatingHostName : %s" % self.Ticket.OriginatingHostName) 
    325          
     325 
    326326        # fakes some entries to allow for external mailto 
    327327        # before real entries are extracted from the database. 
    328328        self.User = FakeUser(self.UserName) 
    329329        self.Printer = FakePrinter(self.PrinterName) 
    330          
     330 
    331331        self.enableSigInt() 
    332332        self.logdebug("Backend initialized.") 
    333          
     333 
    334334    def overwriteJobAttributes(self) : 
    335335        """Overwrites some of the job's attributes if needed.""" 
     
    337337        # First overwrite the job ticket 
    338338        self.overwriteJobTicket() 
    339          
     339 
    340340        # do we want to strip out the Samba/Winbind domain name ? 
    341341        separator = self.config.getWinbindSeparator() 
    342342        if separator is not None : 
    343343            self.UserName = self.UserName.split(separator)[-1] 
    344              
    345         # this option is deprecated, and we want to tell people     
     344 
     345        # this option is deprecated, and we want to tell people 
    346346        # this is the case. 
    347347        tolower = self.config.getUserNameToLower() 
     
    352352            if self.config.isTrue(tolower) : 
    353353                self.UserName = self.UserName.lower() 
    354                  
    355         # Now use the newer and more complete 'usernamecase' directive.     
    356         casechange = self.config.getUserNameCase()     
     354 
     355        # Now use the newer and more complete 'usernamecase' directive. 
     356        casechange = self.config.getUserNameCase() 
    357357        if casechange != "native" : 
    358358            self.UserName = getattr(self.UserName, casechange)() 
    359              
    360         # do we want to strip some prefix off of titles ?     
     359 
     360        # do we want to strip some prefix off of titles ? 
    361361        stripprefix = self.config.getStripTitle(self.PrinterName) 
    362362        if stripprefix : 
     
    365365                                      % (stripprefix, self.Ticket.Title)) 
    366366                self.Ticket.Title = self.Ticket.Title[len(stripprefix):] 
    367                  
     367 
    368368        self.logdebug("Username : %s" % self.UserName) 
    369369        self.logdebug("BillingCode : %s" % self.Ticket.BillingCode) 
    370370        self.logdebug("Title : %s" % self.Ticket.Title) 
    371371        self.logdebug("Job's attributes sanitizing done.") 
    372                  
     372 
    373373    def didUserConfirm(self) : 
    374374        """Asks for user confirmation through an external script. 
    375          
     375 
    376376           returns False if the end user wants to cancel the job, else True. 
    377377        """ 
    378378        self.logdebug("Checking if we have to ask for user's confirmation...") 
    379         answer = None                          
     379        answer = None 
    380380        confirmationcommand = self.config.getAskConfirmation(self.PrinterName) 
    381381        if confirmationcommand : 
     
    388388                    if answer == "CANCEL" : 
    389389                        break 
    390             except IOError, msg :             
     390            except IOError, msg : 
    391391                self.logdebug("IOError while reading subprocess' output : %s" % msg) 
    392             inputfile.close()     
     392            inputfile.close() 
    393393            self.logdebug("User's confirmation received : %s" % (((answer == "CANCEL") and "CANCEL") or "CONTINUE")) 
    394         else :     
     394        else : 
    395395            self.logdebug("No need to ask for user's confirmation, job processing will continue.") 
    396         return (answer != "CANCEL")     
    397          
    398     def overwriteJobTicket(self) :     
     396        return (answer != "CANCEL") 
     397 
     398    def overwriteJobTicket(self) : 
    399399        """Should we overwrite the job's ticket (username and billingcode) ?""" 
    400400        self.logdebug("Checking if we need to overwrite the job ticket...") 
     
    414414                        self.logdebug("Seen CANCEL command.") 
    415415                        action = "CANCEL" 
    416                     elif line.startswith("USERNAME=") :     
     416                    elif line.startswith("USERNAME=") : 
    417417                        username = line.split("=", 1)[1].strip().decode(self.charset, "replace") 
    418418                        self.logdebug("Seen new username [%s]" % username) 
    419                     elif line.startswith("BILLINGCODE=") :     
     419                    elif line.startswith("BILLINGCODE=") : 
    420420                        billingcode = line.split("=", 1)[1].strip().decode(self.charset, "replace") 
    421421                        self.logdebug("Seen new billing code [%s]" % billingcode) 
     
    423423                        reason = line.split("=", 1)[1].strip().decode(self.charset, "replace") 
    424424                        self.logdebug("Seen new reason [%s]" % reason) 
    425             except IOError, msg :             
     425            except IOError, msg : 
    426426                self.logdebug("IOError while reading subprocess' output : %s" % msg) 
    427             inputfile.close()     
    428              
     427            inputfile.close() 
     428 
    429429            # now overwrite the job's ticket if new data was supplied 
    430430            if action == "DENY" : 
     
    441441                    self.UserName = username 
    442442                if billingcode is not None : 
    443                     self.Ticket.BillingCode = billingcode  
     443                    self.Ticket.BillingCode = billingcode 
    444444        self.logdebug("Job ticket overwriting done.") 
    445              
     445 
    446446    def saveDatasAndCheckSum(self) : 
    447447        """Saves the input datas into a static file.""" 
    448448        self.logdebug("Duplicating data stream into %s" % self.DataFile) 
    449449        mustclose = 0 
    450         outfile = open(self.DataFile, "wb")     
     450        outfile = open(self.DataFile, "wb") 
    451451        if self.Ticket.FileName is not None : 
    452452            infile = open(self.Ticket.FileName, "rb") 
    453453            self.logdebug("Reading input datas from %s" % self.Ticket.FileName) 
    454454            mustclose = 1 
    455         else :     
     455        else : 
    456456            infile = sys.stdin 
    457457            self.logdebug("Reading input datas from stdin") 
     
    461461        checksum = md5.new() 
    462462        while 1 : 
    463             data = infile.read(CHUNK)  
     463            data = infile.read(CHUNK) 
    464464            if not data : 
    465465                break 
    466             sizeread += len(data)     
     466            sizeread += len(data) 
    467467            outfile.write(data) 
    468             checksum.update(data)     
     468            checksum.update(data) 
    469469            if not (dummy % 32) : # Only display every 2 Mb 
    470470                self.logdebug("%s bytes saved..." % sizeread) 
    471             dummy += 1     
    472         if mustclose :     
     471            dummy += 1 
     472        if mustclose : 
    473473            infile.close() 
    474              
     474 
    475475        outfile.close() 
    476         self.JobSizeBytes = sizeread     
     476        self.JobSizeBytes = sizeread 
    477477        self.JobMD5Sum = checksum.hexdigest() 
    478          
     478 
    479479        self.logdebug("JobSizeBytes : %s" % self.JobSizeBytes) 
    480480        self.logdebug("JobMD5Sum : %s" % self.JobMD5Sum) 
    481481        self.logdebug("Data stream duplicated into %s" % self.DataFile) 
    482              
     482 
    483483    def clean(self) : 
    484484        """Cleans up the place.""" 
     
    487487            try : 
    488488                keep = self.config.getPrinterKeepFiles(self.PrinterName) 
    489             except AttributeError :     
     489            except AttributeError : 
    490490                keep = False 
    491491            if not keep : 
     
    497497                else : 
    498498                    self.logdebug("Work file %s has been deleted." % self.DataFile) 
    499             else :     
     499            else : 
    500500                self.logdebug("Work file %s will be kept." % self.DataFile) 
    501         PyKotaTool.clean(self)     
     501        PyKotaTool.clean(self) 
    502502        if self.lockfile is not None : 
    503503            self.logdebug("Unlocking %s..." %  self.lockfilename) 
     
    505505                fcntl.lockf(self.lockfile, fcntl.LOCK_UN) 
    506506                self.lockfile.close() 
    507             except :     
     507            except : 
    508508                self.printInfo("Problem while unlocking %s" % self.lockfilename, "error") 
    509             else :     
     509            else : 
    510510                self.logdebug("%s unlocked." % self.lockfilename) 
    511511        self.logdebug("Clean.") 
    512              
    513     def precomputeJobSize(self) :     
     512 
     513    def precomputeJobSize(self) : 
    514514        """Computes the job size with a software method.""" 
    515515        self.logdebug("Precomputing job's size...") 
     
    518518        self.softwareJobSize = self.preaccounter.getJobSize(None) 
    519519        self.logdebug("Precomputed job's size is %s pages." % self.softwareJobSize) 
    520          
    521     def precomputeJobPrice(self) :     
     520 
     521    def precomputeJobPrice(self) : 
    522522        """Precomputes the job price with a software method.""" 
    523523        self.logdebug("Precomputing job's price...") 
     
    525525        self.logdebug("Precomputed job's price is %.3f credits." \ 
    526526                                   % self.softwareJobPrice) 
    527          
    528     def exportJobInfo(self) :     
     527 
     528    def exportJobInfo(self) : 
    529529        """Exports the actual job's attributes to the environment.""" 
    530530        self.logdebug("Exporting job information to the environment...") 
     
    550550        setenv("PYKOTAPRECOMPUTEDJOBSIZE", str(self.softwareJobSize), self.charset) 
    551551        self.logdebug("Environment updated.") 
    552          
     552 
    553553    def exportUserInfo(self) : 
    554554        """Exports user information to the environment.""" 
     
    559559        setenv("PYKOTALIFETIMEPAID", str(self.User.LifeTimePaid or 0.0), self.charset) 
    560560        setenv("PYKOTAUSERDESCRIPTION", self.User.Description or "", self.charset) 
    561          
     561 
    562562        setenv("PYKOTAPAGECOUNTER", str(self.UserPQuota.PageCounter or 0), self.charset) 
    563563        setenv("PYKOTALIFEPAGECOUNTER", str(self.UserPQuota.LifePageCounter or 0), self.charset) 
     
    566566        setenv("PYKOTADATELIMIT", str(self.UserPQuota.DateLimit), self.charset) 
    567567        setenv("PYKOTAWARNCOUNT", str(self.UserPQuota.WarnCount), self.charset) 
    568          
     568 
    569569        # TODO : move this elsewhere once software accounting is done only once. 
    570570        setenv("PYKOTAPRECOMPUTEDJOBPRICE", str(self.softwareJobPrice), self.charset) 
    571          
     571 
    572572        self.logdebug("Environment updated.") 
    573          
     573 
    574574    def exportPrinterInfo(self) : 
    575575        """Exports printer information to the environment.""" 
     
    584584        setenv("PYKOTAPRICEPERJOB", str(self.Printer.PricePerJob or 0), self.charset) 
    585585        self.logdebug("Environment updated.") 
    586          
     586 
    587587    def exportPhaseInfo(self, phase) : 
    588588        """Exports phase information to the environment.""" 
     
    590590        setenv("PYKOTAPHASE", phase, self.charset) 
    591591        self.logdebug("Environment updated.") 
    592          
     592 
    593593    def exportJobSizeAndPrice(self) : 
    594594        """Exports job's size and price information to the environment.""" 
     
    597597        setenv("PYKOTAJOBPRICE", str(self.JobPrice), self.charset) 
    598598        self.logdebug("Environment updated.") 
    599          
     599 
    600600    def exportReason(self) : 
    601601        """Exports the job's action status and optional reason.""" 
     
    605605            setenv("PYKOTAREASON", self.Reason or "", self.charset) 
    606606        self.logdebug("Environment updated.") 
    607          
    608     def acceptJob(self) :         
     607 
     608    def acceptJob(self) : 
    609609        """Returns the appropriate exit code to tell CUPS all is OK.""" 
    610610        return 0 
    611              
    612     def removeJob(self) :             
     611 
     612    def removeJob(self) : 
    613613        """Returns the appropriate exit code to let CUPS think all is OK. 
    614          
     614 
    615615           Returning 0 (success) prevents CUPS from stopping the print queue. 
    616         """    
     616        """ 
    617617        return 0 
    618          
     618 
    619619    def launchPreHook(self) : 
    620620        """Allows plugging of an external hook before the job gets printed.""" 
     
    624624            retcode = os.system(prehook) 
    625625            self.logdebug("pre-hook exited with status %s." % retcode) 
    626          
     626 
    627627    def launchPostHook(self) : 
    628628        """Allows plugging of an external hook after the job gets printed and/or denied.""" 
     
    632632            retcode = os.system(posthook) 
    633633            self.logdebug("post-hook exited with status %s." % retcode) 
    634              
    635     def improveMessage(self, message) :         
     634 
     635    def improveMessage(self, message) : 
    636636        """Improves a message by adding more informations in it if possible.""" 
    637637        try : 
     
    640640                                        self.Ticket.JobId, \ 
    641641                                        message) 
    642         except :                                                
     642        except : 
    643643            return message 
    644          
    645     def logdebug(self, message) :         
     644 
     645    def logdebug(self, message) : 
    646646        """Improves the debug message before outputting it.""" 
    647647        PyKotaTool.logdebug(self, self.improveMessage(message)) 
    648          
    649     def printInfo(self, message, level="info") :         
     648 
     649    def printInfo(self, message, level="info") : 
    650650        """Improves the informational message before outputting it.""" 
    651651        self.logger.log_message(self.improveMessage(message), level) 
    652      
     652 
    653653    def startingBanner(self, withaccounting) : 
    654654        """Retrieves a starting banner for current printer and returns its content.""" 
     
    656656        self.printBanner(self.config.getStartingBanner(self.PrinterName), withaccounting) 
    657657        self.logdebug("Starting banner retrieved.") 
    658      
     658 
    659659    def endingBanner(self, withaccounting) : 
    660660        """Retrieves an ending banner for current printer and returns its content.""" 
     
    662662        self.printBanner(self.config.getEndingBanner(self.PrinterName), withaccounting) 
    663663        self.logdebug("Ending banner retrieved.") 
    664          
     664 
    665665    def printBanner(self, bannerfileorcommand, withaccounting) : 
    666666        """Reads a banner or generates one through an external command. 
    667          
     667 
    668668           Returns the banner's content in a format which MUST be accepted 
    669669           by the printer. 
     
    691691                try : 
    692692                    fh = open(bannerfileorcommand, 'rb') 
    693                 except IOError, msg :     
     693                except IOError, msg : 
    694694                    self.printInfo("Impossible to open %s : %s" \ 
    695695                                       % (bannerfileorcommand, msg), "error") 
    696                 else :     
     696                else : 
    697697                    self.runOriginalBackend(fh, isBanner=1) 
    698698                    fh.close() 
     
    701701                            self.BannerSize += 1 # TODO : fix this by passing the banner's content through software accounting 
    702702        self.logdebug("Banner printed...") 
    703                  
     703 
    704704    def handleBanner(self, bannertype, withaccounting) : 
    705705        """Handles the banner with or without accounting.""" 
    706706        if withaccounting : 
    707707            acc = "with" 
    708         else :     
     708        else : 
    709709            acc = "without" 
    710710        self.logdebug("Handling %s banner %s accounting..." % (bannertype, acc)) 
     
    735735                        if (avoidduplicatebanners == "YES") : 
    736736                            printbanner = False 
    737                         else :     
    738                             # avoidduplicatebanners is an integer, since NO,  
     737                        else : 
     738                            # avoidduplicatebanners is an integer, since NO, 
    739739                            # YES and 0 are already handled 
    740740                            now = DateTime.now() 
     
    746746                            self.logdebug("Difference with previous job : %.2f seconds. Try to avoid banners for : %.2f seconds." % (difference, avoidduplicatebanners)) 
    747747                            if difference < avoidduplicatebanners : 
    748                                 self.logdebug("Duplicate banner avoided because previous banner is less than %.2f seconds old." % avoidduplicatebanners)  
     748                                self.logdebug("Duplicate banner avoided because previous banner is less than %.2f seconds old." % avoidduplicatebanners) 
    749749                                printbanner = False 
    750750                            else : 
     
    753753                    getattr(self, "%sBanner" % bannertype)(withaccounting) 
    754754        self.logdebug("%s banner done." % bannertype.title()) 
    755          
    756     def sanitizeJobSize(self) :     
     755 
     756    def sanitizeJobSize(self) : 
    757757        """Sanitizes the job's size if needed.""" 
    758758        # TODO : there's a difficult to see bug here when banner accounting is activated and hardware accounting is used. 
     
    772772                    if replacement == "PRECOMPUTED" : 
    773773                        self.JobSize = self.softwareJobSize 
    774                     else :     
     774                    else : 
    775775                        self.JobSize = replacement 
    776776        self.logdebug("Job's size sanitized.") 
    777                          
    778     def getPrinterUserAndUserPQuota(self) :         
     777 
     778    def getPrinterUserAndUserPQuota(self) : 
    779779        """Returns a tuple (policy, printer, user, and user print quota) on this printer. 
    780          
     780 
    781781           "OK" is returned in the policy if both printer, user and user print quota 
    782782           exist in the Quota Storage. 
    783783           Otherwise, the policy as defined for this printer in pykota.conf is returned. 
    784             
     784 
    785785           If policy was set to "EXTERNAL" and one of printer, user, or user print quota 
    786786           doesn't exist in the Quota Storage, then an external command is launched, as 
     
    789789           or users, for example, and finally extracting printer, user and user print 
    790790           quota from the Quota Storage is tried a second time. 
    791             
     791 
    792792           "EXTERNALERROR" is returned in case policy was "EXTERNAL" and an error status 
    793793           was returned by the external command. 
     
    802802                break 
    803803            (policy, args) = self.config.getPrinterPolicy(self.PrinterName) 
    804             if policy == "EXTERNAL" :     
     804            if policy == "EXTERNAL" : 
    805805                commandline = self.formatCommandLine(args, user, printer) 
    806806                if not printer.Exists : 
     
    814814                    policy = "EXTERNALERROR" 
    815815                    break 
    816             else :         
     816            else : 
    817817                if not printer.Exists : 
    818818                    self.printInfo(_("Printer %s not registered in the PyKota system, applying default policy (%s)") % (self.PrinterName, policy)) 
     
    822822                    self.printInfo(_("User %s doesn't have quota on printer %s in the PyKota system, applying default policy (%s)") % (self.UserName, self.PrinterName, policy)) 
    823823                break 
    824                  
    825         if policy == "EXTERNAL" :     
     824 
     825        if policy == "EXTERNAL" : 
    826826            if not printer.Exists : 
    827827                self.printInfo(_("Printer %s still not registered in the PyKota system, job will be rejected") % self.PrinterName) 
     
    830830            if not userpquota.Exists : 
    831831                self.printInfo(_("User %s still doesn't have quota on printer %s in the PyKota system, job will be rejected") % (self.UserName, self.PrinterName)) 
    832         self.Policy = policy          
     832        self.Policy = policy 
    833833        self.Printer = printer 
    834834        self.User = user 
    835835        self.UserPQuota = userpquota 
    836836        self.logdebug("Retrieval of printer, user and user print quota entry done.") 
    837          
    838     def getBillingCode(self) :     
     837 
     838    def getBillingCode(self) : 
    839839        """Extracts the billing code from the database. 
    840           
     840 
    841841           An optional script is launched to notify the user when 
    842842           the billing code is unknown and PyKota was configured to 
     
    858858                    if self.BillingCode.Exists : 
    859859                        self.logdebug(msg + "has been created.") 
    860                     else :     
     860                    else : 
    861861                        self.printInfo(msg + "couldn't be created.", "error") 
    862                 else :     
     862                else : 
    863863                    self.logdebug(msg + "job will be denied.") 
    864864                    self.Action = newaction 
    865                     if script is not None :  
     865                    if script is not None : 
    866866                        self.logdebug(msg + "launching subprocess [%s] to notify user." % script) 
    867867                        os.system(script) 
    868868        self.logdebug("Retrieval of billing code information done.") 
    869          
    870     def checkIfDupe(self) :     
     869 
     870    def checkIfDupe(self) : 
    871871        """Checks if the job is a duplicate, and handles the situation.""" 
    872872        self.logdebug("Checking if the job is a duplicate...") 
     
    889889                    self.logdebug("Duplicate job allowed because previous one is more than %.2f seconds old." % duplicatesdelay) 
    890890                else : 
    891                     # TODO : use the current user's last job instead of   
     891                    # TODO : use the current user's last job instead of 
    892892                    # TODO : the current printer's last job. This would be 
    893893                    # TODO : better but requires an additional database query 
    894                     # TODO : with SQL, and is much more complex with the  
     894                    # TODO : with SQL, and is much more complex with the 
    895895                    # TODO : actual LDAP schema. Maybe this is not very 
    896896                    # TODO : important, because usually duplicate jobs are sucessive. 
     
    900900                        self.Action = "DENY" 
    901901                        self.Reason = _("Duplicate print jobs are not allowed on printer %s.") % self.PrinterName 
    902                     else :     
     902                    else : 
    903903                        self.logdebug("Launching subprocess [%s] to see if duplicate jobs should be allowed or not." % denyduplicates) 
    904904                        fanswer = os.popen(denyduplicates, "r") 
    905905                        self.Action = fanswer.read().strip().upper() 
    906906                        fanswer.close() 
    907                         if self.Action == "DENY" :      
     907                        if self.Action == "DENY" : 
    908908                            self.printInfo("%s : %s." % (msg, _("Subprocess denied printing of a dupe")), "warn") 
    909909                            self.Reason = _("Duplicate print jobs are not allowed on printer %s at this time.") % self.PrinterName 
    910                         else :     
     910                        else : 
    911911                            self.printInfo("%s : %s." % (msg, _("Subprocess allowed printing of a dupe")), "warn") 
    912             else :             
     912            else : 
    913913                self.logdebug("Job doesn't seem to be a duplicate.") 
    914914        self.logdebug("Checking if the job is a duplicate done.") 
    915          
     915 
    916916    def tellUser(self) : 
    917917        """Sends a message to an user.""" 
    918         self.logdebug("Sending some feedback to user %s..." % self.UserName)   
     918        self.logdebug("Sending some feedback to user %s..." % self.UserName) 
    919919        if not self.Reason : 
    920920            self.logdebug("No feedback to send to user %s." % self.UserName) 
    921         else :     
     921        else : 
    922922            (mailto, arguments) = self.config.getMailTo(self.PrinterName) 
    923923            if mailto == "EXTERNAL" : 
    924924                # TODO : clean this again 
    925925                self.externalMailTo(arguments, self.Action, self.User, self.Printer, self.Reason) 
    926             else :     
     926            else : 
    927927                # TODO : clean this again 
    928928                admin = self.config.getAdmin(self.PrinterName) 
     
    934934                if mailto in ("BOTH", "ADMIN") : 
    935935                    destination.append(adminmail) 
    936                 if mailto in ("BOTH", "USER") :     
     936                if mailto in ("BOTH", "USER") : 
    937937                    destination.append(usermail) 
    938                      
     938 
    939939                fullmessage = self.Reason + (_("\n\nYour system administrator :\n\n\t%s - <%s>\n") % (admin, adminmail)) 
    940                 try :     
     940                try : 
    941941                    server = smtplib.SMTP(self.smtpserver) 
    942                 except socket.error, msg :     
     942                except socket.error, msg : 
    943943                    self.printInfo(_("Impossible to connect to SMTP server : %s") % msg, "error") 
    944944                else : 
     
    951951                            if mailto == "BOTH" : 
    952952                                msg["Cc"] = adminmail 
    953                         else :     
     953                        else : 
    954954                            msg["To"] = adminmail 
    955955                        msg["Date"] = email.Utils.formatdate(localtime=True) 
    956956                        server.sendmail(adminmail, destination, msg.as_string()) 
    957                     except smtplib.SMTPException, answer :     
     957                    except smtplib.SMTPException, answer : 
    958958                        try : 
    959959                            for (k, v) in answer.recipients.items() : 
     
    963963                    server.quit() 
    964964            self.logdebug("Feedback sent to user %s." % self.UserName) 
    965                  
    966     def mainWork(self) :     
     965 
     966    def mainWork(self) : 
    967967        """Main work is done here.""" 
    968968        if not self.JobSizeBytes : 
     
    974974            self.tellUser() 
    975975            return self.removeJob() 
    976              
     976 
    977977        self.getPrinterUserAndUserPQuota() 
    978978        if self.Policy == "EXTERNALERROR" : 
     
    989989            self.tellUser() 
    990990            return self.removeJob() 
    991         elif self.Policy == "DENY" :     
     991        elif self.Policy == "DENY" : 
    992992            # Either printer, user or user print quota doesn't exist, 
    993993            # and the job should be rejected. 
     
    10071007            #            be allowed if current user is allowed to print on this printer 
    10081008            return self.doWork() 
    1009         else :     
     1009        else : 
    10101010            self.Reason = _("Invalid policy %s for printer %s") % (self.Policy, self.PrinterName) 
    10111011            self.printInfo(self.Reason, "error") 
    10121012            self.tellUser() 
    10131013            return self.removeJob() 
    1014      
    1015     def doWork(self) :     
     1014 
     1015    def doWork(self) : 
    10161016        """The accounting work is done here.""" 
    10171017        self.precomputeJobPrice() 
     
    10191019        self.exportPrinterInfo() 
    10201020        self.exportPhaseInfo("BEFORE") 
    1021          
    1022         if self.Action not in ("DENY", "CANCEL") :  
     1021 
     1022        if self.Action not in ("DENY", "CANCEL") : 
    10231023            if self.Printer.MaxJobSize and (self.softwareJobSize > self.Printer.MaxJobSize) : 
    10241024                # This printer was set to refuse jobs this large. 
     
    10281028                # because in case of error the user could complain :-) 
    10291029                self.Reason = _("You are not allowed to print so many pages on printer %s at this time.") % self.PrinterName 
    1030              
     1030 
    10311031        if self.Action not in ("DENY", "CANCEL") : 
    10321032            if self.User.LimitBy == "noprint" : 
     
    10341034                self.Action = "DENY" 
    10351035                self.Reason = _("Your account settings forbid you to print at this time.") 
    1036                  
     1036 
    10371037        if self.Action not in ("DENY", "CANCEL") : 
    10381038            # If printing is still allowed at this time, we 
     
    10411041            # save some database queries. 
    10421042            self.getBillingCode() 
    1043              
     1043 
    10441044        if self.Action not in ("DENY", "CANCEL") : 
    10451045            # If printing is still allowed at this time, we 
     
    10481048            # save some database queries. 
    10491049            self.checkIfDupe() 
    1050                      
     1050 
    10511051        if self.Action not in ("DENY", "CANCEL") : 
    10521052            # If printing is still allowed at this time, we 
     
    10561056            if self.User.LimitBy in ('noquota', 'nochange') : 
    10571057                self.logdebug("User %s is allowed to print with no limit, no need to check quota." % self.UserName) 
    1058             elif self.Printer.PassThrough :     
     1058            elif self.Printer.PassThrough : 
    10591059                self.logdebug("Printer %s is in PassThrough mode, no need to check quota." % self.PrinterName) 
    10601060            else : 
     
    10671067                    self.printInfo(_("Print Quota exceeded for user %s on printer %s") % (self.UserName, self.PrinterName)) 
    10681068                    self.Reason = self.config.getHardWarn(self.PrinterName) 
    1069                 elif self.Action == "WARN" :     
     1069                elif self.Action == "WARN" : 
    10701070                    self.printInfo(_("Print Quota low for user %s on printer %s") % (self.UserName, self.PrinterName)) 
    1071                     if self.User.LimitBy and (self.User.LimitBy.lower() == "balance") :  
     1071                    if self.User.LimitBy and (self.User.LimitBy.lower() == "balance") : 
    10721072                        self.Reason = self.config.getPoorWarn() 
    1073                     else :      
     1073                    else : 
    10741074                        self.Reason = self.config.getSoftWarn(self.PrinterName) 
    1075              
    1076         # If job still allowed to print, should we ask for confirmation ?     
    1077         if self.Action not in ("DENY", "CANCEL") :  
     1075 
     1076        # If job still allowed to print, should we ask for confirmation ? 
     1077        if self.Action not in ("DENY", "CANCEL") : 
    10781078            if not self.didUserConfirm() : 
    10791079                self.Action = "CANCEL" 
    10801080                self.Reason = _("Print job cancelled.") 
    10811081                setenv("PYKOTASTATUS", "CANCELLED", self.charset) 
    1082                  
     1082 
    10831083        # exports some new environment variables 
    10841084        self.exportReason() 
    1085          
     1085 
    10861086        # now tell the user if he needs to know something 
    10871087        self.tellUser() 
    1088          
     1088 
    10891089        # launches the pre hook 
    10901090        self.launchPreHook() 
    1091          
     1091 
    10921092        # handle starting banner pages without accounting 
    10931093        self.BannerSize = 0 
     
    10951095        if (self.Action != "CANCEL") and accountbanner in ["ENDING", "NONE"] : 
    10961096            self.handleBanner("starting", 0) 
    1097          
     1097 
    10981098        if self.Action == "DENY" : 
    10991099            self.printInfo(_("Job denied, no accounting will be done.")) 
    1100         elif self.Action == "CANCEL" :     
     1100        elif self.Action == "CANCEL" : 
    11011101            self.printInfo(_("Job cancelled, no accounting will be done.")) 
    11021102        else : 
    11031103            self.printInfo(_("Job accounting begins.")) 
    11041104            self.accounter.beginJob(self.Printer) 
    1105          
     1105 
    11061106        # handle starting banner pages with accounting 
    11071107        if (self.Action != "CANCEL") and accountbanner in ["STARTING", "BOTH"] : 
    11081108            self.handleBanner("starting", 1) 
    1109          
    1110         # pass the job's data to the real backend if needed    
     1109 
     1110        # pass the job's data to the real backend if needed 
    11111111        if self.Action in ("ALLOW", "WARN") : 
    11121112            retcode = self.printJobDatas() 
    1113         else :         
     1113        else : 
    11141114            retcode = self.removeJob() 
    1115          
     1115 
    11161116        # indicate phase change 
    11171117        self.exportPhaseInfo("AFTER") 
    1118          
     1118 
    11191119        # handle ending banner pages with accounting 
    11201120        if (self.Action != "CANCEL") and accountbanner in ["ENDING", "BOTH"] : 
    11211121            self.handleBanner("ending", 1) 
    1122          
     1122 
    11231123        # stops accounting 
    11241124        if self.Action == "DENY" : 
    11251125            self.printInfo(_("Job denied, no accounting has been done.")) 
    1126         elif self.Action == "CANCEL" :     
     1126        elif self.Action == "CANCEL" : 
    11271127            self.printInfo(_("Job cancelled, no accounting has been done.")) 
    11281128        else : 
    11291129            self.accounter.endJob(self.Printer) 
    11301130            self.printInfo(_("Job accounting ends.")) 
    1131          
    1132         # Do all these database changes within a single transaction     
     1131 
     1132        # Do all these database changes within a single transaction 
    11331133        # NB : we don't enclose ALL the changes within a single transaction 
    11341134        # because while waiting for the printer to answer its internal page 
     
    11471147                    self.JobSize = 0 
    11481148                    self.printInfo(_("Job size forced to 0 because the real CUPS backend failed. No accounting will be done."), "warn") 
    1149                 else :     
     1149                else : 
    11501150                    self.printInfo(_("The real CUPS backend failed, but the job will be accounted for anyway."), "warn") 
    1151                      
    1152             # retrieve the job size     
     1151 
     1152            # retrieve the job size 
    11531153            if self.Action == "DENY" : 
    11541154                self.JobSize = 0 
    11551155                self.printInfo(_("Job size forced to 0 because printing is denied.")) 
    1156             elif self.Action == "CANCEL" :      
     1156            elif self.Action == "CANCEL" : 
    11571157                self.JobSize = 0 
    11581158                self.printInfo(_("Job size forced to 0 because printing was cancelled.")) 
    1159             else :     
     1159            else : 
    11601160                self.UserPQuota.resetDenyBannerCounter() 
    1161                 if (self.Action != "PROBLEM") or ("CHARGE" in onbackenderror) :  
     1161                if (self.Action != "PROBLEM") or ("CHARGE" in onbackenderror) : 
    11621162                    self.JobSize = self.accounter.getJobSize(self.Printer) 
    11631163                    self.sanitizeJobSize() 
    11641164                    self.JobSize += self.BannerSize 
    11651165            self.printInfo(_("Job size : %i") % self.JobSize) 
    1166              
     1166 
    11671167            if ((self.Action == "PROBLEM") and ("NOCHARGE" in onbackenderror)) or \ 
    11681168                (self.Action in ("DENY", "CANCEL")) : 
     
    11731173                self.JobPrice = 0.0 
    11741174            else : 
    1175                 # update the quota for the current user on this printer  
     1175                # update the quota for the current user on this printer 
    11761176                self.printInfo(_("Updating user %s's quota on printer %s") % (self.UserName, self.PrinterName)) 
    11771177                self.JobPrice = self.UserPQuota.increasePagesUsage(self.JobSize, self.accounter.inkUsage) 
    1178              
    1179             # adds the current job to history     
     1178 
     1179            # adds the current job to history 
    11801180            self.Printer.addJobToHistory(self.Ticket.JobId, self.User, self.accounter.getLastPageCounter(), \ 
    11811181                                    self.Action, self.JobSize, self.JobPrice, self.Ticket.FileName, \ 
     
    11841184                                    self.softwareJobSize, self.softwareJobPrice) 
    11851185            self.printInfo(_("Job added to history.")) 
    1186              
     1186 
    11871187            if hasattr(self, "BillingCode") and self.BillingCode and self.BillingCode.Exists : 
    11881188                if (self.Action in ("ALLOW", "WARN")) or \ 
     
    11901190                    self.BillingCode.consume(self.JobSize, self.JobPrice) 
    11911191                    self.printInfo(_("Billing code %s was updated.") % self.BillingCode.BillingCode) 
    1192         except :     
     1192        except : 
    11931193            self.storage.rollbackTransaction() 
    11941194            raise 
    1195         else :     
     1195        else : 
    11961196            self.storage.commitTransaction() 
    1197              
     1197 
    11981198        # exports some new environment variables 
    11991199        self.exportJobSizeAndPrice() 
    1200          
     1200 
    12011201        # then re-export user information with new values 
    12021202        self.exportUserInfo() 
    1203          
     1203 
    12041204        # handle ending banner pages without accounting 
    12051205        if (self.Action != "CANCEL") and accountbanner in ["STARTING", "NONE"] : 
    12061206            self.handleBanner("ending", 0) 
    1207                      
     1207 
    12081208        self.launchPostHook() 
    1209              
    1210         return retcode     
    1211                 
    1212     def printJobDatas(self) :            
     1209 
     1210        return retcode 
     1211 
     1212    def printJobDatas(self) : 
    12131213        """Sends the job's datas to the real backend.""" 
    12141214        self.logdebug("Sending job's datas to real backend...") 
    1215          
     1215 
    12161216        delay = 0 
    12171217        number = 1 
     
    12221222                    if (number < 0) or (delay < 0) : 
    12231223                        raise ValueError 
    1224                 except ValueError :     
     1224                except ValueError : 
    12251225                    self.printInfo(_("Incorrect value for the 'onbackenderror' directive in section [%s]") % self.PrinterName, "error") 
    12261226                    delay = 0 
    12271227                    number = 1 
    1228                 else :     
     1228                else : 
    12291229                    break 
    1230         loopcnt = 1  
    1231         while True :             
     1230        loopcnt = 1 
     1231        while True : 
    12321232            if self.Ticket.FileName is None : 
    12331233                infile = open(self.DataFile, "rb") 
    1234             else :     
     1234            else : 
    12351235                infile = None 
    12361236            retcode = self.runOriginalBackend(infile) 
     
    12441244                    time.sleep(delay) 
    12451245                    loopcnt += 1 
    1246                 else :     
     1246                else : 
    12471247                    break 
    1248              
     1248 
    12491249        self.logdebug("Job's datas sent to real backend.") 
    12501250        return retcode 
    1251          
     1251 
    12521252    def runOriginalBackend(self, filehandle=None, isBanner=0) : 
    12531253        """Launches the original backend.""" 
     
    12551255        if not isBanner : 
    12561256            arguments = [os.environ["DEVICE_URI"]] + [a.encode("UTF-8") for a in sys.argv[1:]] 
    1257         else :     
     1257        else : 
    12581258            # For banners, we absolutely WANT 
    12591259            # to remove any filename from the command line ! 
     
    12641264        # TODO : do something about the job title : if we are printing a banner and the backend 
    12651265        # TODO : uses the job's title to name an output file (cups-pdf:// for example), we're stuck ! 
    1266          
     1266 
    12671267        self.logdebug("Starting original backend %s with args %s" % (originalbackend, " ".join(['"%s"' % a.decode("UTF-8") for a in arguments]))) 
    12681268        pid = os.fork() 
     
    12771277            except OSError, msg : 
    12781278                self.logdebug("execve() failed: %s" % msg) 
    1279             self.logdebug("We shouldn't be there !!!")     
     1279            self.logdebug("We shouldn't be there !!!") 
    12801280            os._exit(-1) 
    1281          
    1282         self.logdebug("Waiting for original backend to exit...")     
     1281 
     1282        self.logdebug("Waiting for original backend to exit...") 
    12831283        killed = False 
    12841284        status = -1 
     
    12891289                if err == 4 : 
    12901290                    killed = True 
    1291                      
     1291 
    12921292        if os.WIFEXITED(status) : 
    12931293            status = os.WEXITSTATUS(status) 
     
    12971297                level = "error" 
    12981298                self.Reason = message 
    1299             else :     
     1299            else : 
    13001300                level = "info" 
    13011301            self.printInfo(message, level) 
     
    13091309            self.printInfo(self.Reason, "warn") 
    13101310            return 1 
    1311          
    1312 if __name__ == "__main__" :     
     1311 
     1312if __name__ == "__main__" : 
    13131313    # This is a CUPS backend, we should act and die like a CUPS backend 
    13141314    wrapper = CUPSBackend() 
    13151315    if len(sys.argv) == 1 : 
    13161316        print "\n".join(wrapper.discoverOtherBackends()) 
    1317         sys.exit(0)                 
    1318     elif len(sys.argv) not in (6, 7) :     
     1317        sys.exit(0) 
     1318    elif len(sys.argv) not in (6, 7) : 
    13191319        logerr("ERROR: %s job-id user title copies options [file]\n"\ 
    13201320                              % sys.argv[0]) 
    13211321        sys.exit(1) 
    1322     else :     
     1322    else : 
    13231323        os.environ["PATH"] = "%s:/bin:/usr/bin:/usr/local/bin:/opt/bin:/sbin:/usr/sbin" % os.environ.get("PATH", "") 
    13241324        try : 
     
    13331333                wrapper.accounter = openAccounter(wrapper) 
    13341334                wrapper.precomputeJobSize() 
    1335                 wrapper.exportJobInfo() # exports a first time to give hints to external scripts  
     1335                wrapper.exportJobInfo() # exports a first time to give hints to external scripts 
    13361336                wrapper.overwriteJobAttributes() 
    13371337                wrapper.exportJobInfo() # re-exports in case it was overwritten 
    13381338                retcode = wrapper.mainWork() 
    1339             except KeyboardInterrupt :     
     1339            except KeyboardInterrupt : 
    13401340                wrapper.printInfo(_("Job %s interrupted by the administrator !") % wrapper.Ticket.JobId, "warn") 
    13411341                retcode = 0 
    1342             except SystemExit, err :     
     1342            except SystemExit, err : 
    13431343                retcode = err.code 
    1344             except :     
     1344            except : 
    13451345                try : 
    13461346                    wrapper.crashed("cupspykota backend failed") 
    1347                 except :     
     1347                except : 
    13481348                    crashed("cupspykota backend failed") 
    13491349                retcode = 1 
    1350         finally :         
     1350        finally : 
    13511351            wrapper.clean() 
    13521352        sys.exit(retcode)