Index: /pykota/trunk/conf/pykota.conf.sample
===================================================================
--- /pykota/trunk/conf/pykota.conf.sample (revision 2692)
+++ /pykota/trunk/conf/pykota.conf.sample (revision 2759)
@@ -327,7 +327,17 @@
 # When the real CUPS backend fail, should we modify the
 # user's page counters and account balance or not ?
+# Also should we retry and if yes then how often and how many times ?
 # If you trust your users, set it to "nocharge".
 # If you think they found some mean to kill the real CUPS backend, 
 # then set it to "charge".
+# If your print queues get regularly disabled by CUPS when the printers
+# are switched off, you might want to set it to "retry:N:S" where
+# N is the number of times the operation should be retried, and S is
+# the delay in seconds during which PyKota will sleep before trying again.
+# If N is 0, PyKota will retry indefinitely each S seconds until the
+# backend succeeds, so you should use this with caution. If N is 0,
+# of course neither "charge" nor "nocharge" will be honored.
+# You can combine "charge" or "nocharge" with "retry:N:S" if you want,
+# by separating the values with a comma as shown in the examples below.
 # If unset, the default value is "nocharge", meaning that users won't be
 # charged whenever a CUPS backend fails. This is the OPPOSITE
@@ -335,4 +345,7 @@
 # This value can be set either globally or on a per printer basis
 # If both are defined, the printer option has priority.
+# onbackenderror : charge,retry:5:60
+# onbackenderror : retry:0:300
+# onbackenderror : retry:3:300,nocharge
 # onbackenderror : charge
 onbackenderror : nocharge
Index: /pykota/trunk/pykota/config.py
===================================================================
--- /pykota/trunk/pykota/config.py (revision 2692)
+++ /pykota/trunk/pykota/config.py (revision 2759)
@@ -299,9 +299,19 @@
             action = self.getPrinterOption(printername, "onbackenderror")
         except PyKotaConfigError :    
-            return "NOCHARGE"
-        else :    
-            action = action.upper()
-            if action not in validactions :
-                raise PyKotaConfigError, _("Option onbackenderror in section %s only supports values in %s") % (printername, str(validactions))
+            return ["NOCHARGE"]
+        else :    
+            action = action.upper().split(",")
+            error = False
+            for act in action :
+                if act not in validactions :
+                    if act.startswith("RETRY:") :
+                        try :
+                            (num, delay) = [int(p) for p in act[6:].split(":", 2)]
+                        except ValueError :    
+                            error = True
+                    else :        
+                        error = True
+            if error :
+                raise PyKotaConfigError, _("Option onbackenderror in section %s only supports values 'charge', 'nocharge', and 'retry:num:delay'") % printername
             return action  
             
Index: /pykota/trunk/pykota/version.py
===================================================================
--- /pykota/trunk/pykota/version.py (revision 2755)
+++ /pykota/trunk/pykota/version.py (revision 2759)
@@ -22,5 +22,5 @@
 #
 
-__version__ = "1.24alpha14_unofficial"
+__version__ = "1.24alpha15_unofficial"
 
 __doc__ = "PyKota : a complete Printing Quota Solution for CUPS."
Index: /pykota/trunk/bin/cupspykota
===================================================================
--- /pykota/trunk/bin/cupspykota (revision 2692)
+++ /pykota/trunk/bin/cupspykota (revision 2759)
@@ -27,4 +27,5 @@
 import sys
 import os
+import time
 import errno
 import tempfile
@@ -1018,5 +1019,5 @@
                 self.Action = "PROBLEM"
                 self.exportReason()
-                if onbackenderror == "NOCHARGE" :
+                if "NOCHARGE" in onbackenderror :
                     self.JobSize = 0
                     self.printInfo(_("Job size forced to 0 because the real CUPS backend failed. No accounting will be done."), "warn")
@@ -1033,5 +1034,5 @@
             else :    
                 self.UserPQuota.resetDenyBannerCounter()
-                if (self.Action != "PROBLEM") or (onbackenderror == "CHARGE") : 
+                if (self.Action != "PROBLEM") or ("CHARGE" in onbackenderror) : 
                     self.JobSize = self.accounter.getJobSize(self.Printer)
                     self.sanitizeJobSize()
@@ -1039,5 +1040,5 @@
             self.printInfo(_("Job size : %i") % self.JobSize)
             
-            if ((self.Action == "PROBLEM") and (onbackenderror == "NOCHARGE")) or \
+            if ((self.Action == "PROBLEM") and ("NOCHARGE" in onbackenderror)) or \
                 (self.Action in ("DENY", "CANCEL")) :
                 self.JobPrice = 0.0
@@ -1061,5 +1062,5 @@
             if hasattr(self, "BillingCode") and self.BillingCode and self.BillingCode.Exists :
                 if (self.Action in ("ALLOW", "WARN")) or \
-                   ((self.Action == "PROBLEM") and (onbackenderror == "CHARGE")) :
+                   ((self.Action == "PROBLEM") and ("CHARGE" in onbackenderror)) :
                     self.BillingCode.consume(self.JobSize, self.JobPrice)
                     self.printInfo(_("Billing code %s was updated.") % self.BillingCode.BillingCode)
@@ -1087,11 +1088,38 @@
         """Sends the job's datas to the real backend."""
         self.logdebug("Sending job's datas to real backend...")
-        if self.InputFile is None :
-            infile = open(self.DataFile, "rb")
-        else :    
-            infile = None
-        retcode = self.runOriginalBackend(infile)
-        if self.InputFile is None :
-            infile.close()
+        
+        delay = 0
+        number = 1
+        for onb in self.config.getPrinterOnBackendError(self.PrinterName) :
+            if onb.startswith("RETRY:") :
+                try :
+                    (number, delay) = [int(p) for p in onb[6:].split(":", 2)]
+                    if (number < 0) or (delay < 0) :
+                        raise ValueError
+                except ValueError :    
+                    self.printInfo(_("Incorrect value for the 'onbackenderror' directive in section [%s]") % self.PrinterName, "error")
+                    delay = 0
+                    number = 1
+                else :    
+                    break
+        loopcnt = 1 
+        while True :            
+            if self.InputFile is None :
+                infile = open(self.DataFile, "rb")
+            else :    
+                infile = None
+            retcode = self.runOriginalBackend(infile)
+            if self.InputFile is None :
+                infile.close()
+            if not retcode :
+                break
+            else :
+                if (not number) or (loopcnt < number) :
+                    self.logdebug(_("The real backend produced an error, we will try again in %s seconds.") % delay)
+                    time.sleep(delay)
+                    loopcnt += 1
+                else :    
+                    break
+            
         self.logdebug("Job's datas sent to real backend.")
         return retcode
Index: /pykota/trunk/NEWS
===================================================================
--- /pykota/trunk/NEWS (revision 2755)
+++ /pykota/trunk/NEWS (revision 2759)
@@ -22,4 +22,9 @@
 PyKota NEWS :
        
+    - 1.24alpha15 :
+    
+        - Extended the functionnality of the 'onbackenderror' directive to
+          allow for configurable retries.
+          
     - 1.24alpha14 :
     
