Index: /pykota/trunk/conf/pykota.conf.sample
===================================================================
--- /pykota/trunk/conf/pykota.conf.sample (revision 974)
+++ /pykota/trunk/conf/pykota.conf.sample (revision 976)
@@ -58,8 +58,20 @@
 #
 #    - querying : 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.
+#
+#    - stupid : counts the occurences of the 'showpage' postscript
+#               statement in the document to be printed, only at
+#               the beginning of each line which makes the postscript
+#               file. THIS IS NOT RELIABLE. This is just to serve as
+#               an example on how to implement your own accounting
+#               method.
+#
 #    - more to be added in the future
 #
 # This value can be set either globally or on a per printer basis
-# if not set it defaults to 'querying'
+# If both are defined, the printer option has priority.
+# if not set it defaults to 'querying'.
 accounter: querying
 
Index: /pykota/trunk/pykota/accounters/stupid.py
===================================================================
--- /pykota/trunk/pykota/accounters/stupid.py (revision 976)
+++ /pykota/trunk/pykota/accounters/stupid.py (revision 976)
@@ -0,0 +1,102 @@
+# PyKota
+#
+# PyKota - Print Quotas for CUPS and LPRng
+#
+# (c) 2003 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  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 doAccounting(self, printerid, userid) :
+        """Does print accounting by stupidly counting the 'showpage' postscript instructions in the document.
+        
+           This method is essentially unreliable, but shows how to create a simple accounter.
+        """
+        # 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")
+        
+        # get the job size    
+        jobsize = self.getJobSize()
+            
+        # get last job information for this printer
+        pgc = self.filter.storage.getPrinterPageCounter(printerid)    
+        if pgc is None :
+            # The printer hasn't been used yet, from PyKota's point of view
+            counterbeforejob = 0
+        else :    
+            # get last job size and page counter from Quota Storage
+            # Last lifetime page counter before actual job is 
+            # last page counter + last job size
+            counterbeforejob = pgc["pagecounter"] + pgc["jobsize"]
+            
+        # Is the current user allowed to print at all ?
+        action = self.filter.warnUserPQuota(self.filter.username, self.filter.printername)
+        
+        # update the quota for the current user on this printer, if allowed to print
+        if action == "DENY" :
+            jobsize = 0
+        else :    
+            self.filter.storage.updateUserPQuota(userid, printerid, jobsize)
+        
+        # adds the current job to history    
+        self.filter.storage.addJobToHistory(self.filter.jobid, self.filter.storage.getUserId(self.filter.username), printerid, counterbeforejob, action, jobsize)
+            
+        return action
+        
+    def getJobSize(self) :    
+        """Computes the job size and return its value.
+        
+           THIS METHOD IS COMPLETELY UNRELIABLE BUT SERVES AS AN EXAMPLE.
+        """
+        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() :
+            if line.startswith("showpage") :
+                pagecount += 1
+            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: /pykota/trunk/pykota/accounters/querying.py
===================================================================
--- /pykota/trunk/pykota/accounters/querying.py (revision 973)
+++ /pykota/trunk/pykota/accounters/querying.py (revision 976)
@@ -21,4 +21,7 @@
 #
 # $Log$
+# 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)
@@ -27,4 +30,5 @@
 #
 
+import sys
 from pykota.accounter import AccounterBase, PyKotaAccounterError
 from pykota.requester import openRequester, PyKotaRequesterError
@@ -118,2 +122,3 @@
             
         return action
+            
Index: /pykota/trunk/pykota/storages/sql.py
===================================================================
--- /pykota/trunk/pykota/storages/sql.py (revision 967)
+++ /pykota/trunk/pykota/storages/sql.py (revision 976)
@@ -21,4 +21,7 @@
 #
 # $Log$
+# Revision 1.31  2003/04/30 13:36:40  jalet
+# Stupid accounting method was added.
+#
 # Revision 1.30  2003/04/27 08:04:15  jalet
 # LDAP storage backend's skeleton added. DOESN'T WORK.
@@ -368,7 +371,7 @@
         self.doQuery("UPDATE grouppquota SET datelimit=%s::TIMESTAMP WHERE groupid=%s AND printerid=%s" % (self.doQuote("%04i-%02i-%02i %02i:%02i:%02i" % (datelimit.year, datelimit.month, datelimit.day, datelimit.hour, datelimit.minute, datelimit.second)), self.doQuote(groupid), self.doQuote(printerid)))
         
