Source code for extract_msg.attachments.emb_msg_att

from __future__ import annotations


__all__ = [
    'EmbeddedMsgAttachment',
]


import os
import pathlib
import zipfile

from typing import TYPE_CHECKING

from .. import constants
from .attachment_base import AttachmentBase
from ..enums import AttachmentType, SaveType
from ..open_msg import openMsg
from ..utils import createZipOpen, prepareFilename


if TYPE_CHECKING:
    from ..msg_classes import MSGFile
    from ..properties import PropertiesStore


_saveDoc = AttachmentBase.save.__doc__


[docs]class EmbeddedMsgAttachment(AttachmentBase): """ The attachment entry for an Embedded MSG file. """ def __init__(self, msg: MSGFile, dir_: str, propStore: PropertiesStore): super().__init__(msg, dir_, propStore) self.__prefix = msg.prefixList + [dir_, '__substg1.0_3701000D'] self.__data = openMsg(self.msg.path, prefix = self.__prefix, parentMsg = self.msg, treePath = self.treePath, **self.msg.kwargs)
[docs] def getFilename(self, **kwargs) -> str: """ Returns the filename to use for the attachment. :param contentId: Use the contentId, if available. :param customFilename: A custom name to use for the file. If the filename starts with "UnknownFilename" then there is no guarantee that the files will have exactly the same filename. """ customFilename = kwargs.get('customFilename') if customFilename: customFilename = str(customFilename) # First we need to validate it. If there are invalid characters, # this will detect it. if constants.re.INVALID_FILENAME_CHARS.search(customFilename): raise ValueError('Invalid character found in customFilename. Must not contain any of the following characters: \\/:*?"<>|') return customFilename else: return self.name
[docs] def save(self, **kwargs) -> constants.SAVE_TYPE: # First check if we are skipping embedded messages and stop # *immediately* if we are. if kwargs.get('skipEmbedded'): return (SaveType.NONE, None) # We only need to handle things if we are saving as bytes. if kwargs.get('extractEmbedded', False): # Get the filename to use. filename = self.getFilename(**kwargs) # Someone managed to have a null character here, so let's get rid of # that filename = prepareFilename(filename) # Get the maximum name length. maxNameLength = kwargs.get('maxNameLength', 256) # Make sure the filename is not longer than it should be. if len(filename) > maxNameLength: name, ext = os.path.splitext(filename) filename = name[:maxNameLength - len(ext)] + ext # Check if we are doing a zip file. _zip = kwargs.get('zip') createdZip = False try: # ZipFile handling. if _zip: # If we are doing a zip file, first check that we have been given a path. if isinstance(_zip, (str, pathlib.Path)): # If we have a path then we use the zip file. _zip = zipfile.ZipFile(_zip, 'a', zipfile.ZIP_DEFLATED) kwargs['zip'] = _zip createdZip = True # Path needs to be done in a special way if we are in a zip file. customPath = pathlib.Path(kwargs.get('customPath', '')) # Set the open command to be that of the zip file. _open = createZipOpen(_zip.open) # Zip files use w for writing in binary. mode = 'w' else: customPath = pathlib.Path(kwargs.get('customPath', '.')).absolute() mode = 'wb' _open = open fullFilename = self._handleFnc(_zip, filename, customPath, kwargs) with _open(str(fullFilename), mode) as f: self.data.export(f) return (SaveType.FILE, str(fullFilename)) finally: # Close the ZipFile if this function created it. if _zip and createdZip: _zip.close() else: # If we are letting the MSG file create stuff, just let it handle # everything. return self.data.save(**kwargs)
save.__doc__ = _saveDoc @property def data(self) -> MSGFile: """ Returns the attachment data. """ return self.__data @property def type(self) -> AttachmentType: return AttachmentType.MSG