def parse(self, data, negotiated): if not data: return self # We do not care if the attribute are transitive or not as we do not redistribute flag = Attribute.Flag(ord(data[0])) aid = Attribute.ID(ord(data[1])) if flag & Attribute.Flag.EXTENDED_LENGTH: length = unpack('!H', data[2:4])[0] offset = 4 else: length = ord(data[2]) offset = 3 data = data[offset:] next = data[length:] attribute = data[:length] logger = Logger() logger.parser( LazyFormat( "parsing flag %x type %02x (%s) len %02x %s" % (flag, int(aid), aid, length, 'payload ' if length else ''), od, data[:length])) # remove the PARTIAL bit before comparaison if the attribute is optional if aid in Attribute.attributes_optional: aid &= Attribute.Flag.MASK_PARTIAL & 0xFF # aid &= ~Attribute.Flag.PARTIAL & 0xFF # cleaner than above (python use signed integer for ~) # handle the attribute if we know it if Attribute.registered(aid, flag): self.add(Attribute.unpack(aid, flag, attribute, negotiated)) return self.parse(next, negotiated) # XXX: FIXME: we could use a fallback function here like capability # if we know the attribute but the flag is not what the RFC says. ignore it. if aid in Attribute.attributes_known: logger.parser( 'invalid flag for attribute %s (flag 0x%02X, aid 0x%02X)' % (Attribute.ID.names.get(aid, 'unset'), flag, aid)) return self.parse(next, negotiated) # it is an unknown transitive attribute we need to pass on if flag & Attribute.Flag.TRANSITIVE: logger.parser( 'unknown transitive attribute (flag 0x%02X, aid 0x%02X)' % (flag, aid)) self.add( GenericAttribute(aid, flag | Attribute.Flag.PARTIAL, attribute), attribute) return self.parse(next, negotiated) # it is an unknown non-transitive attribute we can ignore. logger.parser( 'ignoring unknown non-transitive attribute (flag 0x%02X, aid 0x%02X)' % (flag, aid)) return self.parse(next, negotiated)
def flag_attribute_content(data): flag = Attribute.Flag(ord(data[0])) attr = Attribute.ID(ord(data[1])) if flag & Attribute.Flag.EXTENDED_LENGTH: length = unpack('!H', data[2:4])[0] return flag, attr, data[4:length + 4] else: length = ord(data[2]) return flag, attr, data[3:length + 3]
def add(self, attribute, data=None): # we return None as attribute if the unpack code must not generate them if attribute is None: return self._str = '' self._json = '' if attribute.MULTIPLE: if self.has(attribute.ID): self[attribute.ID].append(attribute) else: self[attribute.ID] = MultiAttributes(attribute) else: if attribute.ID in self: raise Notify( 3, 0, 'multiple attribute for %s' % str(Attribute.ID(attribute.ID))) self[attribute.ID] = attribute