-    def addJobToHistory(self, jobid, userid, printerid, pagecounter, action) :
+    def addJobToHistory(self, jobid, userid, printerid, pagecounter, action, jobsize=None) :
         """Adds a job to the history: (jobid, userid, printerid, last page counter taken from requester)."""
-        self.doQuery("INSERT INTO jobhistory (jobid, userid, printerid, pagecounter, action) VALUES (%s, %s, %s, %s, %s)" % (self.doQuote(jobid), self.doQuote(userid), self.doQuote(printerid), self.doQuote(pagecounter), self.doQuote(action)))
+        self.doQuery("INSERT INTO jobhistory (jobid, userid, printerid, pagecounter, action, jobsize) VALUES (%s, %s, %s, %s, %s, %s)" % (self.doQuote(jobid), self.doQuote(userid), self.doQuote(printerid), self.doQuote(pagecounter), self.doQuote(action), self.doQuote(jobsize)))
         return self.getJobHistoryId(jobid, userid, printerid) # in case jobid is not sufficient
     
@@ -379,5 +382,5 @@
     def getPrinterPageCounter(self, printerid) :
         """Returns the last page counter value for a printer given its id, also returns last username, last jobid and history line id."""
-        result = self.doQuery("SELECT jobhistory.id, jobid, userid, username, pagecounter FROM jobhistory, users WHERE printerid=%s AND userid=users.id ORDER BY jobdate DESC LIMIT 1" % self.doQuote(printerid))
+        result = self.doQuery("SELECT jobhistory.id, jobid, userid, username, pagecounter, jobsize FROM jobhistory, users WHERE printerid=%s AND userid=users.id ORDER BY jobdate DESC LIMIT 1" % self.doQuote(printerid))
         try :
             return self.doParseResult(result)[0]
Index: /pykota/trunk/pykota/storages/postgresql.py
===================================================================
--- /pykota/trunk/pykota/storages/postgresql.py (revision 967)
+++ /pykota/trunk/pykota/storages/postgresql.py (revision 976)
@@ -21,4 +21,7 @@
 #
 # $Log$
+# Revision 1.10  2003/04/30 13:36:40  jalet
+# Stupid accounting method was added.
+#
 # Revision 1.9  2003/04/27 08:04:15  jalet
 # LDAP storage backend's skeleton added. DOESN'T WORK.
@@ -111,5 +114,5 @@
     def doQuote(self, field) :
         """Quotes a field for use as a string in SQL queries."""
-        if type(field) == type(0) : # TODO : do something safer
+        if type(field) in (type(0), type(0.0)) : # TODO : do something safer
             typ = "decimal"
         else :    
Index: /pykota/trunk/pykota/accounter.py
===================================================================
--- /pykota/trunk/pykota/accounter.py (revision 973)
+++ /pykota/trunk/pykota/accounter.py (revision 976)
@@ -21,4 +21,7 @@
 #
 # $Log$
+# 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)
@@ -26,4 +29,6 @@
 #
 #
+
+import sys
 
 class PyKotaAccounterError(Exception):
@@ -42,4 +47,22 @@
         self.filter = kotafilter
         
+    def filterInput(self, inputfile) :
+        """Transparent filter."""
+        mustclose = 0    
+        if inputfile is not None :    
+            if hasattr(inputfile, "read") :
+                infile = inputfile
+            else :    
+                infile = open(inputfile, "rb")
+            mustclose = 1
+        else :    
+            infile = sys.stdin
+        data = infile.read(256*1024)    
+        while data :
+            sys.stdout.write(data)
+            data = infile.read(256*1024)
+        if mustclose :    
+            infile.close()
+            
     def doAccounting(self, printerid, userid) :    
         """Does the real accounting."""
Index: /pykota/trunk/pykota/config.py
===================================================================
--- /pykota/trunk/pykota/config.py (revision 973)
+++ /pykota/trunk/pykota/config.py (revision 976)
@@ -21,4 +21,7 @@
 #
 # $Log$
+# Revision 1.25  2003/04/30 13:36:40  jalet
+# Stupid accounting method was added.
+#
 # Revision 1.24  2003/04/29 18:37:54  jalet
 # Pluggable accounting methods (actually doesn't support external scripts)
