Index: /pykota/trunk/conf/pykota.conf.sample
===================================================================
--- /pykota/trunk/conf/pykota.conf.sample (revision 1442)
+++ /pykota/trunk/conf/pykota.conf.sample (revision 1475)
@@ -182,44 +182,36 @@
 # supported values :
 #
-#    - querying : asks the printer for its lifetime page counter
+#    - hardware : asks the printer for its lifetime page counter
 #                 via either SNMP, AppleTalk, or any external
 #                 command. This method is the method used by
 #                 default in PyKota since its beginning.
 #
-#    - external : delegates the job's size computation to any 
-#                 external command of your choice. A stupid and 
-#                 completely unreliable example, but which
-#                 shows what this command may be is :
-#
-#                   accounter: external(/bin/grep -c showpage)
-#
-#                 Another one, which should work with all DSC
-#                 compliant Postscript files :
-#
-#                   accounter: external(/bin/grep -c "%%Page:")
-#
-#                 Finally the new smart external accounter which
-#                 can handle both PostScript and PCL documents :
-#
-#                   accounter: external(/usr/bin/pkpgcounter)
-# 
-#    - stupid : counts the occurences of the 'showpage' postscript
-#               statement in the document to be printed.
-#               THIS IS NOT RELIABLE. This is just to serve as
-#               an example on how to implement your own accounting
-#               method. Use pkpgcounter instead.
-#
+#    - software : delegates the job's size computation to any 
+#                 external command of your choice. 
+#
+#                 best choice for this is probably to set it
+#                 this way :
+#
+#                   accounter: software(/usr/bin/pkpgcounter)
+#
+#                 pkpgcounter is a command line tool which is
+#                 part of PyKota and which can handle both
+#                 DSC compliant PostScript documents and PCL5
+#                 documents. More file formats will be added
+#                 in the future, as time permits.
+#
+#                 while pkpgcounter is the recommended value
+#                 you can use whatever command you want provided
+#                 that your command accepts the job's data on its
+#                 standard input and prints the job's size in pages
+#                 as a single integer on its standard output.
+# 
 # This value can be set either globally or on a per printer basis
 # If both are defined, the printer option has priority.
-# if not set it defaults to 'querying'.
-#
-# A script which seems to be accurate, copy it from the
-# untested/postscript directory to another place.
-# accounter: external(/usr/share/pykota/pagecount.sh)
-# WARNING : it may not work when multiple copies are asked.
-#           this breaks ghostscript, I don't know why yet.
+# if not set it defaults to 'hardware'.
 #
 # default value 
-accounter: querying
+accounter: hardware
+# accounter: software(/usr/bin/pkpgcounter)
 
 # Print Quota administrator
@@ -326,5 +318,5 @@
 
 # How to query the hpmarketing printer for its page counter.
-# THIS IS ONLY USED IF YOU HAVE SET 'accounter' TO 'querying'
+# THIS IS ONLY USED IF YOU HAVE SET 'accounter' TO 'hardware'
 # JUST COMMENT IT OUT IF YOU USE ANY OTHER ACCOUNTING METHOD.
 # (it would be ignored anyway)
@@ -332,21 +324,15 @@
 # In the lines below "%(printer)s" is automatically replaced
 # at run time with your printer's Fully Qualified Domain Name
+# for network printers.
 # e.g. myprinter.example.com
 #
-# Only snmp(community, oid) and external(command) are supported
+# Only value supported is : external(... your command here...) 
 #
 # Example : 
+#
 #     requester: external(/usr/bin/snmpget -v1 -c public -Ov %(printer)s mib-2.43.10.2.1.4.1.1 | cut -f 2,2 -d " ")
-# and :
-#     requester: snmp(public, mib-2.43.10.2.1.4.1.1)
-# are equivalent
-#
-#################################################
-# NB : the 'snmp()' requester is now deprecated #
-# because it has some accuracy problems.        #
-# please use 'external()' instead.              #
-#################################################
 #
 # Another untested example, using npadmin :
+#
 #     requester: external(/usr/bin/npadmin --pagecount %(printer)s)
 #
@@ -355,4 +341,5 @@
 # pagecount.ps file from untested/netatalk into /etc or any 
 # appropriate location)
+#
 #     requester: external(/usr/share/pykota/papwaitprinter.sh "MyPrinter:LaserWriter@*" && /usr/bin/pap -p "MyPrinter:LaserWriter@*" /usr/share/pykota/pagecount.ps  2>/dev/null | /bin/grep -v status | /bin/grep -v Connect | /usr/bin/tail -1)
 #
@@ -361,13 +348,6 @@
 #     requester: external(/bin/cat /usr/share/pykota/pagecount.pjl >/dev/lp0 && /usr/bin/head -2 </dev/lp0 | /usr/bin/tail -1)
 # 
-# 
 # This value can be set either globally or per printer or both.
 # If both are defined, the printer option has priority.
-#
-# NB : The SNMP oid mib-2.43.10.2.1.4.1.1 works on HP Laserjet Printers, but it may
-#      be different with other brands, refer to your printer's documentation 
-#      for details. Also you may have to specify -v2c or -v3 depending on your 
-#      printer's support for different versions of the SNMP specification.
-#
 #
 # Some examples and comments provided by Bob Martel from csuohio.edu
@@ -382,5 +362,4 @@
 #
 # requester: external(/opt/local/net-snmp/bin/snmpwalk -v 1 -Cc -c public -Ov %(printer)s | grep Counter32 | tail -2 | head -1 | cut -d " " -f2)
-#
 #
 # An example using netcat and a preformatted PJL job which you can find
@@ -390,10 +369,8 @@
 # requester: external(/bin/nc -w 2 %(printer)s 9100 </usr/share/pykota/pagecount.pjl | /usr/bin/tail -2)
 #
