def __init__(self, msg): # Temporarily uses the Message instance as the input super(Named, self).__init__() guid_stream = msg._getStream('__nameid_version1.0/__substg1.0_00020102') entry_stream = msg._getStream('__nameid_version1.0/__substg1.0_00030102') names_stream = msg._getStream('__nameid_version1.0/__substg1.0_00040102') gl = len(guid_stream) el = len(entry_stream) nl = len(names_stream) # TODO guid stream parsing # TODO entry_stream parsing entries = [] for x in divide(entry_stream, 8): tmp = constants.STNP_ENT.unpack(x) entries.append({ 'id': tmp[0], 'pid': tmp[2], 'guid': tmp[1] >> 1, 'pkind': tmp[1] & 1, }) names = [] pos = 0 while pos < nl: l = constants.STNP_NAM.unpack(names_stream[pos:pos + 4])[0] pos += 4 names.append(names_stream[pos:pos + l].decode('utf_16_le')) pos += round_up(l, 4)
def __init__(self, msg): super(Named, self).__init__() self.__msg = msg guid_stream = self._getStream('__substg1.0_00020102') entry_stream = self._getStream('__substg1.0_00030102') names_stream = self._getStream('__substg1.0_00040102') guid_stream = self._getStream('__substg1.0_00020102', False) if guid_stream is None else guid_stream entry_stream = self._getStream('__substg1.0_00030102', False) if entry_stream is None else entry_stream names_stream = self._getStream('__substg1.0_00040102', False) if names_stream is None else names_stream self.guid_stream = guid_stream self.entry_stream = entry_stream self.names_stream = names_stream guid_stream_length = len(guid_stream) entry_stream_length = len(entry_stream) names_stream_length = len(names_stream) # TODO guid stream parsing guids = tuple([None, constants.GUID_PS_MAPI, constants.GUID_PS_PUBLIC_STRINGS] + [bytesToGuid(x) for x in divide(guid_stream, 16)]) # TODO entry_stream parsing entries = [] for x in divide(entry_stream, 8): tmp = constants.STNP_ENT.unpack(x) entry = { 'id': tmp[0], 'pid': tmp[2], 'guid_index': tmp[1] >> 1, 'pkind': tmp[1] & 1, # 0 if numerical, 1 if string } entry['guid'] = guids[entry['guid_index']] entries.append(entry) # Parse the names stream. names = {} pos = 0 while pos < names_stream_length: name_length = constants.STNP_NAM.unpack(names_stream[pos:pos+4])[0] pos += 4 # Move to the start of the names[pos - 4] = names_stream[pos:pos+name_length].decode('utf_16_le') # Names are stored in the dictionary as the position they start at pos += roundUp(name_length, 4) self.entries = entries self.__names = names self.__guids = guids self.__properties = [] for entry in entries: streamID = properHex(0x8000 + entry['pid']) msg._registerNamedProperty(entry, entry['pkind'], names[entry['id']] if entry['pkind'] == constants.STRING_NAMED else None) if msg.ExistsTypedProperty(streamID): self.__properties.append(StringNamedProperty(entry, names[entry['id']], msg._getTypedData(streamID)) if entry['pkind'] == constants.STRING_NAMED else NumericalNamedProperty(entry, msg._getTypedData(streamID))) self.__propertiesDict = {} for property in self.__properties: self.__propertiesDict[property.name if isinstance(property, StringNamedProperty) else property.propertyID] = property
def __init__(self, stream, type=None, skip=None): object.__init__(self) self.__stream = stream self.__pos = 0 self.__len = len(stream) self.__props = {} self.__naid = None self.__nrid = None self.__ac = None self.__rc = None if type != None: self.__intel = constants.INTELLIGENCE_SMART if type == constants.TYPE_MESSAGE: skip = 32 self.__naid, self.__nrid, self.__ac, self.__rc = constants.ST1.unpack( self.__stream[:24]) elif type == constants.TYPE_MESSAGE_EMBED: skip = 24 self.__naid, self.__nrid, self.__ac, self.__rc = constants.ST1.unpack( self.__stream[:24]) else: skip = 8 else: self.__intel = constants.INTELLIGENCE_DUMB if skip == None: # This section of the skip handling is not very good. # While it does work, it is likely to create extra # properties that are created from the properties file's # header data. While that won't actually mess anything # up, it is far from ideal. Basically, this is the dumb # skip length calculation. Preferably, we want the type # to have been specified so all of the additional fields # will have been filled out skip = self.__len % 16 if skip == 0: skip = 32 streams = divide(self.__stream[skip:], 16) for st in streams: a = create_prop(st) self.__props[a.name] = a self.__pl = len(self.__props)
def __init__(self, stream, type=None, skip=None): object.__init__(self) self.__stream = stream self.__pos = 0 self.__len = len(stream) self.__props = {} self.__naid = None self.__nrid = None self.__ac = None self.__rc = None if type is not None: self.__intel = constants.INTELLIGENCE_SMART if type == constants.TYPE_MESSAGE: skip = 32 self.__naid, self.__nrid, self.__ac, self.__rc = constants.ST1.unpack(self.__stream[:24]) elif type == constants.TYPE_MESSAGE_EMBED: skip = 24 self.__naid, self.__nrid, self.__ac, self.__rc = constants.ST1.unpack(self.__stream[:24]) else: skip = 8 else: self.__intel = constants.INTELLIGENCE_DUMB if skip is None: # This section of the skip handling is not very good. # While it does work, it is likely to create extra # properties that are created from the properties file's # header data. While that won't actually mess anything # up, it is far from ideal. Basically, this is the dumb # skip length calculation. Preferably, we want the type # to have been specified so all of the additional fields # will have been filled out skip = self.__len % 16 if skip == 0: skip = 32 streams = divide(self.__stream[skip:], 16) for st in streams: a = create_prop(st) self.__props[a.name] = a self.__pl = len(self.__props)
def _getTypedStream(self, filename, prefix=True, _type=None): """ Gets the contents of the specified stream as the type that it is supposed to be. Rather than the full filename, you should only feed this function the filename sans the type. So if the full name is "__substg1.0_001A001F", the filename this function should receive should be "__substg1.0_001A". If you know for sure what type the stream is before hand, you can specify it as being one of the strings in the constant FIXED_LENGTH_PROPS_STRING or VARIABLE_LENGTH_PROPS_STRING. If you have not specified the type, the type this function returns in many cases cannot be predicted. As such, when using this function it is best for you to check the type that it returns. If the function returns None, that means it could not find the stream specified. """ verifyType(_type) filename = self.fix_path(filename, prefix) for x in (filename + _type, ) if _type is not None else self.slistDir(): if x.startswith(filename) and x.find('-') == -1: contents = self._getStream(x, False) if len(contents) == 0: return True, None # We found the file, but it was empty. extras = [] _type = x[-4:] if x[-4] == '1': # It's a multiple if _type in ('101F', '101E'): streams = len( contents) // 4 # These lengths are normal. elif _type == '1102': streams = len( contents ) // 8 # These lengths have 4 0x00 bytes at the end for seemingly no reason. They are "reserved" bytes elif _type in ('1002', '1003', '1004', '1005', '1007', '1040', '1048'): try: streams = self.mainProperties[x[-8:]].realLength except: logger.error( 'Could not find matching VariableLengthProp for stream {}' .format(x)) streams = len(contents) // ( 2 if _type == '1002' else 4 if _type in ('1003', '1004') else 8 if type in ('1005', '1007', '1040') else 16) else: raise NotImplementedError( 'The stream specified is of type {}. We don\'t currently understand exactly how this type works. If it is mandatory that you have the contents of this stream, please create an issue labled "NotImplementedError: _getTypedStream {}".' .format(_type, _type)) if _type in ('101F', '101E', '1102'): if self.Exists(x + '-00000000', False): for y in range(streams): if self.Exists(x + '-' + properHex(y, 8), False): extras.append( self._getStream( x + '-' + properHex(y, 8), False)) elif _type in ('1002', '1003', '1004', '1005', '1007', '1040', '1048'): extras = divide( contents, (2 if _type == '1002' else 4 if _type in ( '1003', '1004') else 8 if type in ('1005', '1007', '1040') else 16)) contents = streams return True, parseType(int(_type, 16), contents, self.stringEncoding, extras) return False, None # We didn't find the stream.