- Timestamp:
- 03/12/05 23:57:44 (20 years ago)
- Location:
- tea4cups/trunk
- Files:
-
- 2 modified
Legend:
- Unmodified
- Added
- Removed
-
tea4cups/trunk/tea4cups
r576 r577 26 26 import os 27 27 import errno 28 import md5 28 29 import cStringIO 29 30 import shlex … … 54 55 def __init__(self) : 55 56 """Initializes the CUPS backend wrapper.""" 57 self.MyName = "Tea4CUPS" 58 self.myname = "tea4cups" 59 self.pid = os.getpid() 56 60 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) 58 62 if os.path.isfile(self.conffile) : 59 63 self.config = ConfigParser.ConfigParser() … … 67 71 """Logs something to debug output if debug is enabled.""" 68 72 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)) 70 74 sys.stderr.flush() 71 75 72 76 def logInfo(self, message, level="info") : 73 77 """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)) 75 79 sys.stderr.flush() 76 80 … … 87 91 return self.config.get("global", option, raw=1) 88 92 except (ConfigParser.NoSectionError, ConfigParser.NoOptionError) : 89 if ignore : 90 return 91 else : 93 if not ignore : 92 94 raise ConfigError, "Option %s not found in section global of %s" % (option, self.conffile) 93 95 94 def get SectionOption(self, printqueuename, option) :96 def getPrintQueueOption(self, printqueuename, option, ignore=0) : 95 97 """Returns an option from the printer section, or the global section, or raises a ConfigError.""" 96 98 globaloption = self.getGlobalOption(option, ignore=1) … … 100 102 if globaloption is not None : 101 103 return globaloption 102 el se :104 elif not ignore : 103 105 raise ConfigError, "Option %s not found in section [%s] of %s" % (option, printqueuename, self.conffile) 104 106 … … 155 157 if not os.path.exists(lockfilename) : 156 158 lockfile = open(lockfilename, "w") 157 lockfile.write("%i" % os.getpid())159 lockfile.write("%i" % self.pid) 158 160 lockfile.close() 159 161 allbackends = [ os.path.join(directory, b) \ … … 194 196 if fullname.startswith('"') and fullname.endswith('"') : 195 197 fullname = fullname[1:-1] 196 available.append('%s tea4cups:%s "Tea4CUPS+%s" "Tea4CUPSmanaged %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)) 198 200 os.remove(lockfilename) 199 201 return available 200 202 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)) 242 283 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 243 289 if __name__ == "__main__" : 244 290 # This is a CUPS backend, we should act and die like a CUPS backend … … 252 298 sys.exit(1) 253 299 else : 300 wrapper.initBackend() 301 wrapper.saveDatasAndCheckSum() 302 wrapper.exportAttributes() 303 wrapper.cleanUp() 254 304 sys.stderr.write("ERROR: Not Yet !\n") 255 305 sys.exit(1) -
tea4cups/trunk/tea4cups.conf
r576 r577 18 18 # 19 19 # 20 21 # First we set all top-level directives in the [global] section 20 22 [global] 23 24 # Should we log debugging information to CUPS' error_log file ? 25 # defaults to No if unset. 21 26 debug : 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. 30 directory : /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 ! 35 keepfiles : 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 22 58 #tee_0 : blah 23 59 #tee_1 : blah … … 28 64 # 29 65 [HP2100] 30 #blah:31 66 #tee_2 : zut # overwrites the [global] value of tee_2 32 67 #tee_4 : gniak