@@ -197,5 +200,5 @@
            for its internal lifetime page counter.
         """   
-        validaccounters = [ "querying" ]     
+        validaccounters = [ "querying", "stupid" ]     
         try :
             accounter = self.getPrinterOption(printer, "accounter").lower()
Index: /pykota/trunk/pykota/version.py
===================================================================
--- /pykota/trunk/pykota/version.py (revision 973)
+++ /pykota/trunk/pykota/version.py (revision 976)
@@ -21,5 +21,5 @@
 #
 
-__version__ = "1.05alpha2-unofficial"
+__version__ = "1.05alpha3-unofficial"
 
 __doc__ = """PyKota : a complete Printing Quota Solution for CUPS and LPRng."""
Index: /pykota/trunk/bin/pykota
===================================================================
--- /pykota/trunk/bin/pykota (revision 975)
+++ /pykota/trunk/bin/pykota (revision 976)
@@ -23,4 +23,7 @@
 #
 # $Log$
+# Revision 1.31  2003/04/30 13:36:39  jalet
+# Stupid accounting method was added.
+#
 # Revision 1.30  2003/04/29 22:03:38  jalet
 # Better error handling.
@@ -192,19 +195,4 @@
         return (None, None, None, None, None, None)   # Unknown printing system          
         
-    def filterInput(self, inputfile) :
-        """Transparent filter."""
-        mustclose = 0    
-        if inputfile is not None :    
-            infile = open(inputfile, "rb")
-            mustclose = 1
-        else :    
-            infile = sys.stdin
-        data = infile.read(256*1024)    
-        while data :
-            sys.stdout.write(data)
-            data = infile.read(256*1024)
-        if mustclose :    
-            infile.close()
-            
     def acceptJob(self) :        
         """Returns the exit code needed by the printing backend to accept the job and print it."""
@@ -270,5 +258,5 @@
         
     # pass the job untouched to the underlying layer
-    kotafilter.filterInput(kotafilter.inputfile)      
+    kotafilter.accounter.filterInput(kotafilter.inputfile)      
     
     return kotafilter.acceptJob()
Index: /pykota/trunk/NEWS
===================================================================
--- /pykota/trunk/NEWS (revision 975)
+++ /pykota/trunk/NEWS (revision 976)
@@ -22,4 +22,15 @@
 PyKota NEWS :
 
+    - 1.05alpha3 :
+    
+        - A 'stupid' and unreliable accounting method was
+          implemented to serve as an example on how to
+          do this sort of things. This method only counts
+          the 'showpage' statements in the input data.
+          See sample configuration file for details.
+          Pluggable accounting methods work, but I advise
+          you TO NOT USE THIS ONE WHICH IS JUST AN EXAMPLE.
+          It is not reliable enough to be used.
+          
     - 1.05alpha2 :
     
Index: /pykota/trunk/po/en/pykota.po
===================================================================
--- /pykota/trunk/po/en/pykota.po (revision 973)
+++ /pykota/trunk/po/en/pykota.po (revision 976)
@@ -21,4 +21,7 @@
 #
 # $Log$
+# Revision 1.23  2003/04/30 13:36:40  jalet
+# Stupid accounting method was added.
+#
 # Revision 1.22  2003/04/29 18:37:54  jalet
 # Pluggable accounting methods (actually doesn't support external scripts)
@@ -337,2 +340,5 @@
 msgid "Option requester for printer %s was not set"
 msgstr ""
+
+msgid "Using the 'stupid' accounting method is unreliable."
+msgstr ""
Index: /pykota/trunk/po/fr/pykota.po
===================================================================
--- /pykota/trunk/po/fr/pykota.po (revision 973)
+++ /pykota/trunk/po/fr/pykota.po (revision 976)
@@ -21,4 +21,7 @@
 #
 # $Log$
+# Revision 1.22  2003/04/30 13:36:40  jalet
+# Stupid accounting method was added.
+#
 # Revision 1.21  2003/04/29 18:37:54  jalet
 # Pluggable accounting methods (actually doesn't support external scripts)
@@ -349,2 +352,5 @@
 msgid "Option requester for printer %s was not set"
 msgstr "L'option requester pour l'imprimante %s n'a pas � d�nie"
+
+msgid "Using the 'stupid' accounting method is unreliable."
+msgstr "Utiliser la m�ode 'stupid' n'est pas fiable."
Index: /pykota/trunk/po/pykota.pot
===================================================================
--- /pykota/trunk/po/pykota.pot (revision 973)
+++ /pykota/trunk/po/pykota.pot (revision 976)
@@ -21,4 +21,7 @@
 #
 # $Log$
+# Revision 1.23  2003/04/30 13:36:40  jalet
+# Stupid accounting method was added.
+#
 # Revision 1.22  2003/04/29 18:37:54  jalet
 # Pluggable accounting methods (actually doesn't support external scripts)
@@ -337,2 +340,5 @@
 msgid "Option requester for printer %s was not set"
 msgstr ""
+
+msgid "Using the 'stupid' accounting method is unreliable."
+msgstr ""