-#
 # An example using the contributed pagecount.pl script which does 
 # the same as above, but should work on more printers : 
 #
 # requester: external(/usr/share/pykota/pagecount.pl %(printer)s 9100)
-#
 #
 # WARNING : In any case, when using an external requester, please test the command line outside
@@ -404,4 +381,11 @@
 # not yet finished (not all pages are printed, but the complete job is in 
 # the printer)
+#
+# YOU ABSOLUTELY HAVE TO BE SURE YOU HAVE A SCRIPT WHICH WAITS FOR THE
+# PRINTER BEING READY BEFORE ASKING FOR ITS INTERNAL PAGE COUNTER.
+#
+# PYKOTA INCLUDES SUCH SCRIPTS FOR SNMP AND APPLETALK PRINTERS, MORE TO COME
+#
+# default value
 requester: external(/usr/share/pykota/waitprinter.sh %(printer)s && /usr/bin/snmpget -v1 -c public -Ov %(printer)s mib-2.43.10.2.1.4.1.1 | cut -f 2,2 -d " ")
 
Index: /pykota/trunk/setup.py
===================================================================
--- /pykota/trunk/setup.py (revision 1430)
+++ /pykota/trunk/setup.py (revision 1475)
@@ -24,4 +24,7 @@
 #
 # $Log$
+# Revision 1.40  2004/05/13 13:59:27  jalet
+# Code simplifications
+#
 # Revision 1.39  2004/04/08 17:07:41  jalet
 # pkpgcounter added
@@ -173,4 +176,5 @@
     sys.exit(-1)
 
+from distutils import sysconfig
 sys.path.insert(0, "pykota")
 from pykota.version import __version__, __doc__
@@ -179,4 +183,14 @@
 ACTION_ABORT = 1
 
+def checkOldModule(path) :
+    """Checks if an old PyKota module is still in the destination (in case of upgrade)."""
+    fname = os.path.join(sysconfig.get_python_lib(), "pykota", path)
+    for ext in ["py", "pyc", "pyo"] :
+        fullname = "%s.%s" % (fname, ext)
+        if os.path.isfile(fullname) :
+            sys.stderr.write("ERROR : old module %s still exists. Remove it and restart installation.\n" % fullname)
+            sys.stderr.write("INSTALLATION ABORTED !\n")
+            sys.exit(-1)
+    
 def checkOldScript(cmd) :
     """Checks if an old shell script is still around in /usr/bin."""
@@ -282,4 +296,8 @@
                 sys.stderr.write("\nINSTALLATION ABORTED !\nPlease correct the problem and restart installation.\n")
                 sys.exit(-1)
+                
+        # now checks if pre-1.19alpha8 code is still there       
+        for module in ["accounters/querying", "accounters/external", "requesters/snmp"] :
+            checkOldModule(module)
         
     # Second stage, we will fail if onfiguration is incorrect for security reasons
@@ -348,11 +366,10 @@
     
     # WARNING MESSAGE    
-    sys.stdout.write("WARNING : IF YOU ARE UPGRADING FROM A PRE-1.14 TO 1.16 OR ABOVE\n")
+    sys.stdout.write("WARNING : IF YOU ARE UPGRADING FROM A PRE-1.19alpha7 TO 1.19alpha7 OR ABOVE\n")
     sys.stdout.write("AND USE THE POSTGRESQL BACKEND, THEN YOU HAVE TO MODIFY YOUR\n")
-    sys.stdout.write("DATABASE SCHEMA USING initscripts/postgresql/upgrade-to-1.14.sql\n")
-    sys.stdout.write("AND initscripts/postgresql/upgrade-to-1.16.sql\n")
+    sys.stdout.write("DATABASE SCHEMA USING initscripts/postgresql/upgrade-to-1.19.sql\n")
     sys.stdout.write("PLEASE READ DOCUMENTATION IN initscripts/postgresql/ TO LEARN HOW TO DO.\n")
     sys.stdout.write("YOU CAN DO THAT AFTER THE INSTALLATION IS FINISHED, OR PRESS CTRL+C NOW.\n")
-    sys.stdout.write("\n\nYOU DON'T HAVE ANYTHING SPECIAL TO DO IF THIS IS YOUR FIRST INSTALLATION\nOR IF YOU ARE ALREADY RUNNING VERSION 1.16 OR ABOVE.\n\n")
+    sys.stdout.write("\n\nYOU DON'T HAVE ANYTHING SPECIAL TO DO IF THIS IS YOUR FIRST INSTALLATION\nOR IF YOU ARE ALREADY RUNNING VERSION 1.19alpha7 OR ABOVE.\n\n")
     dummy = raw_input("Please press ENTER when you have read the message above. ")
     
Index: /pykota/trunk/docs/filterpykota.sgml
===================================================================
--- /pykota/trunk/docs/filterpykota.sgml (revision 1386)
+++ /pykota/trunk/docs/filterpykota.sgml (revision 1475)
@@ -72,5 +72,5 @@
   
   <para>
-    When using the <literal>querying</literal> accounting method,
+    When using the <literal>hardware</literal> accounting method,
     <application>pykota</application> asks the printer for its internal page counter, reads from the Quota DataBase the internal
     page counter for this printer when the previous job was launched, computes the difference, and report it as the 
@@ -86,5 +86,5 @@
   
   <para>
-    When using the <literal>external</literal> accounting method,
+    When using the <literal>software</literal> accounting method,
     and if the user is still allowed to print,
     the command you specified is launched with the job's data on its 
@@ -92,5 +92,5 @@
     pages on a single line on its standard output. This number is then
     read by PyKota and used to update the current user's quota information.
