Show
Ignore:
Timestamp:
03/13/05 14:54:22 (19 years ago)
Author:
jerome
Message:

Added initial code for IPP messages parsing

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • tea4cups/trunk/tea4cups

    r579 r581  
    3131import tempfile 
    3232import ConfigParser 
     33from struct import unpack 
     34 
     35OPERATION_ATTRIBUTES_TAG = 0x01 
     36JOB_ATTRIBUTES_TAG = 0x02 
     37END_OF_ATTRIBUTES_TAG = 0x03 
     38PRINTER_ATTRIBUTES_TAG = 0x04 
     39UNSUPPORTED_ATTRIBUTES_TAG = 0x05 
    3340 
    3441class TeeError(Exception): 
     
    4552    pass  
    4653     
     54class IPPError(TeeError) :     
     55    """IPP related exceptions.""" 
     56    pass  
     57     
     58class IPPMessage : 
     59    """A class for IPP message files.""" 
     60    def __init__(self, data) : 
     61        """Initializes an IPP Message object.""" 
     62        self.data = data 
     63        self._attributes = {} 
     64        self.curname = None 
     65        self.tags = [ None ] * 256      # by default all tags reserved 
     66         
     67        # Delimiter tags 
     68        self.tags[0x01] = "operation-attributes-tag" 
     69        self.tags[0x02] = "job-attributes-tag" 
     70        self.tags[0x03] = "end-of-attributes-tag" 
     71        self.tags[0x04] = "printer-attributes-tag" 
     72        self.tags[0x05] = "unsupported-attributes-tag" 
     73         
     74        # out of band values 
     75        self.tags[0x10] = "unsupported" 
     76        self.tags[0x11] = "reserved-for-future-default" 
     77        self.tags[0x12] = "unknown" 
     78        self.tags[0x13] = "no-value" 
     79         
     80        # integer values 
     81        self.tags[0x20] = "generic-integer" 
     82        self.tags[0x21] = "integer" 
     83        self.tags[0x22] = "boolean" 
     84        self.tags[0x23] = "enum" 
     85         
     86        # octetString 
     87        self.tags[0x30] = "octetString-with-an-unspecified-format" 
     88        self.tags[0x31] = "dateTime" 
     89        self.tags[0x32] = "resolution" 
     90        self.tags[0x33] = "rangeOfInteger" 
     91        self.tags[0x34] = "reserved-for-collection" 
     92        self.tags[0x35] = "textWithLanguage" 
     93        self.tags[0x36] = "nameWithLanguage" 
     94         
     95        # character strings 
     96        self.tags[0x20] = "generic-character-string" 
     97        self.tags[0x41] = "textWithoutLanguage" 
     98        self.tags[0x42] = "nameWithoutLanguage" 
     99        # self.tags[0x43] = "reserved" 
     100        self.tags[0x44] = "keyword" 
     101        self.tags[0x45] = "uri" 
     102        self.tags[0x46] = "uriScheme" 
     103        self.tags[0x47] = "charset" 
     104        self.tags[0x48] = "naturalLanguage" 
     105        self.tags[0x49] = "mimeMediaType" 
     106         
     107        # now parses the IPP message 
     108        self.parse() 
     109         
     110    def __getattr__(self, attrname) :     
     111        """Allows self.attributes to return the attributes names.""" 
     112        if attrname == "attributes" : 
     113            keys = self._attributes.keys() 
     114            keys.sort() 
     115            return keys 
     116        raise AttributeError, attrname 
     117             
     118    def __getitem__(self, ippattrname) :     
     119        """Fakes a dictionnary d['key'] notation.""" 
     120        value = self._attributes.get(ippattrname) 
     121        if value is not None : 
     122            if len(value) == 1 : 
     123                value = value[0] 
     124        return value         
     125    get = __getitem__     
     126         
     127    def parseTag(self) :     
     128        """Extracts information from an IPP tag.""" 
     129        pos = self.position 
     130        valuetag = self.tags[ord(self.data[pos])] 
     131        # print valuetag.get("name") 
     132        pos += 1 
     133        posend = pos2 = pos + 2 
     134        namelength = unpack(">H", self.data[pos:pos2])[0] 
     135        if not namelength : 
     136            name = self.curname 
     137        else :     
     138            posend += namelength 
     139            self.curname = name = self.data[pos2:posend] 
     140        pos2 = posend + 2 
     141        valuelength = unpack(">H", self.data[posend:pos2])[0] 
     142        posend = pos2 + valuelength 
     143        value = self.data[pos2:posend] 
     144        oldval = self._attributes.setdefault(name, []) 
     145        oldval.append(value) 
     146        return posend - self.position 
     147         
     148    def operation_attributes_tag(self) :  
     149        """Indicates that the parser enters into an operation-attributes-tag group.""" 
     150        return self.parseTag() 
     151         
     152    def job_attributes_tag(self) :  
     153        """Indicates that the parser enters into an operation-attributes-tag group.""" 
     154        return self.parseTag() 
     155         
     156    def printer_attributes_tag(self) :  
     157        """Indicates that the parser enters into an operation-attributes-tag group.""" 
     158        return self.parseTag() 
     159         
     160    def parse(self) : 
     161        """Parses an IPP Message. 
     162         
     163           NB : Only a subset of RFC2910 is implemented. 
     164           We are only interested in textual informations for now anyway. 
     165        """ 
     166        self.version = "%s.%s" % (ord(self.data[0]), ord(self.data[1])) 
     167        self.operation_id = "0x%04x" % unpack(">H", self.data[2:4])[0] 
     168        self.request_id = "0x%08x" % unpack(">I", self.data[4:8])[0] 
     169        self.position = 8 
     170        try : 
     171            tag = ord(self.data[self.position]) 
     172            while tag != END_OF_ATTRIBUTES_TAG : 
     173                self.position += 1 
     174                name = self.tags[tag] 
     175                if name is not None : 
     176                    func = getattr(self, name.replace("-", "_"), None) 
     177                    if func is not None : 
     178                        self.position += func() 
     179                        if ord(self.data[self.position]) > UNSUPPORTED_ATTRIBUTES_TAG : 
     180                            self.position -= 1 
     181                            continue 
     182                tag = ord(self.data[self.position]) 
     183        except IndexError : 
     184            raise IPPError, "Unexpected end of IPP message." 
     185             
    47186class FakeConfig :     
    48187    """Fakes a configuration file parser.""" 
     
    232371        self.PrinterName = os.environ.get("PRINTER", "") 
    233372        self.Directory = self.getPrintQueueOption(self.PrinterName, "directory") 
    234         self.DataFile = os.path.join(self.Directory, "%s-%s-%s" % (self.myname, self.PrinterName, self.JobId)) 
     373        self.DataFile = os.path.join(self.Directory, "%s-%s-%s-%s" % (self.myname, self.PrinterName, self.UserName, self.JobId)) 
    235374             
    236375    def exportAttributes(self) :     
     
    289428        """Launches each tee defined for the current print queue.""" 
    290429        branches = self.enumTeeBranches(self.PrinterName) 
    291         for (branch, command) in branches.items() : 
    292             self.logDebug("Launching %s : %s" % (branch, command)) 
    293             os.system(command) 
     430        if self.isTrue(self.getPrintQueueOption(self.PrinterName, "serialize", ignore=1)) : 
     431            for (branch, command) in branches.items() : 
     432                self.logDebug("Launching %s : %s" % (branch, command)) 
     433                os.system(command) 
     434        else :         
     435            raise TeeError, "Forking tees not yet implemented." 
    294436         
    295437if __name__ == "__main__" :