Example #1
0
 def date(self):
     """
     Returns the send date contained in the Properties file.
     """
     try:
         return self.__date
     except AttributeError:
         if self.has_key('00390040'):
             self.__date = fromTimeStamp(msgEpoch(self.get('00390040').value)).__format__(
                 '%a, %d %b %Y %H:%M:%S %z')
         elif self.has_key('30080040'):
             self.__date = fromTimeStamp(msgEpoch(self.get('30080040').value)).__format__(
                 '%a, %d %b %Y %H:%M:%S %z')
         elif self.has_key('30070040'):
             self.__date = fromTimeStamp(msgEpoch(self.get('30070040').value)).__format__(
                 '%a, %d %b %Y %H:%M:%S %z')
         else:
             # DEBUG
             logger.warning(
                 'Error retrieving date. Setting as "Unknown". Please send the following data to developer:\n--------------------')
             logger.warning(properHex(self.__stream))
             logger.warning(self.keys())
             logger.warning('--------------------')
             self.__date = 'Unknown'
         return self.__date
Example #2
0
 def date(self):
     """
     Returns the send date contained in the Properties file.
     """
     try:
         return self.__date
     except AttributeError:
         if self.has_key('00390040'):
             self.__date = fromTimeStamp(
                 msgEpoch(self.get('00390040').value)).__format__(
                     '%a, %d %b %Y %H:%M:%S GMT %z')
         elif self.has_key('30080040'):
             self.__date = fromTimeStamp(
                 msgEpoch(self.get('30080040').value)).__format__(
                     '%a, %d %b %Y %H:%M:%S GMT %z')
         elif self.has_key('30070040'):
             self.__date = fromTimeStamp(
                 msgEpoch(self.get('30070040').value)).__format__(
                     '%a, %d %b %Y %H:%M:%S GMT %z')
         else:
             # DEBUG
             print(
                 'Warning: Error retrieving date. Setting as "Unknown". Please send the following data to developer:\n--------------------'
             )
             print(properHex(self.__stream))
             print(self.keys())
             print('--------------------')
             self.__date = 'Unknown'
         return self.__date
Example #3
0
    def __init__(self, msg, dir_):
        """
        :param msg: the Message instance that the attachment belongs to.
        :param dir_: the directory inside the msg file where the attachment is located.
        """
        object.__init__(self)
        self.__msg = msg
        self.__dir = dir_
        self.__props = Properties(
            msg._getStream([self.__dir, '__properties_version1.0']),
            constants.TYPE_ATTACHMENT)

        # Get attachment data
        if msg.Exists([dir_, '__substg1.0_37010102']):
            self.__type = 'data'
            self.__data = msg._getStream([dir_, '__substg1.0_37010102'])
        elif msg.Exists([dir_, '__substg1.0_3701000D']):
            if (self.__props['37050003'].value & 0x7) != 0x5:
                logger.log(5, 'Printing details of NotImplementedError...')
                logger.log(5, 'dir_ = {}'.format(dir_))
                logger.log(5, 'Writing properties stream to output:')
                logger.log(5, '--------Start-Properties-Stream--------\n' +
                              properHex(self.__props.stream) +
                              '\n---------End-Properties-Stream---------')
                logger.log(5, 'Writing directory contents to output:')
                logger.log(5, '--------Start-Directory-Content--------\n' +
                              '\n'.join([repr(x) for x in msg.listDir(True, True)]))
                logger.log(5, '---------End-Directory-Content---------')
                logger.log(5, 'End of NotImplementedError details')
            else:
                self.__prefix = msg.prefixList + [dir_, '__substg1.0_3701000D']
                self.__type = 'msg'
                self.__data = msg.__class__(msg.path, self.__prefix)
        else:
            raise TypeError('Unknown attachment type.')
Example #4
0
 def date(self):
     """
     Returns the send date contained in the Properties file.
     """
     try:
         return self.__date
     except AttributeError:
         if self.has_key('00390040'):
             self.__date = self.get('00390040').value.__format__(
                 '%a, %d %b %Y %H:%M:%S %z')
         elif self.has_key('30080040'):
             self.__date = self.get('30080040').value.__format__(
                 '%a, %d %b %Y %H:%M:%S %z')
         elif self.has_key('30070040'):
             self.__date = self.get('30070040').value.__format__(
                 '%a, %d %b %Y %H:%M:%S %z')
         else:
             # DEBUG
             logger.warning(
                 'Error retrieving date. Setting as "Unknown". Please send the following data to developer:\n--------------------'
             )
             logger.warning(properHex(self.__stream))
             logger.warning(self.keys())
             logger.warning('--------------------')
             self.__date = 'Unknown'
         return self.__date
Example #5
0
 def __init__(self, entry, data):
     super(NumericalNamedProperty, self).__init__()
     self.__propertyID = properHex(entry['id'], 4).upper()
     self.__guidIndex = entry['guid_index']
     self.__namedPropertyID = entry['pid']
     self.__streamID = 0x1000 + (entry['id'] ^ (self.__guidIndex << 1)) % 0x1F
     self.__data = data