-    Of course checks are also done like with the <literal>querying</literal>
+    Of course checks are also done like with the <literal>hardware</literal>
     accounting method, to see if the current job is allowed to be printed or not.
   </para>
@@ -108,4 +108,7 @@
 
 $Log$
+Revision 1.10  2004/05/13 13:59:28  jalet
+Code simplifications
+
 Revision 1.9  2004/03/03 19:35:36  jalet
 Spelling problem. Thanks to Jurandy Martins
Index: /pykota/trunk/README
===================================================================
--- /pykota/trunk/README (revision 1408)
+++ /pykota/trunk/README (revision 1475)
@@ -43,5 +43,5 @@
         
         - Supports OpenLDAP as the Quota Storage backend.
-          Complete LDAP schema and sample tree are included.
+          Complete LDAP schema and sample empty tree are included.
           Plugging PyKota into your existing LDAP infrastructure
           is really easy thanks to PyKota's great configurability.
@@ -49,16 +49,18 @@
     Printers :        
     
+        - Hardware or Software accounting methods are completely
+          configurable.
+          
         - Supports any printer which can report its internal
-          page counter.
+          page counter. Can ask printers for their internal 
+          page counter via SNMP, Netatalk, or any other way.
+          This is completely configurable.
+          
+        - Supports PostScript and PCL5 printers natively,
+          more formats to come.
           
         - Supports any other printer via GhostScript.
           Depending on the printer some configuration may
           be needed.
-        
-        - Can ask printers for their internal page counter
-          via SNMP, Netatalk, or any other mean of your
-          choice. This is completely configurable.
-          
-        - External accounting methods are configurable.
             
     Quota systems :        
@@ -156,5 +158,5 @@
 implemented :
 
