Show
Ignore:
Timestamp:
03/11/05 01:09:17 (19 years ago)
Author:
jerome
Message:

Autodetection with no reentrance now works

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • tea4cups/trunk/cupsoftee

    r567 r568  
    2525import sys 
    2626import os 
    27 import popen2 
     27import errno 
    2828import cStringIO 
    2929import shlex 
    30 import select 
    31 import signal 
    32 import time 
     30import tempfile 
     31 
     32class CupsBackend : 
     33    """Base class for tools with no database access.""" 
     34    def __init__(self) : 
     35        """Initializes the CUPS backend wrapper.""" 
     36        self.debug = 1 
     37         
     38    def fakePrint(self) :     
     39        """Fakes to print the job.""" 
     40        if os.environ.has_key("CUPS_SERVERROOT") and os.path.isdir(os.environ.get("CUPS_SERVERROOT", "")) : 
     41            # Either the job's datas are on our stdin, or in a file 
     42            if len(sys.argv) == 7 : 
     43                self.InputFile = sys.argv[6] 
     44            else :     
     45                self.InputFile = None 
     46                 
     47            # check that the DEVICE_URI environment variable's value is  
     48            # prefixed with "cupsoftee:" otherwise don't touch it. 
     49            # If this is the case, we have to remove the prefix from  
     50            # the environment before launching the real backend in cupspykota 
     51            device_uri = os.environ.get("DEVICE_URI", "") 
     52            if device_uri.startswith("cupspykota:") : 
     53                fulldevice_uri = device_uri[:] 
     54                device_uri = fulldevice_uri[len("cupspykota:"):] 
     55                if device_uri.startswith("//") :    # lpd (at least) 
     56                    device_uri = device_uri[2:] 
     57                os.environ["DEVICE_URI"] = device_uri   # TODO : side effect ! 
     58            # TODO : check this for more complex urls than ipp://myprinter.dot.com:631/printers/lp 
     59            try : 
     60                (backend, destination) = device_uri.split(":", 1)  
     61            except ValueError :     
     62                raise PyKotaToolError, "Invalid DEVICE_URI : %s\n" % device_uri 
     63            while destination.startswith("/") : 
     64                destination = destination[1:] 
     65            checkauth = destination.split("@", 1)     
     66            if len(checkauth) == 2 : 
     67                destination = checkauth[1] 
     68            printerhostname = destination.split("/")[0].split(":")[0] 
     69            return ("CUPS", \ 
     70                    printerhostname, \ 
     71                    os.environ.get("PRINTER"), \ 
     72                    sys.argv[2].strip(), \ 
     73                    sys.argv[1].strip(), \ 
     74                    inputfile, \ 
     75                    int(sys.argv[4].strip()), \ 
     76                    sys.argv[3], \ 
     77                    sys.argv[5], \ 
     78                    backend) 
     79         
     80    def discoverOtherBackends(self) :     
     81        """Discovers the other CUPS backends. 
     82         
     83           Executes each existing backend in turn in device enumeration mode. 
     84           Returns the list of available backends. 
     85        """ 
     86        self.logDebug("Entering device enumeration loop.") 
     87        available = [] 
     88        tmpdir = tempfile.gettempdir() 
     89        lockfilename = os.path.join(tmpdir, "cupsoftee..LCK") 
     90        if os.path.exists(lockfilename) : 
     91            self.logInfo("Lock file present.") 
     92            locked = 1 
     93            lockfile = open(lockfilename, "r") 
     94            pid = int(lockfile.read()) 
     95            lockfile.close() 
     96            try : 
     97                # see if the pid contained in the lock file is still running 
     98                os.kill(pid, 0) 
     99            except OSError, e :     
     100                if e.errno != errno.EPERM : 
     101                    # process doesn't exist anymore 
     102                    self.logInfo("Removing stalled lock.") 
     103                    os.remove(lockfilename) 
     104                    locked = 0 
     105            if locked :         
     106                self.logInfo("No device enumeration.") 
     107             
     108        if not os.path.exists(lockfilename) : 
     109            lockfile = open(lockfilename, "w") 
     110            lockfile.write("%i" % os.getpid()) 
     111            lockfile.close() 
     112            (directory, myname) = os.path.split(sys.argv[0]) 
     113            for backend in [ os.path.join(directory, b) \ 
     114                                 for b in os.listdir(directory)  
     115                                     if os.path.isfile(os.path.join(directory, b))\ 
     116                                        and (b != myname)] : 
     117                answer = os.popen(backend, "r") 
     118                try : 
     119                    devices = [line.strip() for line in answer.readlines()] 
     120                except :     
     121                    devices = [] 
     122                status = answer.close() 
     123                if status is None : 
     124                    for d in devices : 
     125                        # each line is of the form :  
     126                        # 'xxxx xxxx "xxxx xxx" "xxxx xxx"' 
     127                        # so we have to decompose it carefully 
     128                        fdevice = cStringIO.StringIO(d) 
     129                        tokenizer = shlex.shlex(fdevice) 
     130                        tokenizer.wordchars = tokenizer.wordchars + \ 
     131                                                        r".:,?!~/\_$*-+={}[]()#" 
     132                        arguments = [] 
     133                        while 1 : 
     134                            token = tokenizer.get_token() 
     135                            if token : 
     136                                arguments.append(token) 
     137                            else : 
     138                                break 
     139                        fdevice.close() 
     140                        try : 
     141                            (devicetype, device, name, fullname) = arguments 
     142                        except ValueError :     
     143                            pass    # ignore this 'bizarre' device 
     144                        else :     
     145                            if name.startswith('"') and name.endswith('"') : 
     146                                name = name[1:-1] 
     147                            if fullname.startswith('"') and fullname.endswith('"') : 
     148                                fullname = fullname[1:-1] 
     149                            available.append('%s cupsoftee:%s "CupsOfTee+%s" "CupsOfTee managed %s"' \ 
     150                                                 % (devicetype, device, name, fullname)) 
     151            os.remove(lockfilename) 
     152        self.logDebug("Exiting device enumeration loop.") 
     153        return available 
     154                         
     155    def logDebug(self, message) :     
     156        """Logs something to debug output if debug is enabled.""" 
     157        if self.debug : 
     158            sys.stderr.write("DEBUG: %s\n" % message) 
     159            sys.stderr.flush() 
     160             
     161    def logInfo(self, message, level="info") :         
     162        """Logs a message to CUPS' error_log file.""" 
     163        sys.stderr.write("%s: %s\n" % (level.upper(), message)) 
     164        sys.stderr.flush() 
     165         
    33166 
    34167if __name__ == "__main__" :     
    35168    # This is a CUPS backend, we should act and die like a CUPS backend 
    36     retcode = 0 
     169    wrapper = CupsBackend() 
    37170    if len(sys.argv) == 1 : 
    38         # we will execute each existing backend in device enumeration mode 
    39         # and generate their PyKota accounting counterpart 
    40         (directory, myname) = os.path.split(sys.argv[0]) 
    41         for backend in [os.path.join(directory, b) for b in os.listdir(directory) if os.path.isfile(os.path.join(directory, b)) and (b != myname)] : 
    42             answer = os.popen(backend, "r") 
    43             try : 
    44                 devices = [line.strip() for line in answer.readlines()] 
    45             except :     
    46                 devices = [] 
    47             status = answer.close() 
    48             if status is None : 
    49                 for d in devices : 
    50                     # each line is of the form : 'xxxx xxxx "xxxx xxx" "xxxx xxx"' 
    51                     # so we have to decompose it carefully 
    52                     fdevice = cStringIO.StringIO("%s" % d) 
    53                     tokenizer = shlex.shlex(fdevice) 
    54                     tokenizer.wordchars = tokenizer.wordchars + r".:,?!~/\_$*-+={}[]()#" 
    55                     arguments = [] 
    56                     while 1 : 
    57                         token = tokenizer.get_token() 
    58                         if token : 
    59                             arguments.append(token) 
    60                         else : 
    61                             break 
    62                     fdevice.close() 
    63                     try : 
    64                         (devicetype, device, name, fullname) = arguments 
    65                     except ValueError :     
    66                         pass    # ignore this 'bizarre' device 
    67                     else :     
    68                         if name.startswith('"') and name.endswith('"') : 
    69                             name = name[1:-1] 
    70                         if fullname.startswith('"') and fullname.endswith('"') : 
    71                             fullname = fullname[1:-1] 
    72                         print '%s cupspykota:%s "PyKota+%s" "PyKota managed %s"' % (devicetype, device, name, fullname) 
    73         retcode = 0                 
     171        print "\n".join(wrapper.discoverOtherBackends()) 
     172        sys.exit(0)                 
    74173    elif len(sys.argv) not in (6, 7) :     
    75         sys.stderr.write("ERROR: %s job-id user title copies options [file]\n" % sys.argv[0]) 
    76         retcode = 1 
     174        sys.stderr.write("ERROR: %s job-id user title copies options [file]\n"\ 
     175                              % sys.argv[0]) 
     176        sys.exit(1) 
    77177    else :     
    78178        sys.stderr.write("ERROR: Not Yet !\n") 
    79         retcode = 1 
    80     sys.exit(retcode)     
     179        sys.exit(1)