Changeset 646
- Timestamp:
- 06/14/05 21:26:27 (19 years ago)
- Files:
-
- 1 modified
Legend:
- Unmodified
- Added
- Removed
-
tea4cups/trunk/tea4cups
r644 r646 58 58 pass 59 59 60 # Some IPP constants 61 OPERATION_ATTRIBUTES_TAG = 0x01 62 JOB_ATTRIBUTES_TAG = 0x02 63 END_OF_ATTRIBUTES_TAG = 0x03 64 PRINTER_ATTRIBUTES_TAG = 0x04 65 UNSUPPORTED_ATTRIBUTES_TAG = 0x05 66 67 class IPPMessage : 68 """A class for IPP message files. 69 60 class IPPRequest : 61 """A class for IPP requests. 62 70 63 Usage : 71 64 72 65 fp = open("/var/spool/cups/c00001", "rb") 73 message = IPP Message(fp.read())66 message = IPPRequest(fp.read()) 74 67 fp.close() 75 print "IPP version : %s" % message.version 76 print "IPP operation Id : %s" % message.operation_id 77 print "IPP request Id : %s" % message.request_id 78 for attrtype in ("operation", "job", "printer", "unsupported") : 68 message.parse() 69 # print message.dump() # dumps an equivalent to the original IPP message 70 # print str(message) # returns a string of text with the same content as below 71 print "IPP version : %s.%s" % message.version 72 print "IPP operation Id : 0x%04x" % message.operation_id 73 print "IPP request Id : 0x%08x" % message.request_id 74 for attrtype in message.attributes_types : 79 75 attrdict = getattr(message, "%s_attributes" % attrtype) 80 76 if attrdict : … … 82 78 for key in attrdict.keys() : 83 79 print " %s : %s" % (key, attrdict[key]) 80 if message.data : 81 print "IPP datas : ", repr(message.data) 84 82 """ 85 attributes_types = ("operation", "job", "printer", "unsupported") 86 def __init__(self, data, debug=0) : 87 """Initializes and parses IPP Message object. 88 83 attributes_types = ("operation", "job", "printer", "unsupported", \ 84 "subscription", "event_notification") 85 def __init__(self, data="", version=None, operation_id=None, \ 86 request_id=None, debug=0) : 87 """Initializes an IPP Message object. 88 89 89 Parameters : 90 91 data : the IPP Message's content.90 91 data : the complete IPP Message's content. 92 92 debug : a boolean value to output debug info on stderr. 93 93 """ 94 94 self.debug = debug 95 self.data = data 95 self._data = data 96 self.parsed = 0 97 98 # Initializes message 99 if version is not None : 100 try : 101 self.version = [int(p) for p in version.split(".")] 102 except AttributeError : 103 if len(version) == 2 : # 2-tuple 104 self.version = version 105 else : 106 try : 107 self.version = [int(p) for p in str(float(version)).split(".")] 108 except : 109 self.version = (1, 1) # default version number 110 self.operation_id = operation_id 111 self.request_id = request_id 112 self.data = "" 113 114 # Initialize attributes mappings 96 115 for attrtype in self.attributes_types : 97 116 setattr(self, "%s_attributes" % attrtype, {}) 98 self.tags = [ None ] * 256 # by default all tags reserved 99 117 118 # Initialize tags 119 self.tags = [ None ] * 256 # by default all tags reserved 120 100 121 # Delimiter tags 101 self.tags[OPERATION_ATTRIBUTES_TAG] = "operation-attributes-tag" 102 self.tags[JOB_ATTRIBUTES_TAG] = "job-attributes-tag" 103 self.tags[END_OF_ATTRIBUTES_TAG] = "end-of-attributes-tag" 104 self.tags[PRINTER_ATTRIBUTES_TAG] = "printer-attributes-tag" 105 self.tags[UNSUPPORTED_ATTRIBUTES_TAG] = "unsupported-attributes-tag" 106 122 self.tags[0x01] = "operation-attributes-tag" 123 self.tags[0x02] = "job-attributes-tag" 124 self.tags[0x03] = "end-of-attributes-tag" 125 self.tags[0x04] = "printer-attributes-tag" 126 self.tags[0x05] = "unsupported-attributes-tag" 127 self.tags[0x06] = "subscription-attributes-tag" 128 self.tags[0x07] = "event-notification-attributes-tag" 129 107 130 # out of band values 108 131 self.tags[0x10] = "unsupported" … … 110 133 self.tags[0x12] = "unknown" 111 134 self.tags[0x13] = "no-value" 112 135 self.tags[0x15] = "not-settable" 136 self.tags[0x16] = "delete-attribute" 137 self.tags[0x17] = "admin-define" 138 113 139 # integer values 114 140 self.tags[0x20] = "generic-integer" … … 116 142 self.tags[0x22] = "boolean" 117 143 self.tags[0x23] = "enum" 118 144 119 145 # octetString 120 146 self.tags[0x30] = "octetString-with-an-unspecified-format" … … 122 148 self.tags[0x32] = "resolution" 123 149 self.tags[0x33] = "rangeOfInteger" 124 self.tags[0x34] = " reserved-for-collection"150 self.tags[0x34] = "begCollection" # TODO : find sample files for testing 125 151 self.tags[0x35] = "textWithLanguage" 126 152 self.tags[0x36] = "nameWithLanguage" 127 153 self.tags[0x37] = "endCollection" 154 128 155 # character strings 129 self.tags[0x 20] = "generic-character-string"156 self.tags[0x40] = "generic-character-string" 130 157 self.tags[0x41] = "textWithoutLanguage" 131 158 self.tags[0x42] = "nameWithoutLanguage" 132 # self.tags[0x43] = "reserved"133 159 self.tags[0x44] = "keyword" 134 160 self.tags[0x45] = "uri" … … 137 163 self.tags[0x48] = "naturalLanguage" 138 164 self.tags[0x49] = "mimeMediaType" 139 140 # now parses the IPP message 141 self.parse() 142 143 def printInfo(self, msg) : 165 self.tags[0x4a] = "memberAttrName" 166 167 # Reverse mapping to generate IPP messages 168 self.dictags = {} 169 for i in range(len(self.tags)) : 170 value = self.tags[i] 171 if value is not None : 172 self.dictags[value] = i 173 174 def printInfo(self, msg) : 144 175 """Prints a debug message.""" 145 176 if self.debug : 146 177 sys.stderr.write("%s\n" % msg) 147 178 sys.stderr.flush() 148 149 def parseTag(self) : 150 """Extracts information from an IPP tag.""" 151 pos = self.position 152 tagtype = self.tags[ord(self.data[pos])] 153 pos += 1 154 posend = pos2 = pos + 2 155 namelength = unpack(">H", self.data[pos:pos2])[0] 156 if not namelength : 157 name = self._curname 158 else : 159 posend += namelength 160 self._curname = name = self.data[pos2:posend] 161 pos2 = posend + 2 162 valuelength = unpack(">H", self.data[posend:pos2])[0] 163 posend = pos2 + valuelength 164 value = self.data[pos2:posend] 165 if tagtype in ("integer", "enum") : 166 value = unpack(">I", value)[0] 167 oldval = self._curdict.setdefault(name, []) 168 oldval.append((tagtype, value)) 169 self.printInfo("%s(%s) %s" % (name, tagtype, value)) 170 return posend - self.position 171 172 def operation_attributes_tag(self) : 173 """Indicates that the parser enters into an operation-attributes-tag group.""" 174 self.printInfo("Start of operation_attributes_tag") 175 self._curdict = self.operation_attributes 176 return self.parseTag() 177 178 def job_attributes_tag(self) : 179 """Indicates that the parser enters into a job-attributes-tag group.""" 180 self.printInfo("Start of job_attributes_tag") 181 self._curdict = self.job_attributes 182 return self.parseTag() 183 184 def printer_attributes_tag(self) : 185 """Indicates that the parser enters into a printer-attributes-tag group.""" 186 self.printInfo("Start of printer_attributes_tag") 187 self._curdict = self.printer_attributes 188 return self.parseTag() 189 190 def unsupported_attributes_tag(self) : 191 """Indicates that the parser enters into an unsupported-attributes-tag group.""" 192 self.printInfo("Start of unsupported_attributes_tag") 193 self._curdict = self.unsupported_attributes 194 return self.parseTag() 195 179 180 def __str__(self) : 181 """Returns the parsed IPP message in a readable form.""" 182 if not self.parsed : 183 return "" 184 else : 185 buffer = [] 186 buffer.append("IPP version : %s.%s" % self.version) 187 buffer.append("IPP operation Id : 0x%04x" % self.operation_id) 188 buffer.append("IPP request Id : 0x%08x" % self.request_id) 189 for attrtype in self.attributes_types : 190 attrdict = getattr(self, "%s_attributes" % attrtype) 191 if attrdict : 192 buffer.append("%s attributes :" % attrtype.title()) 193 for key in attrdict.keys() : 194 buffer.append(" %s : %s" % (key, attrdict[key])) 195 if self.data : 196 buffer.append("IPP datas : %s" % repr(message.data)) 197 return "\n".join(buffer) 198 199 def dump(self) : 200 """Generates an IPP Message. 201 202 Returns the message as a string of text. 203 """ 204 buffer = [] 205 if None not in (self.version, self.operation_id, self.request_id) : 206 buffer.append(chr(self.version[0]) + chr(self.version[1])) 207 buffer.append(pack(">H", self.operation_id)) 208 buffer.append(pack(">I", self.request_id)) 209 for attrtype in self.attributes_types : 210 tagprinted = 0 211 for (attrname, value) in getattr(self, "%s_attributes" % attrtype).items() : 212 if not tagprinted : 213 buffer.append(chr(self.dictags["%s-attributes-tag" % attrtype])) 214 tagprinted = 1 215 if type(value) != type([]) : 216 value = [ value ] 217 for (vtype, val) in value : 218 buffer.append(chr(self.dictags[vtype])) 219 buffer.append(pack(">H", len(attrname))) 220 buffer.append(attrname) 221 if vtype in ("integer", "enum") : 222 buffer.append(pack(">H", 4)) 223 buffer.append(pack(">I", val)) 224 elif vtype == "boolean" : 225 buffer.append(pack(">H", 1)) 226 buffer.append(chr(val)) 227 else : 228 buffer.append(pack(">H", len(val))) 229 buffer.append(val) 230 buffer.append(chr(self.dictags["end-of-attributes-tag"])) 231 buffer.append(self.data) 232 return "".join(buffer) 233 196 234 def parse(self) : 197 """Parses an IPP Message.198 235 """Parses an IPP Request. 236 199 237 NB : Only a subset of RFC2910 is implemented. 200 238 """ 201 239 self._curname = None 202 240 self._curdict = None 203 self.version = "%s.%s" % (ord(self.data[0]), ord(self.data[1]))204 self.operation_id = "0x%04x" % unpack(">H", self.data[2:4])[0]205 self.request_id = "0x%08x" % unpack(">I", self.data[4:8])[0]241 self.version = (ord(self._data[0]), ord(self._data[1])) 242 self.operation_id = unpack(">H", self._data[2:4])[0] 243 self.request_id = unpack(">I", self._data[4:8])[0] 206 244 self.position = 8 207 try : 208 tag = ord(self.data[self.position]) 209 while tag != END_OF_ATTRIBUTES_TAG : 245 endofattributes = self.dictags["end-of-attributes-tag"] 246 maxdelimiter = self.dictags["event-notification-attributes-tag"] 247 try : 248 tag = ord(self._data[self.position]) 249 while tag != endofattributes : 210 250 self.position += 1 211 251 name = self.tags[tag] … … 214 254 if func is not None : 215 255 self.position += func() 216 if ord(self. data[self.position]) > UNSUPPORTED_ATTRIBUTES_TAG:256 if ord(self._data[self.position]) > maxdelimiter : 217 257 self.position -= 1 218 258 continue 219 tag = ord(self. data[self.position])259 tag = ord(self._data[self.position]) 220 260 except IndexError : 221 261 raise IPPError, "Unexpected end of IPP message." 222 262 223 263 # Now transform all one-element lists into single values 224 264 for attrtype in self.attributes_types : … … 227 267 if len(value) == 1 : 228 268 attrdict[key] = value[0] 269 self.data = self._data[self.position+1:] 270 self.parsed = 1 271 272 def parseTag(self) : 273 """Extracts information from an IPP tag.""" 274 pos = self.position 275 tagtype = self.tags[ord(self._data[pos])] 276 pos += 1 277 posend = pos2 = pos + 2 278 namelength = unpack(">H", self._data[pos:pos2])[0] 279 if not namelength : 280 name = self._curname 281 else : 282 posend += namelength 283 self._curname = name = self._data[pos2:posend] 284 pos2 = posend + 2 285 valuelength = unpack(">H", self._data[posend:pos2])[0] 286 posend = pos2 + valuelength 287 value = self._data[pos2:posend] 288 if tagtype in ("integer", "enum") : 289 value = unpack(">I", value)[0] 290 elif tagtype == "boolean" : 291 value = ord(value) 292 oldval = self._curdict.setdefault(name, []) 293 oldval.append((tagtype, value)) 294 self.printInfo("%s(%s) : %s" % (name, tagtype, value)) 295 return posend - self.position 296 297 def operation_attributes_tag(self) : 298 """Indicates that the parser enters into an operation-attributes-tag group.""" 299 self.printInfo("Start of operation_attributes_tag") 300 self._curdict = self.operation_attributes 301 return self.parseTag() 302 303 def job_attributes_tag(self) : 304 """Indicates that the parser enters into a job-attributes-tag group.""" 305 self.printInfo("Start of job_attributes_tag") 306 self._curdict = self.job_attributes 307 return self.parseTag() 308 309 def printer_attributes_tag(self) : 310 """Indicates that the parser enters into a printer-attributes-tag group.""" 311 self.printInfo("Start of printer_attributes_tag") 312 self._curdict = self.printer_attributes 313 return self.parseTag() 314 315 def unsupported_attributes_tag(self) : 316 """Indicates that the parser enters into an unsupported-attributes-tag group.""" 317 self.printInfo("Start of unsupported_attributes_tag") 318 self._curdict = self.unsupported_attributes 319 return self.parseTag() 320 321 def subscription_attributes_tag(self) : 322 """Indicates that the parser enters into a subscription-attributes-tag group.""" 323 self.printInfo("Start of subscription_attributes_tag") 324 self._curdict = self.subscription_attributes 325 return self.parseTag() 326 327 def event_notification_attributes_tag(self) : 328 """Indicates that the parser enters into an event-notification-attributes-tag group.""" 329 self.printInfo("Start of event_notification_attributes_tag") 330 self._curdict = self.event_notification_attributes 331 return self.parseTag() 229 332 230 333 class FakeConfig : … … 433 536 self.Directory = self.getPrintQueueOption(self.PrinterName, "directory") 434 537 self.DataFile = os.path.join(self.Directory, "%s-%s-%s-%s" % (self.myname, self.PrinterName, self.UserName, self.JobId)) 435 (ippfilename, ippmessage) = self.parseIPP MessageFile()538 (ippfilename, ippmessage) = self.parseIPPRequestFile() 436 539 self.ControlFile = ippfilename 437 540 (chtype, self.ClientHost) = ippmessage.operation_attributes.get("job-originating-host-name", \ … … 466 569 return dirvalues 467 570 468 def parseIPP MessageFile(self) :571 def parseIPPRequestFile(self) : 469 572 """Parses the IPP message file and returns a tuple (filename, parsedvalue).""" 470 573 cupsdconf = self.getCupsConfigDirectives(["RequestRoot"]) … … 483 586 self.logDebug("Parsing of IPP message file %s begins." % ippmessagefile) 484 587 try : 485 ippmessage = IPPMessage(ippdatafile.read()) 588 ippmessage = IPPRequest(ippdatafile.read()) 589 ippmessage.parse() 486 590 except IPPError, msg : 487 591 self.logInfo("Error while parsing %s : %s" % (ippmessagefile, msg), "warn")