-  - The 'querying' method consists in querying the printer (via SNMP
+  - The 'hardware' method consists in querying the printer (via SNMP
     or Netatalk or any other method of your choice) for its total pages 
     counter.
@@ -168,5 +170,5 @@
     of one print job, but this is generally ok.
     
-  - The 'external' method consists in delegating the computation of the
+  - The 'software' method consists in delegating the computation of the
     job's size in number of pages to any external command of your choice.
     The command can read the job's data from its standard input and MUST
@@ -174,11 +176,4 @@
     account are reported immediately, both with CUPS and LPRng.
     
-  - The 'stupid' method consists in counting the 'showpage' PostSript  
-    statements in the job. THIS IS UNRELIABLE, SO DON'T USE IT, but 
-    can serve as an example if you plan to write your own accounting 
-    method for integration into PyKota. It basically works like the 
-    'external' method, but does the computation internally and in
-    a non-reliable way.
-  
 PyKota is known to work fine with HP Laserjet 2100 and 2200, and 
 Apple LaserWriter 16/600 PS, both with CUPS and LPRng, under 
Index: /pykota/trunk/pykota/requesters/Makefile.am
===================================================================
--- /pykota/trunk/pykota/requesters/Makefile.am (revision 1417)
+++ /pykota/trunk/pykota/requesters/Makefile.am (revision 1475)
@@ -3,5 +3,4 @@
 pykota_requesters_PYTHON = 	\
 	external.py				\
-	__init__.py				\
-	snmp.py
+	__init__.py
 
Index: /pykota/trunk/pykota/requesters/external.py
===================================================================
--- /pykota/trunk/pykota/requesters/external.py (revision 1433)
+++ /pykota/trunk/pykota/requesters/external.py (revision 1475)
@@ -22,4 +22,7 @@
 #
 # $Log$
+# Revision 1.12  2004/05/13 13:59:30  jalet
+# Code simplifications
+#
 # Revision 1.11  2004/04/09 22:24:47  jalet
 # Began work on correct handling of child processes when jobs are cancelled by
@@ -63,5 +66,8 @@
 #
 
+import sys
 import os
+import popen2
+import signal
 from pykota.requester import PyKotaRequesterError
 
@@ -82,10 +88,27 @@
         if printer is None :
             raise PyKotaRequesterError, _("Unknown printer address in EXTERNAL(%s) for printer %s") % (commandline, self.printername)
-        answer = os.popen(commandline)
+        error = 1
+        pagecounter = None
+        child = popen2.Popen4(commandline)    
         try :
-            pagecounter = int(answer.readline().strip())
+            pagecounter = int(child.fromchild.readline().strip())
         except ValueError :    
+            pass
+        except IOError :    
+            # we were interrupted by a signal, certainely a SIGTERM
+            # caused by the user cancelling the current job
+            try :
+                os.kill(child.pid, signal.SIGTERM)
+            except :    
+                pass # already killed ?
+            self.kotabackend.logger.log_message(_("SIGTERM was sent to external requester %s (pid: %s)") % (commandline, child.pid), "info")
+        else :    
+            error = 0
+        child.fromchild.close()    
+        child.tochild.close()
+        status = child.wait()
+        if (not error) and os.WIFEXITED(status) and (not os.WEXITSTATUS(status)) :
+            return pagecounter
+        else :    
             raise PyKotaRequesterError, _("Unable to query printer %s via EXTERNAL(%s)") % (printer, commandline) 
-        answer.close()
-        return pagecounter
         
Index: /kota/trunk/pykota/requesters/snmp.py
===================================================================
--- /pykota/trunk/pykota/requesters/snmp.py (revision 1433)
+++  (revision )
@@ -1,105 +1,0 @@
-# PyKota
-# -*- coding: ISO-8859-15 -*-
-#
-# PyKota - Print Quotas for CUPS and LPRng
-#
-# (c) 2003-2004 Jerome Alet <alet@librelogiciel.com>
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-# 
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
-#
-# $Id$
-#
-# $Log$
-# Revision 1.14  2004/04/09 22:24:47  jalet
-# Began work on correct handling of child processes when jobs are cancelled by
-# the user. Especially important when an external requester is running for a
-# long time.
-#
-# Revision 1.13  2004/01/08 14:10:33  jalet
-# Copyright year changed.
-#
-# Revision 1.12  2003/10/07 09:07:29  jalet
-# Character encoding added to please latest version of Python
-#
-# Revision 1.11  2003/07/07 11:49:24  jalet
-# Lots of small fixes with the help of PyChecker
-#
-# Revision 1.10  2003/05/22 12:56:06  jalet
-# Uses SNMP version 1 instead of version 2c by default, which is probably
-# a safer bet.
-#
-# Revision 1.9  2003/05/21 10:07:09  jalet
-# Now works with net-snmp v5.0 and above.
-# (It already worked, but the sample configuration file didn't contain
-# appropriate values)
-#
-# Revision 1.8  2003/04/23 22:13:57  jalet
-# Preliminary support for LPRng added BUT STILL UNTESTED.
-#
-# Revision 1.7  2003/03/29 13:45:27  jalet
-# GPL paragraphs were incorrectly (from memory) copied into the sources.
-# Two README files were added.
-# Upgrade script for PostgreSQL pre 1.01 schema was added.
-#
-# Revision 1.6  2003/02/10 11:47:39  jalet
-# Moved some code down into the requesters
-#
-# Revision 1.5  2003/02/10 00:42:17  jalet
-# External requester should be ok (untested)
-# New syntax for configuration file wrt requesters
-#
-# Revision 1.4  2003/02/09 13:05:43  jalet
-# Internationalization continues...
-#
-# Revision 1.3  2003/02/07 13:12:41  jalet
-# Bad old comment
-#
-# Revision 1.2  2003/02/05 23:00:12  jalet
-# Forgotten import
-# Bad datetime conversion
-#
-# Revision 1.1  2003/02/05 21:28:17  jalet
-# Initial import into CVS
-#
-#
-#
-
-import os
-from pykota.requester import PyKotaRequesterError
-
-class Requester :
-    """A class to send queries to printers via SNMP."""
-    def __init__(self, kotabackend, printername, arguments) :
-        """Sets instance vars depending on the current printer."""
-        self.kotabackend = kotabackend
-        self.printername = printername
-        args = [x.strip() for x in arguments.split(',')]
-        self.community = args[0]
-        self.oid = args[1]
-        
-    def getPrinterPageCounter(self, hostname) :
-        """Returns the page counter from the hostname printer via SNMP.
-        
-           Currently uses the snmpget external command. TODO : do it internally 
-        """
-        if hostname is None :
-            raise PyKotaRequesterError, _("Unknown printer address in SNMP(%s, %s) for printer %s") % (self.community, self.oid, self.printername)
-        answer = os.popen("snmpget -v1 -c %s -Ov %s %s" % (self.community, hostname, self.oid))
-        try :
-            pagecounter = int(answer.readline().split()[-1].strip())
-        except IndexError :    
-            raise PyKotaRequesterError, _("Unable to query printer %s via SNMP(%s, %s)") % (hostname, self.community, self.oid) 
-        answer.close()
-        return pagecounter
-    
Index: /pykota/trunk/pykota/tool.py
===================================================================
--- /pykota/trunk/pykota/tool.py (revision 1469)
+++ /pykota/trunk/pykota/tool.py (revision 1475)
@@ -22,4 +22,7 @@
 #
 # $Log$
+# Revision 1.86  2004/05/13 13:59:28  jalet
+# Code simplifications
+#
 # Revision 1.85  2004/05/11 08:26:27  jalet
 # Now catches connection problems to SMTP server
@@ -809,5 +812,5 @@
             
     def prehook(self, userpquota) :
-        """Allows pluging of an external hook before the job gets printed."""
+        """Allows plugging of an external hook before the job gets printed."""
         prehook = self.config.getPreHook(userpquota.Printer.Name)
         if prehook :
@@ -816,5 +819,5 @@
         
     def posthook(self, userpquota) :
-        """Allows pluging of an external hook after the job gets printed and/or denied."""
+        """Allows plugging of an external hook after the job gets printed and/or denied."""
         posthook = self.config.getPostHook(userpquota.Printer.Name)
         if posthook :
Index: /pykota/trunk/pykota/accounters/software.py
===================================================================
--- /pykota/trunk/pykota/accounters/software.py (revision 1475)
+++ /pykota/trunk/pykota/accounters/software.py (revision 1475)
@@ -0,0 +1,102 @@
+# PyKota
+# -*- coding: ISO-8859-15 -*-
+#
+# PyKota - Print Quotas for CUPS and LPRng
+#
+# (c) 2003-2004 Jerome Alet <alet@librelogiciel.com>
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+#
+# $Id$
+#
+# $Log$
+# Revision 1.1  2004/05/13 13:59:30  jalet
+# Code simplifications
+#
+#
+#
+
+import sys
+import os
+import popen2
+import tempfile
+from pykota.accounter import AccounterBase, PyKotaAccounterError
+
+class Accounter(AccounterBase) :
+    def computeJobSize(self) :    
+        """Feeds an external command with our datas to let it compute the job size, and return its value."""
+        temporary = None    
+        if self.filter.inputfile is None :    
+            infile = sys.stdin
+            # we will have to duplicate our standard input
+            temporary = tempfile.TemporaryFile()
+        else :    
+            infile = open(self.filter.inputfile, "rb")
+            
+        # launches external accounter
+        # TODO : USE tempfile.mkstemp() instead ! Needs some work !
+        infilename = tempfile.mktemp()
+        outfilename = tempfile.mktemp()
+        errfilename = tempfile.mktemp()
+        
+        try :
+            # feed it with our data
+            fakeinput = open(infilename, "wb")
+            data = infile.read(256*1024)    
+            while data :
+                fakeinput.write(data)
+                if temporary is not None :
+                    temporary.write(data)
+                data = infile.read(256*1024)
+            fakeinput.close()
+        
+            # launches child process
+            command = "%s <%s >%s 2>%s" % (self.arguments, infilename, outfilename, errfilename)
+            retcode = os.system(command)
+            
+            # check exit status
+            if (os.WIFEXITED(retcode) and not os.WEXITSTATUS(retcode)) or os.stat(errfilename) :
+                # tries to extract the job size from the external accounter's
+                # standard output
+                childoutput = open(outfilename, "r")
+                try :
+                    pagecount = int(childoutput.readline().strip())
+                except (AttributeError, ValueError) :
+                    self.filter.logger.log_message(_("Unable to compute job size with external accounter %s") % self.arguments)
+                    pagecount = 0
+                childoutput.close()    
+            else :
+                self.filter.logger.log_message(_("Unable to compute job size with external accounter %s") % self.arguments)
+                pagecount = 0
+            os.remove(infilename)
+            os.remove(outfilename)
+            os.remove(errfilename)
+        except IOError, msg :    
+            # TODO : temporary files may remain on the filesystem...
+            msg = "%s : %s" % (self.arguments, msg) 
+            self.filter.logger.log_message(_("Unable to compute job size with external accounter %s") % msg)
+            pagecount = 0
+            
+        if temporary is not None :    
+            # this is a copy of our previous standard input
+            # flush, then rewind
+            temporary.flush()
+            temporary.seek(0, 0)
+            # our temporary file will be used later if the
+            # job is allowed.
+            self.filter.inputfile = temporary
+        else :
+            infile.close()
+        return pagecount    
+            
Index: /pykota/trunk/pykota/accounters/hardware.py
===================================================================
--- /pykota/trunk/pykota/accounters/hardware.py (revision 1475)
+++ /pykota/trunk/pykota/accounters/hardware.py (revision 1475)
@@ -0,0 +1,99 @@
+# PyKota
+# -*- coding: ISO-8859-15 -*-
+#
+# PyKota - Print Quotas for CUPS and LPRng
+#
+# (c) 2003-2004 Jerome Alet <alet@librelogiciel.com>
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+#
+# $Id$
+#
+# $Log$
+# Revision 1.1  2004/05/13 13:59:30  jalet
+# Code simplifications
+#
+#
+#
+
+import sys
+import os
+from pykota.accounter import AccounterBase, PyKotaAccounterError
+from pykota.requester import openRequester, PyKotaRequesterError
+
+class Accounter(AccounterBase) :
+    def __init__(self, kotabackend, arguments) :
+        """Initializes querying accounter."""
+        AccounterBase.__init__(self, kotabackend, arguments)
+        self.requester = openRequester(kotabackend, kotabackend.printername)
+        self.isDelayed = 1 # With the pykota filter, accounting is delayed by one job
+        
+    def getPrinterInternalPageCounter(self) :    
+        """Returns the printer's internal page counter."""
+        self.filter.logdebug("Reading printer's internal page counter...")
+        try :
+            counter = self.requester.getPrinterPageCounter(self.filter.printerhostname)
+        except PyKotaRequesterError, msg :
+            # can't get actual page counter, assume printer is off or warming up
+            # log the message anyway.
+            self.filter.logger.log_message("%s" % msg, "warn")
+            counter = None
+        self.filter.logdebug("Printer's internal page counter value is : %s" % str(counter))
+        return counter    
+        
+    def beginJob(self, userpquota) :    
+        """Saves printer internal page counter at start of job."""
+        # save page counter before job
+        self.LastPageCounter = self.counterbefore = self.getPrinterInternalPageCounter()
+        
+    def endJob(self, userpquota) :    
+        """Saves printer internal page counter at end of job."""
+        # save page counter after job
+        self.LastPageCounter = self.counterafter = self.getPrinterInternalPageCounter()
+        
+    def getJobSize(self) :    
+        """Returns the actual job size."""
+        try :
+            jobsize = (self.counterafter - self.counterbefore)    
+            if jobsize < 0 :
+                # Try to take care of HP printers 
+                # Their internal page counter is saved to NVRAM
+                # only every 10 pages. If the printer was switched
+                # off then back on during the job, and that the
+                # counters difference is negative, we know 
+                # the formula (we can't know if more than eleven
+                # pages were printed though) :
+                if jobsize > -10 :
+                    jobsize += 10
+                else :    
+                    # here we may have got a printer being replaced
+                    # DURING the job. This is HIGHLY improbable !
+                    jobsize = 0
+        except :    
+            # takes care of the case where one counter (or both) was never set.
+            jobsize = 0
+        return jobsize
+        
+    def doAccounting(self, userpquota) :
+        """Does print accounting and returns if the job status is ALLOW or DENY."""
+        # Get the page counter directly from the printer itself
+        counterbeforejob = self.getPrinterInternalPageCounter() or 0
+        
+        # Is the current user allowed to print at all ?
+        action = self.filter.warnUserPQuota(userpquota)
+        
+        # adds the current job to history    
+        userpquota.Printer.addJobToHistory(self.filter.jobid, userpquota.User, counterbeforejob, action, filename=self.filter.preserveinputfile, title=self.filter.title, copies=self.filter.copies, options=self.filter.options)
+        return action
+            
Index: /pykota/trunk/pykota/accounters/Makefile.am
===================================================================
--- /pykota/trunk/pykota/accounters/Makefile.am (revision 1417)
+++ /pykota/trunk/pykota/accounters/Makefile.am (revision 1475)
@@ -2,7 +2,6 @@
 
 pykota_accounters_PYTHON = 	\
-	external.py				\
+	software.py				\
 	__init__.py				\
-	querying.py				\
-	stupid.py				
+	hardware.py
 
Index: /kota/trunk/pykota/accounters/stupid.py
===================================================================
--- /pykota/trunk/pykota/accounters/stupid.py (revision 1257)
+++  (revision )
@@ -1,95 +1,0 @@
-# PyKota
-# -*- coding: ISO-8859-15 -*-
-#
-# PyKota - Print Quotas for CUPS and LPRng
-#
-# (c) 2003-2004 Jerome Alet <alet@librelogiciel.com>
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-# 
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
-#
-# $Id$
-#
-# $Log$
-# Revision 1.11  2004/01/08 14:10:32  jalet
-# Copyright year changed.
-#
-# Revision 1.10  2003/12/27 16:49:25  uid67467
-# Should be ok now.
-#
-# Revision 1.8  2003/11/23 19:01:37  jalet
-# Job price added to history
-#
-# Revision 1.7  2003/11/21 14:28:46  jalet
-# More complete job history.
-#
-# Revision 1.6  2003/11/12 23:29:24  jalet
-# More work on new backend. This commit may be unstable.
-#
-# Revision 1.5  2003/10/07 09:07:29  jalet
-# Character encoding added to please latest version of Python
-#
-# Revision 1.4  2003/06/25 14:10:01  jalet
-# Hey, it may work (edpykota --reset excepted) !
-#
-# Revision 1.3  2003/05/27 23:00:21  jalet
-# Big rewrite of external accounting methods.
-# Should work well now.
-#
-# Revision 1.2  2003/04/30 13:40:47  jalet
-# Small fix
-#
-# Revision 1.1  2003/04/30 13:36:40  jalet
-# Stupid accounting method was added.
-#
-#
-#
-
-import sys
-import tempfile
-from pykota.accounter import AccounterBase, PyKotaAccounterError
-
-class Accounter(AccounterBase) :
-    def computeJobSize(self) :    
-        """Computes the job size and return its value.
-        
-           THIS METHOD IS COMPLETELY UNRELIABLE BUT SERVES AS AN EXAMPLE.
-        """
-        # first we log a message because using this accounting method is not recommended.
-        self.filter.logger.log_message(_("Using the 'stupid' accounting method is unreliable."), "warn")
-        
-        temporary = None    
-        if self.filter.inputfile is None :    
-            infile = sys.stdin
-            # we will have to duplicate our standard input
-            temporary = tempfile.TemporaryFile()
-        else :    
-            infile = open(self.filter.inputfile, "rb")
-            
-        pagecount = 0
-        for line in infile.xreadlines() :
-            pagecount += line.count("showpage")
-            if temporary is not None :    
-                temporary.write(line)    
-                
-        if temporary is not None :    
-            # this is a copy of our previous standard input
-            # flush, then rewind
-            temporary.flush()
-            temporary.seek(0, 0)
-            # our temporary file will be used later if the
-            # job is allowed.
-            self.filter.inputfile = temporary
-        else :
-            infile.close()
-        return pagecount    
Index: /kota/trunk/pykota/accounters/external.py
===================================================================
--- /pykota/trunk/pykota/accounters/external.py (revision 1257)
+++  (revision )
@@ -1,136 +1,0 @@
-# PyKota
-# -*- coding: ISO-8859-15 -*-
-#
-# PyKota - Print Quotas for CUPS and LPRng
-#
-# (c) 2003-2004 Jerome Alet <alet@librelogiciel.com>
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-# 
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
-#
-# $Id$
-#
-# $Log$
-# Revision 1.13  2004/01/08 14:10:32  jalet
-# Copyright year changed.
-#
-# Revision 1.12  2003/12/27 16:49:25  uid67467
-# Should be ok now.
-#
-# Revision 1.10  2003/11/23 19:01:36  jalet
-# Job price added to history
-#
-# Revision 1.9  2003/11/21 14:28:45  jalet
-# More complete job history.
-#
-# Revision 1.8  2003/11/12 23:29:24  jalet
-# More work on new backend. This commit may be unstable.
-#
-# Revision 1.7  2003/10/07 09:07:28  jalet
-# Character encoding added to please latest version of Python
-#
-# Revision 1.6  2003/09/04 07:57:18  jalet
-# Problem with Python 2.3 fixed : a bug of me.
-#
-# Revision 1.5  2003/07/07 11:49:24  jalet
-# Lots of small fixes with the help of PyChecker
-#
-# Revision 1.4  2003/06/25 14:10:01  jalet
-# Hey, it may work (edpykota --reset excepted) !
-#
-# Revision 1.3  2003/05/27 23:00:21  jalet
-# Big rewrite of external accounting methods.
-# Should work well now.
-#
-# Revision 1.2  2003/05/13 13:54:20  jalet
-# Better handling of broken pipes
-#
-# Revision 1.1  2003/05/07 19:47:06  jalet
-# v1.07 Release of the Shame is out !
-#
-#
-#
-
-import sys
-import os
-import popen2
-import tempfile
-from pykota.accounter import AccounterBase, PyKotaAccounterError
-
-class Accounter(AccounterBase) :
-    def computeJobSize(self) :    
-        """Feeds an external command with our datas to let it compute the job size, and return its value."""
-        temporary = None    
-        if self.filter.inputfile is None :    
-            infile = sys.stdin
-            # we will have to duplicate our standard input
-            temporary = tempfile.TemporaryFile()
-        else :    
-            infile = open(self.filter.inputfile, "rb")
-            
-        # launches external accounter
-        # TODO : USE tempfile.mkstemp() instead ! Needs some work !
-        infilename = tempfile.mktemp()
-        outfilename = tempfile.mktemp()
-        errfilename = tempfile.mktemp()
-        
-        try :
-            # feed it with our data
-            fakeinput = open(infilename, "wb")
-            data = infile.read(256*1024)    
-            while data :
-                fakeinput.write(data)
-                if temporary is not None :
-                    temporary.write(data)
-                data = infile.read(256*1024)
-            fakeinput.close()
-        
-            # launches child process
-            command = "%s <%s >%s 2>%s" % (self.arguments, infilename, outfilename, errfilename)
-            retcode = os.system(command)
-            
-            # check exit status
-            if (os.WIFEXITED(retcode) and not os.WEXITSTATUS(retcode)) or os.stat(errfilename) :
-                # tries to extract the job size from the external accounter's
-                # standard output
-                childoutput = open(outfilename, "r")
-                try :
-                    pagecount = int(childoutput.readline().strip())
-                except (AttributeError, ValueError) :
-                    self.filter.logger.log_message(_("Unable to compute job size with external accounter %s") % self.arguments)
-                    pagecount = 0
-                childoutput.close()    
-            else :
-                self.filter.logger.log_message(_("Unable to compute job size with external accounter %s") % self.arguments)
-                pagecount = 0
-            os.remove(infilename)
-            os.remove(outfilename)
-            os.remove(errfilename)
-        except IOError, msg :    
-            # TODO : temporary files may remain on the filesystem...
-            msg = "%s : %s" % (self.arguments, msg) 
-            self.filter.logger.log_message(_("Unable to compute job size with external accounter %s") % msg)
-            pagecount = 0
-            
-        if temporary is not None :    
-            # this is a copy of our previous standard input
-            # flush, then rewind
-            temporary.flush()
-            temporary.seek(0, 0)
-            # our temporary file will be used later if the
-            # job is allowed.
-            self.filter.inputfile = temporary
-        else :
-            infile.close()
-        return pagecount    
-            
Index: /kota/trunk/pykota/accounters/querying.py
===================================================================
--- /pykota/trunk/pykota/accounters/querying.py (revision 1433)
+++  (revision )
@@ -1,145 +1,0 @@
-# PyKota
-# -*- coding: ISO-8859-15 -*-
-#
-# PyKota - Print Quotas for CUPS and LPRng
-#
-# (c) 2003-2004 Jerome Alet <alet@librelogiciel.com>
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-# 
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
-#
-# $Id$
-#
-# $Log$
-# Revision 1.13  2004/04/09 22:24:47  jalet
-# Began work on correct handling of child processes when jobs are cancelled by
-# the user. Especially important when an external requester is running for a
-# long time.
-#
-# Revision 1.12  2004/01/11 23:22:42  jalet
-# Major code refactoring, it's way cleaner, and now allows automated addition
-# of printers on first print.
-#
-# Revision 1.11  2004/01/08 14:10:32  jalet
-# Copyright year changed.
-#
-# Revision 1.10  2003/12/27 16:49:25  uid67467
-# Should be ok now.
-#
-# Revision 1.8  2003/11/21 14:28:46  jalet
-# More complete job history.
-#
-# Revision 1.7  2003/11/12 23:29:24  jalet
-# More work on new backend. This commit may be unstable.
-#
-# Revision 1.6  2003/10/07 09:07:29  jalet
-# Character encoding added to please latest version of Python
-#
-# Revision 1.5  2003/07/07 11:49:24  jalet
-# Lots of small fixes with the help of PyChecker
-#
-# Revision 1.4  2003/06/25 14:10:01  jalet
-# Hey, it may work (edpykota --reset excepted) !
-#
-# Revision 1.3  2003/05/06 14:55:47  jalet
-# Missing import !
-#
-# Revision 1.2  2003/04/30 13:36:40  jalet
-# Stupid accounting method was added.
-#
-# Revision 1.1  2003/04/29 18:37:54  jalet
-# Pluggable accounting methods (actually doesn't support external scripts)
-#
-#
-#
-
-import sys
-import os
-import time
-from pykota.accounter import AccounterBase, PyKotaAccounterError
-from pykota.requester import openRequester, PyKotaRequesterError
-
-MAXTRIES = 12    # maximum number of tries to get the printer's internal page counter
-TIMETOSLEEP = 10 # number of seconds to sleep between two tries to get the printer's internal page counter
-
-class Accounter(AccounterBase) :
-    def __init__(self, kotabackend, arguments) :
-        """Initializes querying accounter."""
-        AccounterBase.__init__(self, kotabackend, arguments)
-        self.requester = openRequester(kotabackend, kotabackend.printername)
-        self.isDelayed = 1 # With the pykota filter, accounting is delayed by one job
-        
-    def getPrinterInternalPageCounter(self) :    
-        """Returns the printer's internal page counter."""
-        global MAXTRIES, TIMETOSLEEP
-        self.filter.logdebug("Reading printer's internal page counter...")
-        for dummy in range(MAXTRIES) :
-            try :
-                counter = self.requester.getPrinterPageCounter(self.filter.printerhostname)
-            except PyKotaRequesterError, msg :
-                # can't get actual page counter, assume printer is off or warming up
-                # log the message anyway.
-                self.filter.logger.log_message("%s" % msg, "warn")
-                counter = None
-            else :    
-                # printer answered, it is on so we can exit the loop
-                break
-            time.sleep(TIMETOSLEEP)    
-        self.filter.logdebug("Printer's internal page counter value is : %s" % str(counter))
-        return counter    
-        
-    def beginJob(self, userpquota) :    
-        """Saves printer internal page counter at start of job."""
-        # save page counter before job
-        self.LastPageCounter = self.counterbefore = self.getPrinterInternalPageCounter()
-        
-    def endJob(self, userpquota) :    
-        """Saves printer internal page counter at end of job."""
-        # save page counter after job
-        self.LastPageCounter = self.counterafter = self.getPrinterInternalPageCounter()
-        
-    def getJobSize(self) :    
-        """Returns the actual job size."""
-        try :
-            jobsize = (self.counterafter - self.counterbefore)    
-            if jobsize < 0 :
-                # Try to take care of HP printers 
-                # Their internal page counter is saved to NVRAM
-                # only every 10 pages. If the printer was switched
-                # off then back on during the job, and that the
-                # counters difference is negative, we know 
-                # the formula (we can't know if more than eleven
-                # pages were printed though) :
-                if jobsize > -10 :
-                    jobsize += 10
-                else :    
-                    # here we may have got a printer being replaced
-                    # DURING the job. This is HIGHLY improbable !
-                    jobsize = 0
-        except :    
-            # takes care of the case where one counter (or both) was never set.
-            jobsize = 0
-        return jobsize
-        
-    def doAccounting(self, userpquota) :
-        """Does print accounting and returns if the job status is ALLOW or DENY."""
-        # Get the page counter directly from the printer itself
-        counterbeforejob = self.getPrinterInternalPageCounter() or 0
-        
-        # Is the current user allowed to print at all ?
-        action = self.filter.warnUserPQuota(userpquota)
-        
-        # adds the current job to history    
-        userpquota.Printer.addJobToHistory(self.filter.jobid, userpquota.User, counterbeforejob, action, filename=self.filter.preserveinputfile, title=self.filter.title, copies=self.filter.copies, options=self.filter.options)
-        return action
-            
Index: /pykota/trunk/pykota/config.py
===================================================================
--- /pykota/trunk/pykota/config.py (revision 1371)
+++ /pykota/trunk/pykota/config.py (revision 1475)
@@ -22,4 +22,7 @@
 #
 # $Log$
+# Revision 1.46  2004/05/13 13:59:28  jalet
+# Code simplifications
+#
 # Revision 1.45  2004/03/01 10:22:30  jalet
 # Can now extract per printer pre and post hooks from the configuration file
@@ -303,10 +306,10 @@
         """Returns the accounter backend to use for a given printer.
         
-           if it is not set, it defaults to 'querying' which means ask printer
+           if it is not set, it defaults to 'hardware' which means ask printer
            for its internal lifetime page counter.
         """   
-        validaccounters = [ "querying", "stupid", "external" ]     
+        validaccounters = [ "hardware", "software" ]     
         fullaccounter = self.getPrinterOption(printername, "accounter").strip()
-        if fullaccounter.lower().startswith("external") :    
+        if fullaccounter.lower().startswith("software") :    
             try :
                 (accounter, args) = [x.strip() for x in fullaccounter.split('(', 1)]
@@ -343,6 +346,6 @@
         except PyKotaConfigError :    
             # No requester defined, maybe it is not needed if accounting method
-            # is not set to 'querying', but if we are called, then the accounting
-            # method really IS 'querying', and so there's a big problem.
+            # is not set to 'hardware', but if we are called, then the accounting
+            # method really IS 'hardware', and so there's a big problem.
             raise PyKotaConfigError, _("Option requester for printer %s was not set") % printername
         else :    
@@ -355,5 +358,5 @@
             if not args :
                 raise PyKotaConfigError, _("Invalid requester %s for printer %s") % (fullrequester, printername)
-            validrequesters = [ "snmp", "external" ] # TODO : add more requesters
+            validrequesters = [ "external" ] 
             requester = requester.lower()
             if requester not in validrequesters :
Index: /pykota/trunk/pykota/version.py
===================================================================
--- /pykota/trunk/pykota/version.py (revision 1473)
+++ /pykota/trunk/pykota/version.py (revision 1475)
@@ -22,5 +22,5 @@
 #
 
-__version__ = "1.19alpha7_unofficial"
+__version__ = "1.19alpha8_unofficial"
 
 __doc__ = """PyKota : a complete Printing Quota Solution for CUPS and LPRng."""
Index: /pykota/trunk/bin/pkhint
===================================================================
--- /pykota/trunk/bin/pkhint (revision 1423)
+++ /pykota/trunk/bin/pkhint (revision 1475)
@@ -24,4 +24,7 @@
 #
 # $Log$
+# Revision 1.7  2004/05/13 13:59:27  jalet
+# Code simplifications
+#
 # Revision 1.6  2004/03/30 12:59:47  jalet
 # Fixed path problem
@@ -211,5 +214,5 @@
                     snmpcommand = self.accepts(SNMPTESTS, hostname)
                     if snmpcommand is not None :
-                        accounter = "querying"
+                        accounter = "hardware"
                         requester = 'external(/usr/share/pykota/waitprinter.sh %(printer)s && ' + snmpcommand + ')'
                         configuration.append((printer, accounter, requester))
@@ -217,5 +220,5 @@
                         netpjlcommand = self.accepts(NETPJLTESTS, hostname, port)
                         if netpjlcommand is not None :
-                            accounter = "querying"
+                            accounter = "hardware"
                             requester = 'external(' + netpjlcommand + ')'
                             configuration.append((printer, accounter, requester))
Index: /pykota/trunk/NEWS
===================================================================
--- /pykota/trunk/NEWS (revision 1473)
+++ /pykota/trunk/NEWS (revision 1475)
@@ -22,4 +22,16 @@
 PyKota NEWS :
 
+    - 1.19alpha8 :
+    
+        - 'querying' accounting method is now called 'hardware'
+        
+        - 'external' accounting method is now called 'software'
+        
+        - 'stupid' accounting method doesn't exist anymore
+        
+        - 'snmp' requester doesn't exist anymore
+        
+        - code simplifications in external requester
+        
     - 1.19alpha7 :
      