Example #6
0
 def __init__(self, string):
     super(PropBase, self).__init__()
     self.__raw = string
     self.__name = properHex(string[3::-1]).upper()
     self.__type, self.__flags = constants.ST2.unpack(string)
     self.__fm = self.__flags & 1 == 1
     self.__fr = self.__flags & 2 == 2
     self.__fw = self.__flags & 4 == 4
Example #7
0
 def __init__(self, string):
     super(PropBase, self).__init__()
     self.__raw = string
     self.__name = properHex(string[3::-1]).upper()
     self.__type, self.__flags = constants.ST2.unpack(string)
     self.__fm = self.__flags & 1 == 1
     self.__fr = self.__flags & 2 == 2
     self.__fw = self.__flags & 4 == 4
Example #8
0
def create_prop(string):
    temp = constants.ST2.unpack(string)[0]
    if temp in constants.FIXED_LENGTH_PROPS:
        return FixedLengthProp(string)
    else:
        if temp not in constants.VARIABLE_LENGTH_PROPS:
            # DEBUG
            logger.warning('Unknown property type: {}'.format(properHex(temp)))
        return VariableLengthProp(string)
Example #9
0
def create_prop(string):
    temp = constants.ST2.unpack(string)[0]
    if temp in constants.FIXED_LENGTH_PROPS:
        return FixedLengthProp(string)
    else:
        if temp not in constants.VARIABLE_LENGTH_PROPS:
            # DEBUG
            logger.warning('Unknown property type: {}'.format(properHex(temp)))
        return VariableLengthProp(string)
Example #10
0
 def defineProperty(self, entry, _type, name = None):
     """
     Informs the class of a named property that needs to be loaded.
     """
     streamID = properHex(0x8000 + entry['pid']).upper()
     if self.__attachment.ExistsTypedProperty(streamID)[0]:
         data = self.__attachment._getTypedData(streamID)
         property = StringNamedProperty(entry, name, data) if _type == constants.STRING_NAMED else NumericalNamedProperty(entry, data)
         self.__properties.append(property)
         self.__propertiesDict[property.name if isinstance(property, StringNamedProperty) else property.propertyID] = property
Example #11
0
    def __init__(self, msg, dir_):
        """
        :param msg: the Message instance that the attachment belongs to.
        :param dir_: the directory inside the msg file where the attachment is located.
        """
        object.__init__(self)
        self.__msg = msg
        self.__dir = dir_
        self.__props = Properties(
            self.msg._getStream(self.msg.prefixList +
                                [self.__dir, '__properties_version1.0']),
            constants.TYPE_ATTACHMENT)
        # Get long filename
        self.__longFilename = msg._getStringStream([dir_, '__substg1.0_3707'])

        # Get short filename
        self.__shortFilename = msg._getStringStream([dir_, '__substg1.0_3704'])

        # Get Content-ID
        self.__cid = msg._getStringStream([dir_, '__substg1.0_3712'])

        # Get attachment data
        if msg.Exists([dir_, '__substg1.0_37010102']):
            self.__type = 'data'
            self.__data = msg._getStream([dir_, '__substg1.0_37010102'])
        elif msg.Exists([dir_, '__substg1.0_3701000D']):
            if (self.props['37050003'].value & 0x7) != 0x5:
                if not debug:
                    raise NotImplementedError(
                        'Current version of extract_msg does not support extraction of containers that are not embeded msg files.'
                    )
                    # TODO add implementation
                else:
                    # DEBUG
                    print(
                        'DEBUG: Debugging is true, ignoring NotImplementedError and printing debug info...'
                    )
                    print('DEBUG: _dir = {}'.format(_dir))
                    print('DEBUG: Writing properties stream to output:')
                    print('DEBUG: --------Start-Properties-Stream--------')
                    print(properHex(self.props.stream))
                    print('DEBUG: ---------End-Properties-Stream---------')
                    print('DEBUG: Writing directory contents to output:')
                    print('DEBUG: --------Start-Directory-Content--------')
                    for x in msg.listDir(True, True):
                        print(x)
                    print('DEBUG: ---------End-Directory-Content---------')
            else:
                self.__prefix = msg.prefixList + [dir_, '__substg1.0_3701000D']
                self.__type = 'msg'
                self.__data = msg.__class__(self.msg.path, self.__prefix,
                                            self.__class__)
        else:
            raise TypeError('Unknown attachment type.')
Example #12
0
 def get(self, name):
     """
     Retrieve the property of :param name:.
     """
     try:
         return self.__props[name]
     except KeyError:
         # DEBUG
         logger.debug('KeyError exception.')
         logger.debug(properHex(self.__stream))
         logger.debug(self.__props)
         raise
Example #13
0
 def get(self, name):
     """
     Retrieve the property of :param name:.
     """
     try:
         return self.__props[name]
     except KeyError:
         # DEBUG
         logger.debug('KeyError exception.')
         logger.debug(properHex(self.__stream))
         logger.debug(self.__props)
         raise
Example #14
0
 def get(self, name):
     """
     Retrieve the property of :param name:.
     """
     try:
         return self.__props[name]
     except KeyError:
         if debug:
             # DEBUG
             print('DEBUG:')
             print(properHex(self.__stream))
             print(self.__props)
         raise
Example #15
0
    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
Example #16
0
    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.