Changeset 1221

Show
Ignore:
Timestamp:
11/26/03 20:17:35 (21 years ago)
Author:
jalet
Message:

Printing on a printer not present in the Quota Storage now results
in the job being stopped or cancelled depending on the system.

Location:
pykota/trunk
Files:
4 modified

Legend:

Unmodified
Added
Removed
  • pykota/trunk/bin/cupspykota

    r1210 r1221  
    2424# 
    2525# $Log$ 
     26# Revision 1.15  2003/11/26 19:17:35  jalet 
     27# Printing on a printer not present in the Quota Storage now results 
     28# in the job being stopped or cancelled depending on the system. 
     29# 
    2630# Revision 1.14  2003/11/25 13:25:45  jalet 
    2731# Boolean problem with old Python, replaced with 0 
     
    137141    if not printer.Exists : 
    138142        # The printer is unknown from the Quota Storage perspective 
    139         # we let the job pass through, but log a warning message 
    140         thebackend.logger.log_message(_("Printer %s not registered in the PyKota system") % thebackend.printername, "warn") 
    141         action = "ALLOW" 
     143        # we send an error back to CUPS, which will stop 
     144        # the print queue. 
     145        thebackend.logger.log_message(_("Printer %s not registered in the PyKota system") % thebackend.printername, "error") 
     146        return 1 
    142147    else :     
    143148        for dummy in range(2) : 
     
    187192            return 0 
    188193         
    189     if action not in ["ALLOW", "WARN"] :     
    190         # if not allowed to print then die, else proceed. 
    191         # we die without error, so that the job doesn't  
    192         # stop the print queue. 
    193         retcode = 0 
    194     else : 
    195         # pass the job untouched to the underlying layer 
    196         # and starts accounting at the same time 
    197         thebackend.accounter.beginJob(printer, user) 
    198          
    199         # Now it becomes tricky... 
    200          
    201         # First ensure that we have a file object as input 
    202         mustclose = 0     
    203         if thebackend.inputfile is not None :     
    204             if hasattr(thebackend.inputfile, "read") : 
    205                 infile = thebackend.inputfile 
     194        if action not in ["ALLOW", "WARN"] :     
     195            # if not allowed to print then die, else proceed. 
     196            # we die without error, so that the job doesn't  
     197            # stop the print queue. 
     198            retcode = 0 
     199        else : 
     200            # pass the job untouched to the underlying layer 
     201            # and starts accounting at the same time 
     202            thebackend.accounter.beginJob(printer, user) 
     203             
     204            # Now it becomes tricky... 
     205             
     206            # First ensure that we have a file object as input 
     207            mustclose = 0     
     208            if thebackend.inputfile is not None :     
     209                if hasattr(thebackend.inputfile, "read") : 
     210                    infile = thebackend.inputfile 
     211                else :     
     212                    infile = open(thebackend.inputfile, "rb") 
     213                mustclose = 1 
    206214            else :     
    207                 infile = open(thebackend.inputfile, "rb") 
    208             mustclose = 1 
    209         else :     
    210             infile = sys.stdin 
    211              
    212         # Find the real backend pathname     
    213         realbackend = os.path.join(os.path.split(sys.argv[0])[0], thebackend.originalbackend) 
    214          
    215         # And launch it 
    216         subprocess = PyKotaPopen3([realbackend] + sys.argv[1:], capturestderr=1, bufsize=0, arg0=os.environ["DEVICE_URI"]) 
    217          
    218         # Save file descriptors, we will need them later. 
    219         infno = infile.fileno() 
    220         stdoutfno = sys.stdout.fileno() 
    221         stderrfno = sys.stderr.fileno() 
    222         fromcfno = subprocess.fromchild.fileno() 
    223         tocfno = subprocess.tochild.fileno() 
    224         cerrfno = subprocess.childerr.fileno() 
    225          
    226         # We will have to be careful when dealing with I/O  
    227         # So we use a poll object to know when to read or write 
    228         pollster = select.poll() 
    229         pollster.register(infno, select.POLLIN | select.POLLPRI) 
    230         pollster.register(fromcfno, select.POLLIN | select.POLLPRI) 
    231         pollster.register(cerrfno, select.POLLIN | select.POLLPRI) 
    232         pollster.register(stdoutfno, select.POLLOUT) 
    233         pollster.register(stderrfno, select.POLLOUT) 
    234         pollster.register(tocfno, select.POLLOUT) 
    235          
    236         # Initialize our buffers 
    237         indata = "" 
    238         outdata = "" 
    239         errdata = "" 
    240         endinput = 0 
    241         status = -1 
    242         while status == -1 : 
    243             # First check if original backend is still alive 
    244             status = subprocess.poll() 
    245              
    246             # Now if we got SIGTERM, we have  
    247             # to kill -TERM the original backend 
    248             if gotSigTerm : 
    249                 try : 
    250                     os.kill(subprocess.pid, signal.SIGTERM) 
    251                 except : # ignore if process was already killed. 
    252                     pass 
    253              
    254             # In any case, deal with any remaining I/O 
    255             availablefds = pollster.poll() 
    256             for (fd, mask) in availablefds : 
    257                 if mask & select.POLLOUT : 
    258                     # We can write 
    259                     if fd == tocfno : 
    260                         if indata : 
    261                             os.write(fd, indata)     
     215                infile = sys.stdin 
     216                 
     217            # Find the real backend pathname     
     218            realbackend = os.path.join(os.path.split(sys.argv[0])[0], thebackend.originalbackend) 
     219             
     220            # And launch it 
     221            subprocess = PyKotaPopen3([realbackend] + sys.argv[1:], capturestderr=1, bufsize=0, arg0=os.environ["DEVICE_URI"]) 
     222             
     223            # Save file descriptors, we will need them later. 
     224            infno = infile.fileno() 
     225            stdoutfno = sys.stdout.fileno() 
     226            stderrfno = sys.stderr.fileno() 
     227            fromcfno = subprocess.fromchild.fileno() 
     228            tocfno = subprocess.tochild.fileno() 
     229            cerrfno = subprocess.childerr.fileno() 
     230             
     231            # We will have to be careful when dealing with I/O  
     232            # So we use a poll object to know when to read or write 
     233            pollster = select.poll() 
     234            pollster.register(infno, select.POLLIN | select.POLLPRI) 
     235            pollster.register(fromcfno, select.POLLIN | select.POLLPRI) 
     236            pollster.register(cerrfno, select.POLLIN | select.POLLPRI) 
     237            pollster.register(stdoutfno, select.POLLOUT) 
     238            pollster.register(stderrfno, select.POLLOUT) 
     239            pollster.register(tocfno, select.POLLOUT) 
     240             
     241            # Initialize our buffers 
     242            indata = "" 
     243            outdata = "" 
     244            errdata = "" 
     245            endinput = 0 
     246            status = -1 
     247            while status == -1 : 
     248                # First check if original backend is still alive 
     249                status = subprocess.poll() 
     250                 
     251                # Now if we got SIGTERM, we have  
     252                # to kill -TERM the original backend 
     253                if gotSigTerm : 
     254                    try : 
     255                        os.kill(subprocess.pid, signal.SIGTERM) 
     256                    except : # ignore if process was already killed. 
     257                        pass 
     258                 
     259                # In any case, deal with any remaining I/O 
     260                availablefds = pollster.poll() 
     261                for (fd, mask) in availablefds : 
     262                    if mask & select.POLLOUT : 
     263                        # We can write 
     264                        if fd == tocfno : 
     265                            if indata : 
     266                                os.write(fd, indata)     
     267                                indata = "" 
     268                        elif fd == stdoutfno : 
     269                            if outdata : 
     270                                os.write(fd, outdata) 
     271                                outdata = "" 
     272                        elif fd == stderrfno : 
     273                            if errdata : 
     274                                os.write(fd, errdata) 
     275                                errdata = "" 
     276                    if (mask & select.POLLIN) or (mask & select.POLLPRI) :      
     277                        # We have something to read 
     278                        data = os.read(fd, 256 * 1024) 
     279                        if fd == infno : 
     280                            indata += data 
     281                            if not data :    # If yes, then no more input data 
     282                                endinput = 1 # this happens with real files. 
     283                        elif fd == fromcfno : 
     284                            outdata += data 
     285                        elif fd == cerrfno :     
     286                            errdata += data 
     287                    if (mask & select.POLLHUP) or (mask & select.POLLERR) : 
     288                        # I've never seen POLLERR myself, but this probably 
     289                        # can't hurt to treat an error condition just like  
     290                        # an EOF. 
     291                        #  
     292                        # Some standard I/O stream has no more datas 
     293                        if fd == infno : 
     294                            # Here we are in the case where the input file is stdin. 
     295                            # which has no more data to be read. 
     296                            endinput = 1 
     297                        elif fd == fromcfno :     
     298                            # This should never happen, since 
     299                            # CUPS backends don't send anything on their 
     300                            # standard output 
     301                            if outdata :                 
     302                                try : 
     303                                    os.write(stdoutfno, outdata) 
     304                                    outdata = "" 
     305                                except :     
     306                                    pass 
     307                            try :         
     308                                pollster.unregister(fromcfno)         
     309                            except KeyError :     
     310                                pass 
     311                            else :     
     312                                os.close(fromcfno) 
     313                        elif fd == cerrfno :     
     314                            # Original CUPS backend has finished  
     315                            # to write informations on its standard error 
     316                            if errdata :                 
     317                                # Try to write remaining info (normally "Ready to print.") 
     318                                try : 
     319                                    os.write(stderrfno, errdata) 
     320                                    errdata = "" 
     321                                except :     
     322                                    pass 
     323                            # We are no more interested in this file descriptor         
     324                            try :         
     325                                pollster.unregister(cerrfno)         
     326                            except KeyError :     
     327                                pass 
     328                            else :     
     329                                os.close(cerrfno) 
     330                             
     331                if endinput :             
     332                    # We deal with remaining input datas here 
     333                    # because EOF can happen in two different 
     334                    # situations and I don't want to duplicate 
     335                    # code, nor making functions. 
     336                    if indata :                 
     337                        try : 
     338                            os.write(tocfno, indata) 
    262339                            indata = "" 
    263                     elif fd == stdoutfno : 
    264                         if outdata : 
    265                             os.write(fd, outdata) 
    266                             outdata = "" 
    267                     elif fd == stderrfno : 
    268                         if errdata : 
    269                             os.write(fd, errdata) 
    270                             errdata = "" 
    271                 if (mask & select.POLLIN) or (mask & select.POLLPRI) :      
    272                     # We have something to read 
    273                     data = os.read(fd, 256 * 1024) 
    274                     if fd == infno : 
    275                         indata += data 
    276                         if not data :    # If yes, then no more input data 
    277                             endinput = 1 # this happens with real files. 
    278                     elif fd == fromcfno : 
    279                         outdata += data 
    280                     elif fd == cerrfno :     
    281                         errdata += data 
    282                 if (mask & select.POLLHUP) or (mask & select.POLLERR) : 
    283                     # I've never seen POLLERR myself, but this probably 
    284                     # can't hurt to treat an error condition just like  
    285                     # an EOF. 
    286                     #  
    287                     # Some standard I/O stream has no more datas 
    288                     if fd == infno : 
    289                         # Here we are in the case where the input file is stdin. 
    290                         # which has no more data to be read. 
    291                         endinput = 1 
    292                     elif fd == fromcfno :     
    293                         # This should never happen, since 
    294                         # CUPS backends don't send anything on their 
    295                         # standard output 
    296                         if outdata :                 
    297                             try : 
    298                                 os.write(stdoutfno, outdata) 
    299                                 outdata = "" 
    300                             except :     
    301                                 pass 
    302                         try :         
    303                             pollster.unregister(fromcfno)         
    304                         except KeyError :     
     340                        except :     
    305341                            pass 
    306                         else :     
    307                             os.close(fromcfno) 
    308                     elif fd == cerrfno :     
    309                         # Original CUPS backend has finished  
    310                         # to write informations on its standard error 
    311                         if errdata :                 
    312                             # Try to write remaining info (normally "Ready to print.") 
    313                             try : 
    314                                 os.write(stderrfno, errdata) 
    315                                 errdata = "" 
    316                             except :     
    317                                 pass 
    318                         # We are no more interested in this file descriptor         
    319                         try :         
    320                             pollster.unregister(cerrfno)         
    321                         except KeyError :     
    322                             pass 
    323                         else :     
    324                             os.close(cerrfno) 
    325                          
    326             if endinput :             
    327                 # We deal with remaining input datas here 
    328                 # because EOF can happen in two different 
    329                 # situations and I don't want to duplicate 
    330                 # code, nor making functions. 
    331                 if indata :                 
    332                     try : 
    333                         os.write(tocfno, indata) 
    334                         indata = "" 
    335                     except :     
     342                    # Again, we're not interested in this file descriptor         
     343                    # anymore. 
     344                    try :         
     345                        pollster.unregister(tocfno)         
     346                    except KeyError :     
    336347                        pass 
    337                 # Again, we're not interested in this file descriptor         
    338                 # anymore. 
    339                 try :         
    340                     pollster.unregister(tocfno)         
    341                 except KeyError :     
    342                     pass 
    343                 else :     
    344                     os.close(tocfno) 
     348                    else :     
     349                        os.close(tocfno) 
     350                     
     351            # Input file was a real file, we have to close it.     
     352            if mustclose : 
     353                infile.close() 
    345354                 
    346         # Input file was a real file, we have to close it.     
    347         if mustclose : 
    348             infile.close() 
    349              
    350         # Check exit code of original CUPS backend.     
    351         if os.WIFEXITED(status) : 
    352             retcode = os.WEXITSTATUS(status) 
    353         else :     
    354             thebackend.logger.log_message(_("CUPS backend %s died abnormally.") % realbackend, "error") 
    355             retcode = -1 
    356      
    357     # stops accounting.  
    358     thebackend.accounter.endJob(printer, user) 
    359          
    360     # retrieve the job size     
    361     jobsize = thebackend.accounter.getJobSize() 
    362      
    363     # update the quota for the current user on this printer  
    364     if printer.Exists : 
    365         jobprice = (float(printer.PricePerPage or 0.0) * jobsize) + float(printer.PricePerJob or 0.0) 
    366         if jobsize : 
    367             userquota = thebackend.storage.getUserPQuota(user, printer) 
    368             if userquota.Exists : 
    369                 userquota.increasePagesUsage(jobsize) 
    370          
    371         # adds the current job to history     
    372         printer.addJobToHistory(thebackend.jobid, user, thebackend.accounter.getLastPageCounter(), action, jobsize, jobprice, thebackend.preserveinputfile, thebackend.title, thebackend.copies, thebackend.options) 
    373      
    374     return retcode # return (retcode or gotSigTerm) shouldn't be needed 
     355            # Check exit code of original CUPS backend.     
     356            if os.WIFEXITED(status) : 
     357                retcode = os.WEXITSTATUS(status) 
     358            else :     
     359                thebackend.logger.log_message(_("CUPS backend %s died abnormally.") % realbackend, "error") 
     360                retcode = -1 
     361         
     362        # stops accounting.  
     363        thebackend.accounter.endJob(printer, user) 
     364             
     365        # retrieve the job size     
     366        jobsize = thebackend.accounter.getJobSize() 
     367         
     368        # update the quota for the current user on this printer  
     369        if printer.Exists : 
     370            jobprice = (float(printer.PricePerPage or 0.0) * jobsize) + float(printer.PricePerJob or 0.0) 
     371            if jobsize : 
     372                userquota = thebackend.storage.getUserPQuota(user, printer) 
     373                if userquota.Exists : 
     374                    userquota.increasePagesUsage(jobsize) 
     375             
     376            # adds the current job to history     
     377            printer.addJobToHistory(thebackend.jobid, user, thebackend.accounter.getLastPageCounter(), action, jobsize, jobprice, thebackend.preserveinputfile, thebackend.title, thebackend.copies, thebackend.options) 
     378         
     379        return retcode # return (retcode or gotSigTerm) shouldn't be needed 
    375380 
    376381if __name__ == "__main__" :     
  • pykota/trunk/bin/pykota

    r1205 r1221  
    2424# 
    2525# $Log$ 
     26# Revision 1.47  2003/11/26 19:17:35  jalet 
     27# Printing on a printer not present in the Quota Storage now results 
     28# in the job being stopped or cancelled depending on the system. 
     29# 
    2630# Revision 1.46  2003/11/24 14:25:02  jalet 
    2731# Missing import in pykota filter 
     
    231235    printer = thefilter.storage.getPrinter(thefilter.printername) 
    232236    if not printer.Exists : 
    233         # The printer is unknown from the Quota Storage perspective 
    234         # we let the job pass through, but log a warning message 
    235         thefilter.logger.log_message(_("Printer %s not registered in the PyKota system") % thefilter.printername, "warn") 
     237        # The printer is unknown from the Quota Storage perspective. 
     238        # we just cancel the job. 
     239        thefilter.logger.log_message(_("Printer %s not registered in the PyKota system") % thefilter.printername, "error") 
     240        return thefilter.removeJob() 
    236241    else :     
    237242        for dummy in range(2) : 
     
    279284            return thefilter.removeJob() 
    280285         
    281     # pass the job untouched to the underlying layer 
    282     thefilter.accounter.filterInput(thefilter.inputfile)       
     286        # pass the job untouched to the underlying layer 
     287        thefilter.accounter.filterInput(thefilter.inputfile)       
    283288     
    284     return thefilter.acceptJob() 
     289        return thefilter.acceptJob() 
    285290 
    286291if __name__ == "__main__" :     
  • pykota/trunk/NEWS

    r1220 r1221  
    2222PyKota NEWS : 
    2323 
     24    - 1.16alpha14 : 
     25     
     26        - Now printing on a printer not defined in the Quota Storage, 
     27          results in the job being cancelled or stopped, depending 
     28          on the printing system. 
     29           
    2430    - 1.16alpha13 : 
    2531     
  • pykota/trunk/pykota/version.py

    r1212 r1221  
    2222# 
    2323 
    24 __version__ = "1.16alpha13_unofficial" 
     24__version__ = "1.16alpha14_unofficial" 
    2525 
    2626__doc__ = """PyKota : a complete Printing Quota Solution for CUPS and LPRng."""