Changeset 577

Show
Ignore:
Timestamp:
03/12/05 23:57:44 (19 years ago)
Author:
jerome
Message:

Completed the backend initialization code.
Added the list of additionnal environment variables to the sample
configuration file.

Location:
tea4cups/trunk
Files:
2 modified

Legend:

Unmodified
Added
Removed
  • tea4cups/trunk/tea4cups

    r576 r577  
    2626import os 
    2727import errno 
     28import md5 
    2829import cStringIO 
    2930import shlex 
     
    5455    def __init__(self) : 
    5556        """Initializes the CUPS backend wrapper.""" 
     57        self.MyName = "Tea4CUPS" 
     58        self.myname = "tea4cups" 
     59        self.pid = os.getpid() 
    5660        confdir = os.environ.get("CUPS_SERVERROOT", ".")  
    57         self.conffile = os.path.join(confdir, "tea4cups.conf") 
     61        self.conffile = os.path.join(confdir, "%s.conf" % self.myname) 
    5862        if os.path.isfile(self.conffile) : 
    5963            self.config = ConfigParser.ConfigParser() 
     
    6771        """Logs something to debug output if debug is enabled.""" 
    6872        if self.debug : 
    69             sys.stderr.write("DEBUG: %s\n" % message) 
     73            sys.stderr.write("DEBUG: %s (PID %i) : %s\n" % (self.MyName, self.pid, message)) 
    7074            sys.stderr.flush() 
    7175             
    7276    def logInfo(self, message, level="info") :         
    7377        """Logs a message to CUPS' error_log file.""" 
    74         sys.stderr.write("%s: %s\n" % (level.upper(), message)) 
     78        sys.stderr.write("%s: %s (PID %i) : %s\n" % (level.upper(), self.MyName, self.pid, message)) 
    7579        sys.stderr.flush() 
    7680         
     
    8791            return self.config.get("global", option, raw=1) 
    8892        except (ConfigParser.NoSectionError, ConfigParser.NoOptionError) :     
    89             if ignore : 
    90                 return 
    91             else : 
     93            if not ignore : 
    9294                raise ConfigError, "Option %s not found in section global of %s" % (option, self.conffile) 
    9395                 
    94     def getSectionOption(self, printqueuename, option) :     
     96    def getPrintQueueOption(self, printqueuename, option, ignore=0) :     
    9597        """Returns an option from the printer section, or the global section, or raises a ConfigError.""" 
    9698        globaloption = self.getGlobalOption(option, ignore=1) 
     
    100102            if globaloption is not None : 
    101103                return globaloption 
    102             else : 
     104            elif not ignore : 
    103105                raise ConfigError, "Option %s not found in section [%s] of %s" % (option, printqueuename, self.conffile) 
    104106                 
     
    155157        if not os.path.exists(lockfilename) : 
    156158            lockfile = open(lockfilename, "w") 
    157             lockfile.write("%i" % os.getpid()) 
     159            lockfile.write("%i" % self.pid) 
    158160            lockfile.close() 
    159161            allbackends = [ os.path.join(directory, b) \ 
     
    194196                            if fullname.startswith('"') and fullname.endswith('"') : 
    195197                                fullname = fullname[1:-1] 
    196                             available.append('%s tea4cups:%s "Tea4CUPS+%s" "Tea4CUPS managed %s"' \ 
    197                                                  % (devicetype, device, name, fullname)) 
     198                            available.append('%s %s:%s "%s+%s" "%s managed %s"' \ 
     199                                                 % (devicetype, self.myname, device, self.MyName, name, self.MyName, fullname)) 
    198200            os.remove(lockfilename) 
    199201        return available 
    200202                         
    201     def fakePrint(self) :     
    202         """Fakes to print the job.""" 
    203         if os.environ.has_key("CUPS_SERVERROOT") and os.path.isdir(os.environ.get("CUPS_SERVERROOT", "")) : 
    204             # Either the job's datas are on our stdin, or in a file 
    205             if len(sys.argv) == 7 : 
    206                 self.InputFile = sys.argv[6] 
    207             else :     
    208                 self.InputFile = None 
    209                  
    210             # check that the DEVICE_URI environment variable's value is  
    211             # prefixed with "tea4cups:" otherwise don't touch it. 
    212             # If this is the case, we have to remove the prefix from  
    213             # the environment before launching the real backend in cupspykota 
    214             device_uri = os.environ.get("DEVICE_URI", "") 
    215             if device_uri.startswith("cupspykota:") : 
    216                 fulldevice_uri = device_uri[:] 
    217                 device_uri = fulldevice_uri[len("cupspykota:"):] 
    218                 if device_uri.startswith("//") :    # lpd (at least) 
    219                     device_uri = device_uri[2:] 
    220                 os.environ["DEVICE_URI"] = device_uri   # TODO : side effect ! 
    221             # TODO : check this for more complex urls than ipp://myprinter.dot.com:631/printers/lp 
    222             try : 
    223                 (backend, destination) = device_uri.split(":", 1)  
    224             except ValueError :     
    225                 raise PyKotaToolError, "Invalid DEVICE_URI : %s\n" % device_uri 
    226             while destination.startswith("/") : 
    227                 destination = destination[1:] 
    228             checkauth = destination.split("@", 1)     
    229             if len(checkauth) == 2 : 
    230                 destination = checkauth[1] 
    231             printerhostname = destination.split("/")[0].split(":")[0] 
    232             return ("CUPS", \ 
    233                     printerhostname, \ 
    234                     os.environ.get("PRINTER"), \ 
    235                     sys.argv[2].strip(), \ 
    236                     sys.argv[1].strip(), \ 
    237                     inputfile, \ 
    238                     int(sys.argv[4].strip()), \ 
    239                     sys.argv[3], \ 
    240                     sys.argv[5], \ 
    241                     backend) 
     203    def initBackend(self) :     
     204        """Initializes the backend's attributes.""" 
     205        # check that the DEVICE_URI environment variable's value is  
     206        # prefixed with self.myname otherwise don't touch it. 
     207        # If this is the case, we have to remove the prefix from  
     208        # the environment before launching the real backend  
     209        muststartwith = "%s:" % self.myname 
     210        device_uri = os.environ.get("DEVICE_URI", "") 
     211        if device_uri.startswith(muststartwith) : 
     212            fulldevice_uri = device_uri[:] 
     213            device_uri = fulldevice_uri[len(muststartwith):] 
     214            if device_uri.startswith("//") :   
     215                device_uri = device_uri[2:] 
     216        try : 
     217            (backend, destination) = device_uri.split(":", 1)  
     218        except ValueError :     
     219            raise TeeError, "Invalid DEVICE_URI : %s\n" % device_uri 
     220         
     221        self.JobId = sys.argv[1].strip() 
     222        self.UserName = sys.argv[2].strip() 
     223        self.Title = sys.argv[3].strip() 
     224        self.Copies = int(sys.argv[4].strip()) 
     225        self.Options = sys.argv[5].strip() 
     226        if len(sys.argv) == 7 : 
     227            self.InputFile = sys.argv[6] # read job's datas from file 
     228        else :     
     229            self.InputFile = None        # read job's datas from stdin 
     230             
     231        self.RealBackend = backend 
     232        self.DeviceURI = device_uri 
     233        self.PrinterName = os.environ.get("PRINTER", "") 
     234        self.Directory = self.getPrintQueueOption(self.PrinterName, "directory") 
     235        self.DataFile = os.path.join(self.Directory, "%s-%s-%s" % (self.myname, self.PrinterName, self.JobId)) 
     236             
     237    def exportAttributes(self) :     
     238        """Exports our backend's attributes to the environment.""" 
     239        os.environ["DEVICE_URI"] = self.DeviceURI       # WARNING ! 
     240        os.environ["TEAPRINTERNAME"] = self.PrinterName 
     241        os.environ["TEADIRECTORY"] = self.Directory 
     242        os.environ["TEADATAFILE"] = self.DataFile 
     243        os.environ["TEAJOBSIZE"] = self.JobSize 
     244        os.environ["TEAMD5SUM"] = self.JobMD5Sum 
     245        os.environ["TEAJOBID"] = self.JobId 
     246        os.environ["TEAUSERNAME"] = self.UserName 
     247        os.environ["TEATITLE"] = self.Title 
     248        os.environ["TEACOPIES"] = str(self.Copies) 
     249        os.environ["TEAOPTIONS"] = self.Options 
     250        os.environ["TEAINPUTFILE"] = self.InputFile or "" 
     251         
     252    def saveDatasAndCheckSum(self) : 
     253        """Saves the input datas into a static file.""" 
     254        self.logDebug("Duplicating data stream to %s" % self.DataFile) 
     255        mustclose = 0 
     256        if self.InputFile is not None : 
     257            infile = open(self.InputFile, "rb") 
     258            mustclose = 1 
     259        else :     
     260            infile = sys.stdin 
     261        CHUNK = 64*1024         # read 64 Kb at a time 
     262        dummy = 0 
     263        sizeread = 0 
     264        checksum = md5.new() 
     265        outfile = open(self.DataFile, "wb")     
     266        while 1 : 
     267            data = infile.read(CHUNK)  
     268            if not data : 
     269                break 
     270            sizeread += len(data)     
     271            outfile.write(data) 
     272            checksum.update(data)     
     273            if not (dummy % 32) : # Only display every 2 Mb 
     274                self.logDebug("%s bytes saved..." % sizeread) 
     275            dummy += 1     
     276        outfile.close() 
     277        if mustclose :     
     278            self.infile.close() 
     279        self.JobSize = sizeread     
     280        self.JobMD5Sum = checksum.hexdigest() 
     281        self.logDebug("Job %s is %s bytes long." % (self.JobId, self.JobSize)) 
     282        self.logDebug("Job %s MD5 sum is %s" % (self.JobId, self.JobMD5Sum)) 
    242283 
     284    def cleanUp(self) : 
     285        """Cleans up the place.""" 
     286        if not self.isTrue(self.getPrintQueueOption(self.PrinterName, "keepfiles", ignore=1)) : 
     287            os.remove(self.DataFile) 
     288         
    243289if __name__ == "__main__" :     
    244290    # This is a CUPS backend, we should act and die like a CUPS backend 
     
    252298        sys.exit(1) 
    253299    else :     
     300        wrapper.initBackend() 
     301        wrapper.saveDatasAndCheckSum() 
     302        wrapper.exportAttributes() 
     303        wrapper.cleanUp() 
    254304        sys.stderr.write("ERROR: Not Yet !\n") 
    255305        sys.exit(1) 
  • tea4cups/trunk/tea4cups.conf

    r576 r577  
    1818#  
    1919# 
     20 
     21# First we set all top-level directives in the [global] section 
    2022[global] 
     23 
     24# Should we log debugging information to CUPS' error_log file ? 
     25# defaults to No if unset. 
    2126debug : yes 
     27 
     28# The directory in which we will create our files : it must already exist ! 
     29# This directive MUST be present since there's no sane default value. 
     30directory : /var/spool/cups/ 
     31 
     32# Should Tea4CUPS keep the files it creates once all tees have ended ? 
     33# Defaults to No if unset. 
     34# BEWARE : this may use huge amounts of disk space ! 
     35keepfiles : yes 
     36 
     37# 
     38# When executing the contents of a tee directive, tea4cups makes 
     39# the following environment variables available to your own commands : 
     40# 
     41# TEAPRINTERNAME : The print queue name 
     42# TEADIRECTORY : Tea4CUPS output directory 
     43# TEADATAFILE : Full name of Tea4CUPS work file (in $TEADIRECTORY) 
     44# TEAJOBSIZE : Job's size in bytes 
     45# TEAMD5SUM : MD5 sum of the job's datas 
     46# TEAJOBID : Job's Id 
     47# TEAUSERNAME : Name of the user who launched the print job 
     48# TEATITLE : Job's title 
     49# TEACOPIES : Number of copies requested 
     50# TEAOPTIONS : Options of the print job 
     51# TEAINPUTFILE : Print job's data file or empty when job read from stdin 
     52# 
     53# Your own commands will mostly be interested in TEADATAFILE which is 
     54# the name of the file from which your commands may extract the final 
     55# job's datas. 
     56         
     57# Now defines some default tees which will always be launched 
    2258#tee_0 : blah 
    2359#tee_1 : blah 
     
    2864# 
    2965[HP2100] 
    30 #blah:  
    3166#tee_2 : zut    # overwrites the [global] value of tee_2 
    3267#tee_4 : gniak