Changeset 1196

Show
Ignore:
Timestamp:
11/20/03 00:19:38 (20 years ago)
Author:
jalet
Message:

Code refactoring work.
Explicit redirection to /dev/null has to be set in external policy now, just
like in external mailto.

Location:
pykota/trunk
Files:
5 modified

Legend:

Unmodified
Added
Removed
  • pykota/trunk/bin/cupspykota

    r1191 r1196  
    2424# 
    2525# $Log$ 
     26# Revision 1.11  2003/11/19 23:19:35  jalet 
     27# Code refactoring work. 
     28# Explicit redirection to /dev/null has to be set in external policy now, just 
     29# like in external mailto. 
     30# 
    2631# Revision 1.10  2003/11/18 17:54:24  jalet 
    2732# SIGTERMs are now transmitted to original backends. 
     
    6974import signal 
    7075 
    71 from pykota.tool import PyKotaTool, PyKotaToolError 
     76from pykota.tool import PyKotaFilterOrBackend, PyKotaToolError 
    7277from pykota.config import PyKotaConfigError 
    7378from pykota.storage import PyKotaStorageError 
    74 from pykota.accounter import openAccounter, PyKotaAccounterError 
    75 from pykota.requester import openRequester, PyKotaRequesterError 
     79from pykota.accounter import PyKotaAccounterError 
     80from pykota.requester import PyKotaRequesterError 
    7681 
    7782class PyKotaPopen3(popen2.Popen3) : 
     
    96101            os._exit(1) 
    97102     
    98 class PyKotaBackend(PyKotaTool) :     
    99     """Class for the PyKota backend.""" 
    100     def __init__(self) : 
    101         PyKotaTool.__init__(self) 
    102         (self.printingsystem, \ 
    103          self.printerhostname, \ 
    104          self.printername, \ 
    105          self.username, \ 
    106          self.jobid, \ 
    107          self.inputfile, \ 
    108          self.copies, \ 
    109          self.title, \ 
    110          self.options, \ 
    111          self.originalbackend) = self.extractCUPSInfo() 
    112         self.accounter = openAccounter(self) 
    113      
    114     def extractCUPSInfo(self) :     
    115         """Returns a tuple (printingsystem, printerhostname, printername, username, jobid, filename, title, options, backend). 
    116          
    117            Returns (None, None, None, None, None, None, None, None, None, None) if no printing system is recognized. 
    118         """ 
    119         # Try to detect CUPS 
    120         if os.environ.has_key("CUPS_SERVERROOT") and os.path.isdir(os.environ.get("CUPS_SERVERROOT", "")) : 
    121             if len(sys.argv) == 7 : 
    122                 inputfile = sys.argv[6] 
    123             else :     
    124                 inputfile = None 
    125                  
    126             # the DEVICE_URI environment variable's value is  
    127             # prefixed with "cupspykota:" otherwise we wouldn't 
    128             # be called. We have to remove this from the environment  
    129             # before launching the real backend. 
    130             fulldevice_uri = os.environ.get("DEVICE_URI", "") 
    131             device_uri = fulldevice_uri[len("cupspykota:"):] 
    132             if device_uri.startswith("//") :    # lpd (at least) 
    133                 device_uri = device_uri[2:] 
    134             os.environ["DEVICE_URI"] = device_uri 
    135             # TODO : check this for more complex urls than ipp://myprinter.dot.com:631/printers/lp 
    136             try : 
    137                 (backend, destination) = device_uri.split(":", 1)  
    138             except ValueError :     
    139                 raise PyKotaToolError, "Invalid DEVICE_URI : %s\n" % device_uri 
    140             while destination.startswith("/") : 
    141                 destination = destination[1:] 
    142             printerhostname = destination.split("/")[0].split(":")[0] 
    143             return ("CUPS", \ 
    144                     printerhostname, \ 
    145                     os.environ.get("PRINTER"), \ 
    146                     sys.argv[2].strip(), \ 
    147                     sys.argv[1].strip(), \ 
    148                     inputfile, \ 
    149                     int(sys.argv[4].strip()), \ 
    150                     sys.argv[3], \ 
    151                     sys.argv[5], \ 
    152                     backend) 
    153         else :     
    154             self.logger.log_message(_("Printing system unknown, args=%s") % " ".join(sys.argv), "warn") 
    155             return (None, None, None, None, None, None, None, None, None, None)   # Unknown printing system           
    156          
    157 def format_commandline(prt, usr, cmdline) :             
    158     """Passes printer and user names on the command line.""" 
    159     printer = prt.Name 
    160     user = usr.Name 
    161     # we don't want the external command's standard  
    162     # output to break the print job's data, but we 
    163     # want to keep its standard error 
    164     return "%s >/dev/null" % (cmdline % locals()) 
    165  
    166103gotSigTerm = 0 
    167104def sigterm_handler(signum, frame) : 
     
    208145                    action = "POLICY_ALLOW" 
    209146                elif policy == "EXTERNAL" :     
    210                     commandline = format_commandline(printer, user, args) 
     147                    commandline = thebackend.formatCommandLine(args, user, printer) 
    211148                    thebackend.logger.log_message(_("User %s not registered in the PyKota system, applying external policy (%s) for printer %s") % (thebackend.username, commandline, thebackend.printername), "info") 
    212149                    if os.system(commandline) : 
     
    472409        try : 
    473410            # Initializes the backend 
    474             kotabackend = PyKotaBackend()     
     411            kotabackend = PyKotaFilterOrBackend()     
    475412            retcode = main(kotabackend) 
    476         except (PyKotaToolError, PyKotaConfigError, PyKotaStorageError, PyKotaAccounterError, AttributeError, KeyError, IndexError, ValueError, TypeError, IOError), msg : 
     413        except (PyKotaToolError, PyKotaConfigError, PyKotaStorageError, PyKotaAccounterError, PyKotaRequesterError, AttributeError, KeyError, IndexError, ValueError, TypeError, IOError), msg : 
    477414            sys.stderr.write("ERROR : cupspykota backend failed (%s)\n" % msg) 
    478415            sys.stderr.flush() 
  • pykota/trunk/bin/pykota

    r1177 r1196  
    2424# 
    2525# $Log$ 
     26# Revision 1.45  2003/11/19 23:19:37  jalet 
     27# Code refactoring work. 
     28# Explicit redirection to /dev/null has to be set in external policy now, just 
     29# like in external mailto. 
     30# 
    2631# Revision 1.44  2003/11/08 16:05:31  jalet 
    2732# CUPS backend added for people to experiment. 
     
    186191from pykota.config import PyKotaConfigError 
    187192from pykota.storage import PyKotaStorageError 
    188 from pykota.accounter import openAccounter, PyKotaAccounterError 
    189  
    190 class PyKotaFilter(PyKotaTool) :     
    191     """Class for the PyKota filter.""" 
    192     def __init__(self) : 
    193         PyKotaTool.__init__(self) 
    194         (self.printingsystem, self.printerhostname, self.printername, self.username, self.jobid, self.inputfile, self.copies) = self.extractInfoFromCupsOrLprng() 
    195         self.accounter = openAccounter(self) 
    196      
    197     def extractInfoFromCupsOrLprng(self) :     
    198         """Returns a tuple (printingsystem, printerhostname, printername, username, jobid, filename) depending on the printing system in use (as seen by the print filter). 
    199          
    200            Returns (None, None, None, None, None, None, None) if no printing system is recognized. 
    201         """ 
    202         # Try to detect CUPS 
    203         if os.environ.has_key("CUPS_SERVERROOT") and os.path.isdir(os.environ.get("CUPS_SERVERROOT", "")) : 
    204             if len(sys.argv) == 7 : 
    205                 inputfile = sys.argv[6] 
    206             else :     
    207                 inputfile = None 
    208                  
    209             device_uri = os.environ.get("DEVICE_URI", "") 
    210             # TODO : check this for more complex urls than ipp://myprinter.dot.com:631/printers/lp 
    211             try : 
    212                 (backend, destination) = device_uri.split(":", 1)  
    213             except ValueError :     
    214                 raise PyKotaToolError, "Invalid DEVICE_URI : %s\n" % device_uri 
    215             while destination.startswith("/") : 
    216                 destination = destination[1:] 
    217             printerhostname = destination.split("/")[0].split(":")[0] 
    218             return ("CUPS", printerhostname, os.environ.get("PRINTER"), sys.argv[2].strip(), sys.argv[1].strip(), inputfile, int(sys.argv[4].strip())) 
    219         else :     
    220             # Try to detect LPRng 
    221             jseen = Pseen = nseen = rseen = Kseen = None 
    222             for arg in sys.argv : 
    223                 if arg.startswith("-j") : 
    224                     jseen = arg[2:].strip() 
    225                 elif arg.startswith("-n") :      
    226                     nseen = arg[2:].strip() 
    227                 elif arg.startswith("-P") :     
    228                     Pseen = arg[2:].strip() 
    229                 elif arg.startswith("-r") :     
    230                     rseen = arg[2:].strip() 
    231                 elif arg.startswith("-K") or arg.startswith("-#") :     
    232                     Kseen = int(arg[2:].strip()) 
    233             if Kseen is None :         
    234                 Kseen = 1       # we assume the user wants at least one copy... 
    235             if (rseen is None) and jseen and Pseen and nseen :     
    236                 self.logger.log_message(_("Printer hostname undefined, set to 'localhost'"), "warn") 
    237                 rseen = "localhost" 
    238             if jseen and Pseen and nseen and rseen :         
    239                 # job is always in stdin (None) 
    240                 return ("LPRNG", rseen, Pseen, nseen, jseen, None, Kseen) 
    241         self.logger.log_message(_("Printing system unknown, args=%s") % " ".join(sys.argv), "warn") 
    242         return (None, None, None, None, None, None, None)   # Unknown printing system           
    243          
     193from pykota.accounter import PyKotaAccounterError 
     194from pykota.requester import PyKotaRequesterError 
     195 
     196class PyKotaFilter(PyKotaFilterOrBackend) :         
     197    """A class for the pykota filter.""" 
    244198    def acceptJob(self) :         
    245199        """Returns the exit code needed by the printing backend to accept the job and print it.""" 
     
    262216            return -1 
    263217             
    264 def format_commandline(prt, usr, cmdline) :             
    265     """Passes printer and user names on the command line.""" 
    266     printer = prt.Name 
    267     user = usr.Name 
    268     # we don't want the external command's standard  
    269     # output to break the print job's data, but we 
    270     # want to keep its standard error 
    271     return "%s >/dev/null" % (cmdline % locals()) 
    272  
    273218def main(thefilter) :     
    274219    """Do it, and do it right !""" 
     
    300245                    action = "POLICY_ALLOW" 
    301246                elif policy == "EXTERNAL" :     
    302                     commandline = format_commandline(printer, user, args) 
     247                    commandline = thefilter.formatCommandLine(args, user, printer) 
    303248                    thefilter.logger.log_message(_("User %s not registered in the PyKota system, applying external policy (%s) for printer %s") % (thefilter.username, commandline, thefilter.printername), "info") 
    304249                    if os.system(commandline) : 
     
    342287        kotafilter = PyKotaFilter()     
    343288        retcode = main(kotafilter) 
    344     except (PyKotaToolError, PyKotaConfigError, PyKotaStorageError, PyKotaAccounterError, AttributeError, KeyError, IndexError, ValueError, TypeError, IOError), msg : 
     289    except (PyKotaToolError, PyKotaConfigError, PyKotaStorageError, PyKotaAccounterError, PyKotaRequesterError, AttributeError, KeyError, IndexError, ValueError, TypeError, IOError), msg : 
    345290        sys.stderr.write("ERROR : PyKota filter failed (%s)\n" % msg) 
    346291        sys.stderr.flush() 
  • pykota/trunk/conf/pykota.conf.sample

    r1193 r1196  
    340340# if he is unknown. Example : 
    341341#  
    342 #       policy: external(/usr/bin/edpykota --add --printer %(printer)s --softlimit 50 --hardlimit 60 %(user)s)  
    343 # 
    344 #       NB : '%(user)s' and '%(printer)s' will be automatically replaced  
    345 #            by the user and printer names.  
     342#       policy: external(/usr/bin/edpykota --add --printer %(printer)s --softlimit 50 --hardlimit 60 %(user)s >/dev/null)  
    346343# 
    347344# Of course you can launch any command of your choice with this, e.g. : 
    348345# 
    349 #       policy: external(/usr/local/bin/myadminscript.sh %(user)s) 
     346#       policy: external(/usr/local/bin/myadminscript.sh %(user)s >/dev/null) 
     347 
     348# You can use : 
     349# 
     350#       '%(username)s'          will contain the user's name 
     351#       '%(printername)s'       will contain the printer's name 
     352# 
     353#   On your command line, to pass arguments to your command. 
     354# 
     355#   NB : Don't forget to redirect your command's standard output somewhere  
     356#        (e.g. >/dev/null) so that there's no perturbation to the underlying 
     357#        layer (filter or backend) 
     358# 
     359# If the user still doesn't exist after external policy command was  
     360# launched (the external command didn't add it), or if an error occured 
     361# during the execution of the external policy command, the job is rejected. 
    350362# 
    351363policy: deny 
  • pykota/trunk/NEWS

    r1194 r1196  
    2323 
    2424    - 1.16alpha10 : 
     25         
     26        - Some modifications done to external policy handling. 
     27          See sample configuration file for details. 
    2528     
    2629        - Spanish translation added. 
  • pykota/trunk/pykota/tool.py

    r1193 r1196  
    2222# 
    2323# $Log$ 
     24# Revision 1.57  2003/11/19 23:19:38  jalet 
     25# Code refactoring work. 
     26# Explicit redirection to /dev/null has to be set in external policy now, just 
     27# like in external mailto. 
     28# 
    2429# Revision 1.56  2003/11/19 07:40:20  jalet 
    2530# Missing import statement. 
     
    234239 
    235240from pykota import version, config, storage, logger 
     241from pykota.accounter import openAccounter 
    236242 
    237243class PyKotaToolError(Exception): 
     
    514520        return action 
    515521     
    516     def externalMailTo(self, cmd, action, user, printername, message) : 
     522    def externalMailTo(self, cmd, action, user, printer, message) : 
    517523        """Warns the user with an external command.""" 
    518524        username = user.Name 
     525        printername = printer.Name 
    519526        email = user.Email or user.Name 
    520527        if "@" not in email : 
     
    522529        os.system(cmd % locals()) 
    523530     
     531    def formatCommandLine(self, cmd, user, printer) : 
     532        """Executes an external command.""" 
     533        username = user.Name 
     534        printername = printer.Name 
     535        return cmd % locals() 
     536         
    524537    def warnGroupPQuota(self, grouppquota) : 
    525538        """Checks a group quota and send messages if quota is exceeded on current printer.""" 
     
    542555                        self.sendMessageToUser(admin, adminmail, user, _("Print Quota Exceeded"), self.config.getHardWarn(printer.Name)) 
    543556                    else :     
    544                         self.externalMailTo(arguments, action, user, printer.Name, message) 
     557                        self.externalMailTo(arguments, action, user, printer, message) 
    545558        elif action == "WARN" :     
    546559            adminmessage = _("Print Quota low for group %s on printer %s") % (group.Name, printer.Name) 
     
    557570                        self.sendMessageToUser(admin, adminmail, user, _("Print Quota Exceeded"), message) 
    558571                    else :     
    559                         self.externalMailTo(arguments, action, user, printer.Name, message) 
     572                        self.externalMailTo(arguments, action, user, printer, message) 
    560573        return action         
    561574         
     
    578591                    self.sendMessageToUser(admin, adminmail, user, _("Print Quota Exceeded"), message) 
    579592                else :     
    580                     self.externalMailTo(arguments, action, user, printer.Name, message) 
     593                    self.externalMailTo(arguments, action, user, printer, message) 
    581594            if mailto in [ "BOTH", "ADMIN" ] : 
    582595                self.sendMessageToAdmin(adminmail, _("Print Quota"), adminmessage) 
     
    592605                    self.sendMessageToUser(admin, adminmail, user, _("Print Quota Low"), message) 
    593606                else :     
    594                     self.externalMailTo(arguments, action, user, printer.Name, message) 
     607                    self.externalMailTo(arguments, action, user, printer, message) 
    595608            if mailto in [ "BOTH", "ADMIN" ] : 
    596609                self.sendMessageToAdmin(adminmail, _("Print Quota"), adminmessage) 
    597610        return action         
     611         
     612class PyKotaFilterOrBackend(PyKotaTool) :     
     613    """Class for the PyKota filter or backend.""" 
     614    def __init__(self) : 
     615        PyKotaTool.__init__(self) 
     616        (self.printingsystem, \ 
     617         self.printerhostname, \ 
     618         self.printername, \ 
     619         self.username, \ 
     620         self.jobid, \ 
     621         self.inputfile, \ 
     622         self.copies, \ 
     623         self.title, \ 
     624         self.options, \ 
     625         self.originalbackend) = self.extractInfoFromCupsOrLprng() 
     626        self.accounter = openAccounter(self) 
     627     
     628    def extractInfoFromCupsOrLprng(self) :     
     629        """Returns a tuple (printingsystem, printerhostname, printername, username, jobid, filename, title, options, backend). 
     630         
     631           Returns (None, None, None, None, None, None, None, None, None, None) if no printing system is recognized. 
     632        """ 
     633        # Try to detect CUPS 
     634        if os.environ.has_key("CUPS_SERVERROOT") and os.path.isdir(os.environ.get("CUPS_SERVERROOT", "")) : 
     635            if len(sys.argv) == 7 : 
     636                inputfile = sys.argv[6] 
     637            else :     
     638                inputfile = None 
     639                 
     640            # check that the DEVICE_URI environment variable's value is  
     641            # prefixed with "cupspykota:" otherwise don't touch it. 
     642            # If this is the case, we have to remove the prefix from  
     643            # the environment before launching the real backend in cupspykota 
     644            device_uri = os.environ.get("DEVICE_URI", "") 
     645            if device_uri.startswith("cupspykota:") : 
     646                fulldevice_uri = device_uri[:] 
     647                device_uri = fulldevice_uri[len("cupspykota:"):] 
     648                if device_uri.startswith("//") :    # lpd (at least) 
     649                    device_uri = device_uri[2:] 
     650                os.environ["DEVICE_URI"] = device_uri   # TODO : side effect ! 
     651            # TODO : check this for more complex urls than ipp://myprinter.dot.com:631/printers/lp 
     652            try : 
     653                (backend, destination) = device_uri.split(":", 1)  
     654            except ValueError :     
     655                raise PyKotaToolError, "Invalid DEVICE_URI : %s\n" % device_uri 
     656            while destination.startswith("/") : 
     657                destination = destination[1:] 
     658            printerhostname = destination.split("/")[0].split(":")[0] 
     659            return ("CUPS", \ 
     660                    printerhostname, \ 
     661                    os.environ.get("PRINTER"), \ 
     662                    sys.argv[2].strip(), \ 
     663                    sys.argv[1].strip(), \ 
     664                    inputfile, \ 
     665                    int(sys.argv[4].strip()), \ 
     666                    sys.argv[3], \ 
     667                    sys.argv[5], \ 
     668                    backend) 
     669        else :     
     670            # Try to detect LPRng 
     671            jseen = Pseen = nseen = rseen = Kseen = None 
     672            for arg in sys.argv : 
     673                if arg.startswith("-j") : 
     674                    jseen = arg[2:].strip() 
     675                elif arg.startswith("-n") :      
     676                    nseen = arg[2:].strip() 
     677                elif arg.startswith("-P") :     
     678                    Pseen = arg[2:].strip() 
     679                elif arg.startswith("-r") :     
     680                    rseen = arg[2:].strip() 
     681                elif arg.startswith("-K") or arg.startswith("-#") :     
     682                    Kseen = int(arg[2:].strip()) 
     683            if Kseen is None :         
     684                Kseen = 1       # we assume the user wants at least one copy... 
     685            if (rseen is None) and jseen and Pseen and nseen :     
     686                self.logger.log_message(_("Printer hostname undefined, set to 'localhost'"), "warn") 
     687                rseen = "localhost" 
     688            if jseen and Pseen and nseen and rseen :         
     689                # job is always in stdin (None) 
     690                return ("LPRNG", rseen, Pseen, nseen, jseen, None, Kseen, None, None, None) 
     691        self.logger.log_message(_("Printing system unknown, args=%s") % " ".join(sys.argv), "warn") 
     692        return (None, None, None, None, None, None, None, None, None, None)   # Unknown printing system