Changeset 1185 for pykota/trunk
- Timestamp:
- 11/14/03 23:05:12 (21 years ago)
- Location:
- pykota/trunk
- Files:
-
- 4 modified
Legend:
- Unmodified
- Added
- Removed
-
pykota/trunk/bin/cupspykota
r1184 r1185 24 24 # 25 25 # $Log$ 26 # Revision 1.7 2003/11/14 22:05:12 jalet 27 # New CUPS backend fully functionnal. 28 # Old CUPS configuration method is now officially deprecated. 29 # 26 30 # Revision 1.6 2003/11/14 20:13:11 jalet 27 31 # We exit the loop too soon. … … 147 151 return "%s >/dev/null" % (cmdline % locals()) 148 152 149 def sigterm_handler(signum, frame) :150 """Handler for SIGTERM."""151 sys.stderr.write("INFO: PyKota backend aborted.")152 sys.exit(1)153 154 153 def main(thebackend) : 155 154 """Do it, and do it right !""" … … 157 156 # CUPS backends ignore SIGPIPE and exit(1) on SIGTERM 158 157 # Fortunately SIGPIPE is already ignored by Python 159 # It's there just in case this changes in the future 158 # It's there just in case this changes in the future. 159 # But here we will IGNORE SIGTERM for now, and see 160 # if we shouldn't pass it to the original backend 161 # instead. 160 162 signal.signal(signal.SIGPIPE, signal.SIG_IGN) 161 signal.signal(signal.SIGTERM, sig term_handler)163 signal.signal(signal.SIGTERM, signal.SIG_IGN) 162 164 163 165 # … … 226 228 thebackend.accounter.beginJob(printer, user) 227 229 228 # executes original backend 230 # Now it becomes tricky... 231 232 # First ensure that we have a file object as input 229 233 mustclose = 0 230 234 if thebackend.inputfile is not None : … … 236 240 else : 237 241 infile = sys.stdin 242 243 # Find the real backend pathname 238 244 realbackend = os.path.join(os.path.split(sys.argv[0])[0], thebackend.originalbackend) 239 subprocess = PyKotaPopen3([realbackend] + sys.argv[1:], capturestderr=1, arg0=os.environ["DEVICE_URI"]) 240 pollster = select.poll() 245 246 # And launch it 247 subprocess = PyKotaPopen3([realbackend] + sys.argv[1:], capturestderr=1, bufsize=0, arg0=os.environ["DEVICE_URI"]) 248 249 # Save file descriptors, we will need them later. 241 250 infno = infile.fileno() 242 251 stdoutfno = sys.stdout.fileno() … … 245 254 tocfno = subprocess.tochild.fileno() 246 255 cerrfno = subprocess.childerr.fileno() 256 257 # We will have to be careful when dealing with I/O 258 # So we use a poll object to know when to read or write 259 pollster = select.poll() 247 260 pollster.register(infno, select.POLLIN | select.POLLPRI) 248 261 pollster.register(fromcfno, select.POLLIN | select.POLLPRI) … … 251 264 pollster.register(stderrfno, select.POLLOUT) 252 265 pollster.register(tocfno, select.POLLOUT) 266 267 # Initialize our buffers 253 268 indata = "" 254 269 outdata = "" 255 270 errdata = "" 256 end = 0 257 while not end : 258 availablefds = pollster.poll(500) 259 if not availablefds : 260 end = 1 261 else : 262 for (fd, mask) in availablefds : 263 thebackend.logdebug("Stream: %02i Mask: %02x" % (fd, mask)) 264 if mask & select.POLLHUP : 265 if fd == infno : 266 end = 1 # this happens with real stdin 267 if mask & select.POLLOUT : 268 if fd == tocfno : 269 if indata : 270 os.write(fd, indata) 271 indata = "" 272 elif fd == stdoutfno : 273 if outdata : 274 os.write(fd, outdata) 271 endinput = 0 272 status = -1 273 while status == -1 : 274 # First check if original backend is still alive 275 status = subprocess.poll() 276 277 # In any case, deal with any remaining I/O 278 availablefds = pollster.poll() 279 for (fd, mask) in availablefds : 280 if mask & select.POLLOUT : 281 # We can write 282 if fd == tocfno : 283 if indata : 284 os.write(fd, indata) 285 indata = "" 286 elif fd == stdoutfno : 287 if outdata : 288 os.write(fd, outdata) 289 outdata = "" 290 elif fd == stderrfno : 291 if errdata : 292 os.write(fd, errdata) 293 errdata = "" 294 if (mask & select.POLLIN) or (mask & select.POLLPRI) : 295 # We have something to read 296 data = os.read(fd, 256 * 1024) 297 if fd == infno : 298 indata += data 299 if not data : # If yes, then no more input data 300 endinput = 1 # this happens with real files. 301 elif fd == fromcfno : 302 outdata += data 303 elif fd == cerrfno : 304 errdata += data 305 if mask & select.POLLHUP : 306 # Some standard I/O stream has no more datas 307 if fd == infno : 308 # Here we are in the case where the input file is stdin. 309 # which has no more data to be read. 310 endinput = 1 311 elif fd == fromcfno : 312 # This should never happen, since 313 # CUPS backends don't send anything on their 314 # standard output 315 if outdata : 316 try : 317 os.write(stdoutfno, outdata) 275 318 outdata = "" 276 elif fd == stderrfno : 277 if errdata : 278 os.write(fd, errdata) 319 except : 320 pass 321 try : 322 pollster.unregister(fromcfno) 323 except KeyError : 324 pass 325 else : 326 os.close(fromcfno) 327 elif fd == cerrfno : 328 # Original CUPS backend has finished 329 # to write informations on its standard error 330 if errdata : 331 # Try to write remaining info (normally "Ready to print.") 332 try : 333 os.write(stderrfno, errdata) 279 334 errdata = "" 280 if (mask & select.POLLIN) or (mask & select.POLLPRI) : 281 data = os.read(fd, 256 * 1024) 282 if fd == infno : 283 indata += data 284 if not data : 285 end = 1 # this happens with real files 286 elif fd == fromcfno : 287 outdata += data 288 elif fd == cerrfno : 289 errdata += data 290 if indata : 291 try : 292 os.write(tocfno, indata) 293 except : 294 pass 295 sys.stdout.flush() 296 sys.stderr.flush() 297 subprocess.fromchild.close() 298 subprocess.childerr.close() 299 subprocess.tochild.close() 335 except : 336 pass 337 # We are no more interested in this file descriptor 338 try : 339 pollster.unregister(cerrfno) 340 except KeyError : 341 pass 342 else : 343 os.close(cerrfno) 344 345 if endinput : 346 # We deal with remaining input datas here 347 # because EOF can happen in two different 348 # situations and I don't want to duplicate 349 # code, nor making functions. 350 if indata : 351 try : 352 os.write(tocfno, indata) 353 indata = "" 354 except : 355 pass 356 # Again, we're not interested in this file descriptor 357 # anymore. 358 try : 359 pollster.unregister(tocfno) 360 except KeyError : 361 pass 362 else : 363 os.close(tocfno) 364 365 # Input file was a real file, we have to close it. 300 366 if mustclose : 301 367 infile.close() 302 status = subprocess.wait() 368 369 # Check exit code of original CUPS backend. 303 370 if os.WIFEXITED(status) : 304 371 retcode = os.WEXITSTATUS(status) -
pykota/trunk/NEWS
r1179 r1185 22 22 PyKota NEWS : 23 23 24 - 1.16alpha7 : 25 26 - The CUPS backend is now fully functionnal (it seems). 27 28 - From now on, the use of the pykota filter with CUPS 29 is deprecated. The pykota filter still has to be 30 used with LPRng though. 31 24 32 - 1.16alpha6 : 25 33 -
pykota/trunk/pykota/version.py
r1179 r1185 22 22 # 23 23 24 __version__ = "1.16alpha 6_unofficial"24 __version__ = "1.16alpha7_unofficial" 25 25 26 26 __doc__ = """PyKota : a complete Printing Quota Solution for CUPS and LPRng.""" -
pykota/trunk/README
r1181 r1185 280 280 printers, and change the administrator's email address. 281 281 282 - CUPS Print Backend : 283 284 Modify the PPD files for each printer on which you want to manage 285 print quotas, for example /etc/cups/ppd/lp.ppd : 286 287 --- Add the line below exactly as-is somewhere near the top --- 288 *cupsFilter: "application/vnd.cups-postscript 0 /usr/bin/pykota" 289 --- Add the line above exactly as-is somewhere near the top --- 290 291 Modify the path to the pykota executable if needed, unfortunately 292 you have to supply the correct absolute path here due to CUPS 293 internals, or put the pykota executable into /usr/lib/cups/filter 294 instead of into /usr/bin. 295 296 Do this for each ppd file present in this directory if you want 297 to enable quota on every printer. 298 299 WARNING : In the case you've got a non-postscript printer, chances 300 are that the *cupsFilter is already filled-in and points 301 to cupsomatic or such a print filter. In this case please 302 check if you can switch your printer to PostScript mode 303 or if there's a way to make it accept PostScript jobs. 304 If yes then ensure that your workstations uses a PostScript 305 printer driver, and replace the *cupsFilter line with the 306 one pointing to the pykota filter. This should work, but 307 is currently untested. 308 If your printer really needs the original *cupsFilter line 309 then you may not be able to use PyKota easily for now. 310 311 - LPRng Print Backend : 282 - CUPS Printing System : 283 284 Once and for all : 285 286 Create a symbolic link to the cupspykota backend 287 in CUPS's backend directory : 288 289 $ cd /usr/lib/cups/backend 290 $ ln -s /usr/bin/cupspykota cupspykota 291 292 Restart CUPS so that the new backend can be detected. 293 294 $ /etc/init.d/cupsys restart 295 296 For new printers : 297 298 Go to CUPS management interface (http://localhost:631) 299 and choose the appropriate PyKota managed device depending 300 on the type of printer you use. For example, if your 301 printer is waiting on : 302 303 socket://myprinter.domain.com:9100 304 305 Then choose : 306 307 cupspykota:socket://myprinter.domain.com:9100 308 309 Configure your printer as usual. 310 311 That's all. 312 313 For existing printers : 314 315 If you had already installed PyKota, then remove 316 the *cupsFilter lines in your PPD files for each 317 printer already managed printers. Each line to 318 remove is of the form : 319 320 *cupsFilter: "application/vnd.cups-postscript 0 /usr/bin/pykota" 321 322 Don't touch anything else, especially any other *cupsFilter line. 323 Then save each of these files and restart CUPS. 324 325 Then, the easiest is to directly modify the DeviceURI lines 326 in /etc/cups/printers.conf, you just have to put 327 'cupspykota:' in front of what is already on these lines. 328 For example, replace : 329 330 DeviceURI socket://myprinter.domain.com:9100 331 332 with : 333 334 DeviceURI cupspykota:socket://myprinter.domain.com:9100 335 336 Save the file and restart CUPS. 337 338 - LPRng Printing System : 312 339 313 340 Modify the /etc/printcap file to add two lines identical to these ones :