Changeset 3413 for pykota/trunk/pykota/accounters/pjl.py
- Timestamp:
- 09/27/08 22:02:37 (16 years ago)
- Files:
-
- 1 modified
Legend:
- Unmodified
- Added
- Removed
-
pykota/trunk/pykota/accounters/pjl.py
r3411 r3413 8 8 # the Free Software Foundation, either version 3 of the License, or 9 9 # (at your option) any later version. 10 # 10 # 11 11 # This program is distributed in the hope that it will be useful, 12 12 # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 14 # GNU General Public License for more details. 15 # 15 # 16 16 # You should have received a copy of the GNU General Public License 17 17 # along with this program. If not, see <http://www.gnu.org/licenses/>. … … 21 21 # 22 22 23 """This module defines the necessary classes and methods to retrieve 24 a printer's internal page counter over a TCP connection.""" 23 """This module defines the necessary classes and methods to retrieve 24 a printer's internal page counter over a TCP connection.""" 25 25 26 26 import sys … … 36 36 37 37 # Old method : PJLMESSAGE = "\033%-12345X@PJL USTATUSOFF\r\n@PJL INFO STATUS\r\n@PJL INFO PAGECOUNT\r\n\033%-12345X" 38 # Here's a new method, which seems to work fine on my HP2300N, while the 38 # Here's a new method, which seems to work fine on my HP2300N, while the 39 39 # previous one didn't. 40 # TODO : We could also experiment with USTATUS JOB=ON and we would know for sure 40 # TODO : We could also experiment with USTATUS JOB=ON and we would know for sure 41 41 # when the job is finished, without having to poll the printer repeatedly. 42 42 PJLMESSAGE = "\033%-12345X@PJL USTATUS DEVICE=ON\r\n@PJL INFO STATUS\r\n@PJL INFO PAGECOUNT\r\n@PJL USTATUS DEVICE=OFF\033%-12345X" … … 52 52 "40000" : "Sleep Mode", # Standby 53 53 } 54 54 55 55 class Handler : 56 56 """A class for PJL print accounting.""" … … 69 69 self.readthread = None 70 70 self.quitEvent = threading.Event() 71 72 def __del__(self) : 71 72 def __del__(self) : 73 73 """Ensures the network connection is closed at object deletion time.""" 74 74 self.close() 75 76 def open(self) : 75 76 def open(self) : 77 77 """Opens the network connection.""" 78 78 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) … … 93 93 self.parent.filter.logdebug("Connected to printer %s:%s" % (self.printerHostname, self.port)) 94 94 return True 95 96 def close(self) : 95 96 def close(self) : 97 97 """Closes the network connection.""" 98 98 if not self.closed : … … 107 107 self.queue = None 108 108 self.closed = True 109 110 def readloop(self) : 109 110 def readloop(self) : 111 111 """Reading loop thread.""" 112 112 self.parent.filter.logdebug("Reading thread started.") … … 115 115 try : 116 116 answer = self.sock.recv(1) 117 except socket.timeout : 117 except socket.timeout : 118 118 pass 119 119 except socket.error, (dummy, msg) : 120 120 self.parent.filter.printInfo(_("Problem while receiving PJL answer from %s:%s : %s") % (self.printerHostname, self.port, str(msg)), "warn") 121 else : 121 else : 122 122 if answer : 123 123 readbuffer.append(answer) … … 125 125 self.queue.put("".join(readbuffer)) 126 126 readbuffer = [] 127 if readbuffer : 128 self.queue.put("".join(readbuffer)) 127 if readbuffer : 128 self.queue.put("".join(readbuffer)) 129 129 self.parent.filter.logdebug("Reading thread ended.") 130 131 def retrievePJLValues(self) : 130 131 def retrievePJLValues(self) : 132 132 """Retrieves a printer's internal page counter and status via PJL.""" 133 133 while not self.open() : … … 141 141 except socket.error, msg : 142 142 self.parent.filter.printInfo(_("Problem while sending PJL query to %s:%s : %s") % (self.printerHostname, self.port, str(msg)), "warn") 143 else : 143 else : 144 144 self.parent.filter.logdebug("Query sent to %s : %s" % (self.printerHostname, repr(PJLMESSAGE))) 145 145 actualpagecount = self.printerStatus = None … … 147 147 try : 148 148 answer = self.queue.get(True, 5) 149 except Queue.Empty : 149 except Queue.Empty : 150 150 self.parent.filter.logdebug("Timeout when reading printer's answer from %s:%s" % (self.printerHostname, self.port)) 151 else : 151 else : 152 152 readnext = False 153 153 self.parent.filter.logdebug("PJL answer : %s" % repr(answer)) 154 for line in [l.strip() for l in answer.split()] : 154 for line in [l.strip() for l in answer.split()] : 155 155 if line.startswith("CODE=") : 156 156 self.printerStatus = line.split("=")[1] 157 157 self.parent.filter.logdebug("Found status : %s" % self.printerStatus) 158 elif line.startswith("PAGECOUNT=") : 158 elif line.startswith("PAGECOUNT=") : 159 159 try : 160 160 actualpagecount = int(line.split('=')[1].strip()) 161 except ValueError : 161 except ValueError : 162 162 self.parent.filter.logdebug("Received incorrect datas : [%s]" % line.strip()) 163 163 else : 164 164 self.parent.filter.logdebug("Found pages counter : %s" % actualpagecount) 165 elif line.startswith("PAGECOUNT") : 165 elif line.startswith("PAGECOUNT") : 166 166 readnext = True # page counter is on next line 167 elif readnext : 167 elif readnext : 168 168 try : 169 169 actualpagecount = int(line.strip()) 170 except ValueError : 170 except ValueError : 171 171 self.parent.filter.logdebug("Received incorrect datas : [%s]" % line.strip()) 172 172 else : … … 174 174 readnext = False 175 175 self.printerInternalPageCounter = max(actualpagecount, self.printerInternalPageCounter) 176 finally : 176 finally : 177 177 self.close() 178 178 179 179 def waitPrinting(self) : 180 180 """Waits for printer status being 'printing'.""" … … 183 183 if not noprintingmaxdelay : 184 184 self.parent.filter.logdebug("Will wait indefinitely until printer %s is in 'printing' state." % self.parent.filter.PrinterName) 185 else : 185 else : 186 186 self.parent.filter.logdebug("Will wait until printer %s is in 'printing' state or %i seconds have elapsed." % (self.parent.filter.PrinterName, noprintingmaxdelay)) 187 187 previousValue = self.parent.getLastPageCounter() … … 192 192 if self.printerStatus in ('10023', '10003') : 193 193 break 194 if self.printerInternalPageCounter is not None : 194 if self.printerInternalPageCounter is not None : 195 195 if firstvalue is None : 196 196 # first time we retrieved a page counter, save it 197 197 firstvalue = self.printerInternalPageCounter 198 else : 198 else : 199 199 # second time (or later) 200 200 if firstvalue < self.printerInternalPageCounter : … … 213 213 # the printer rejected it for some reason. 214 214 self.parent.filter.printInfo("Printer %s probably won't print this job !!!" % self.parent.filter.PrinterName, "warn") 215 else : 215 else : 216 216 # Here the job has already been entirely printed, and 217 217 # the printer has already passed from 'idle' to 'printing' to 'idle' again. … … 220 220 self.parent.filter.logdebug(_("Waiting for printer %s to be printing...") % self.parent.filter.PrinterName) 221 221 time.sleep(statusstabilizationdelay) 222 222 223 223 def waitIdle(self) : 224 224 """Waits for printer status being 'idle'.""" … … 233 233 and (os.environ.get("PYKOTAPHASE") == "BEFORE") : 234 234 self.parent.filter.logdebug("No need to wait for the printer to be idle, it is the case already.") 235 return 235 return 236 236 idle_num += 1 237 237 if idle_num >= statusstabilizationloops : 238 238 # printer status is stable, we can exit 239 239 break 240 else : 240 else : 241 241 idle_num = 0 242 242 self.parent.filter.logdebug(_("Waiting for printer %s's idle status to stabilize...") % self.parent.filter.PrinterName) 243 243 time.sleep(statusstabilizationdelay) 244 244 245 245 def retrieveInternalPageCounter(self) : 246 246 """Returns the page counter from the printer via internal PJL handling.""" … … 251 251 self.parent.filter.JobSizeBytes : 252 252 self.waitPrinting() 253 self.waitIdle() 254 except : 253 self.waitIdle() 254 except : 255 255 self.parent.filter.printInfo(_("PJL querying stage interrupted. Using latest value seen for internal page counter (%s) on printer %s.") % (self.printerInternalPageCounter, self.parent.filter.PrinterName), "warn") 256 256 raise 257 else : 257 else : 258 258 return self.printerInternalPageCounter 259 259 260 260 def main(hostname) : 261 261 """Tries PJL accounting for a printer host.""" … … 266 266 self.PrinterName = "FakePrintQueue" 267 267 self.JobSizeBytes = 1 268 268 269 269 def printInfo(self, msg, level="info") : 270 270 """Prints informational message.""" 271 271 sys.stderr.write("%s : %s\n" % (level.upper(), msg)) 272 272 sys.stderr.flush() 273 274 def logdebug(self, msg) : 273 274 def logdebug(self, msg) : 275 275 """Prints debug message.""" 276 276 self.printInfo(msg, "debug") 277 278 class FakeAccounter : 277 278 class FakeAccounter : 279 279 """Fakes an accounter for testing purposes.""" 280 280 def __init__(self, hostname) : … … 283 283 self.filter = FakeFilter() 284 284 self.protocolHandler = Handler(self, hostname) 285 286 def getLastPageCounter(self) : 285 286 def getLastPageCounter(self) : 287 287 """Fakes the return of a page counter.""" 288 288 return 0 289 289 290 290 acc = FakeAccounter(hostname) 291 291 return acc.protocolHandler.retrieveInternalPageCounter() 292 293 if __name__ == "__main__" : 294 if len(sys.argv) != 2 : 292 293 if __name__ == "__main__" : 294 if len(sys.argv) != 2 : 295 295 sys.stderr.write("Usage : python %s printer_ip_address\n" % sys.argv[0]) 296 else : 296 else : 297 297 def _(msg) : 298 298 """Fake gettext method.""" 299 299 return msg 300 300 301 301 pagecounter = main(sys.argv[1]) 302 302 print "Internal page counter's value is : %s" % pagecounter 303 303