extract-msg 0.47.0__tar.gz → 0.48.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {extract_msg-0.47.0 → extract_msg-0.48.1}/CHANGELOG.md +16 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/PKG-INFO +5 -4
- {extract_msg-0.47.0 → extract_msg-0.48.1}/README.rst +4 -3
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/__init__.py +2 -2
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/__main__.py +4 -3
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/attachments/attachment_base.py +56 -23
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/encoding/utils.py +1 -1
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/enums.py +6 -1
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/msg_classes/message_signed_base.py +30 -9
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/msg_classes/msg.py +2 -2
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/ole_writer.py +69 -25
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/properties/named.py +41 -6
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/properties/properties_store.py +1 -1
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/structures/cfoas.py +4 -4
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/structures/entry_id.py +1 -1
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/structures/ole_pres.py +8 -8
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/structures/ole_stream_struct.py +2 -2
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/structures/recurrence_pattern.py +2 -2
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/structures/report_tag.py +3 -3
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/utils.py +24 -13
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg.egg-info/PKG-INFO +5 -4
- {extract_msg-0.47.0 → extract_msg-0.48.1}/LICENSE.txt +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/MANIFEST.in +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/_rtf/__init__.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/_rtf/create_doc.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/_rtf/inject_rtf.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/_rtf/token.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/_rtf/tokenize_rtf.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/attachments/__init__.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/attachments/attachment.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/attachments/broken_att.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/attachments/custom_att.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/attachments/custom_att_handler/__init__.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/attachments/custom_att_handler/custom_handler.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/attachments/custom_att_handler/lnk_obj_att.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/attachments/custom_att_handler/outlook_image_dib.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/attachments/emb_msg_att.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/attachments/signed_att.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/attachments/unsupported_att.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/attachments/web_att.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/constants/__init__.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/constants/ps.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/constants/re.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/constants/st.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/data/logging-config/logging-nt.json +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/data/logging-config/logging-posix.json +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/encoding/__init__.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/encoding/_dt/__init__.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/encoding/_dt/_mac_ce.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/encoding/_dt/_mac_cyrillic.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/encoding/_dt/_mac_greek.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/encoding/_dt/_mac_iceland.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/encoding/_dt/_mac_turkish.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/encoding/_dt/_win874_dec.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/encoding/_dt/_win950_dec.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/exceptions.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/msg_classes/__init__.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/msg_classes/appointment.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/msg_classes/calendar.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/msg_classes/calendar_base.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/msg_classes/contact.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/msg_classes/journal.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/msg_classes/meeting_cancellation.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/msg_classes/meeting_exception.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/msg_classes/meeting_forward.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/msg_classes/meeting_related.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/msg_classes/meeting_request.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/msg_classes/meeting_response.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/msg_classes/message.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/msg_classes/message_base.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/msg_classes/message_signed.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/msg_classes/post.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/msg_classes/sticky_note.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/msg_classes/task.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/msg_classes/task_request.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/null_date.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/open_msg.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/properties/__init__.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/properties/prop.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/py.typed +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/recipient.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/structures/__init__.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/structures/_helpers.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/structures/business_card.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/structures/contact_link_entry.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/structures/dev_mode_a.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/structures/dv_target_device.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/structures/misc_id.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/structures/mon_stream.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/structures/odt.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/structures/system_time.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/structures/time_zone_definition.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/structures/time_zone_struct.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/structures/toc_entry.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg/structures/tz_rule.py +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg.egg-info/SOURCES.txt +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg.egg-info/dependency_links.txt +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg.egg-info/entry_points.txt +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg.egg-info/requires.txt +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/extract_msg.egg-info/top_level.txt +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/requirements.txt +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/setup.cfg +0 -0
- {extract_msg-0.47.0 → extract_msg-0.48.1}/setup.py +0 -0
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
**v0.48.1**
|
|
2
|
+
* Added an option (`-s`, `--stdin`) to the command line to take an MSG file from stdin. This allows the user to pipe the MSG data from another program directly instead of having to write a middleman that uses the `extract-msg` library directly or having to write the file to the disk first.
|
|
3
|
+
* Changed main function to allow for manual argument list to be passed to it.
|
|
4
|
+
* Added attributes to `AttachmentBase` for creation and modification time. These can be accessed through `createdAt` or `creationTime` and `lastModificationTime` or `modifiedAt`.
|
|
5
|
+
* Changed `OleWriter` tests to output the name of the test file being done if an error occurs.
|
|
6
|
+
* Added tests for some command line stuff.
|
|
7
|
+
|
|
8
|
+
**v0.48.0**
|
|
9
|
+
* Adjusted error handling for named properties to handle critical streams being missing and to allow suppression of those errors.
|
|
10
|
+
* Adjusted error handling for named properties to allow silencing of errors caused by invalid references to the name stream. If `ErrorBehavior.NAMED_NAME_STREAM` is provided to the `MSGFile` instance, a warning will be logged and that entry will simply be dropped.
|
|
11
|
+
* Adjusted error handling for signed messages to better check for issues with the signed attachment. This should make errors from violating the standard much easier to understand. These errors can be ignored, but the attachment will *not* be parsed as a signed attachment.
|
|
12
|
+
* Minor docstring updates.
|
|
13
|
+
* Minor adjustments to `OleWriter` to prepare the code for being able to write version 4 files. Version 3 files are currently the only one's supported, but much of the code had hard-coded values that could be replaced with variables and small conditionals. This will have very little performance impact, and should not be noticeable.
|
|
14
|
+
* Improved comments on `OleWriter` to make private sections more understandable.
|
|
15
|
+
* Changed `MessageSignedBase._rawAttachments` to `MessageSignedBase.rawAttachments` to provide non-private access in a reliable way.
|
|
16
|
+
|
|
1
17
|
**v0.47.0**
|
|
2
18
|
* Changed the public API for `PropertiesStore` to improve the quality of its code. The properties type is now mandatory, and the intelligence field (and the related enum) has been removed.
|
|
3
19
|
* Additionally, the `toBytes` and `__bytes__` methods will both generate based on the contents of this class, allowing for new properties to be created and for existing properties to be modified or removed if the class is set to writable on creation.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: extract_msg
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.48.1
|
|
4
4
|
Summary: Extracts emails and attachments saved in Microsoft Outlook's .msg files
|
|
5
5
|
Home-page: https://github.com/TeamMsgExtractor/msg-extractor
|
|
6
6
|
Download-URL: https://github.com/TeamMsgExtractor/msg-extractor/archives/master
|
|
@@ -79,7 +79,7 @@ refer to the usage information provided from the program's help dialog:
|
|
|
79
79
|
|
|
80
80
|
usage: extract_msg [-h] [--use-content-id] [--json] [--file-logging] [-v] [--log LOG] [--config CONFIGPATH] [--out OUTPATH] [--use-filename] [--dump-stdout] [--html] [--pdf] [--wk-path WKPATH] [--wk-options [WKOPTIONS ...]]
|
|
81
81
|
[--prepared-html] [--charset CHARSET] [--raw] [--rtf] [--allow-fallback] [--skip-body-not-found] [--zip ZIP] [--save-header] [--attachments-only] [--skip-hidden] [--no-folders] [--skip-embedded] [--extract-embedded]
|
|
82
|
-
[--overwrite-existing] [--skip-not-implemented] [--out-name OUTNAME | --glob] [--ignore-rtfde] [--progress]
|
|
82
|
+
[--overwrite-existing] [--skip-not-implemented] [--out-name OUTNAME | --glob] [--ignore-rtfde] [--progress] [-s]
|
|
83
83
|
msg [msg ...]
|
|
84
84
|
|
|
85
85
|
extract_msg: Extracts emails and attachments saved in Microsoft Outlook's .msg files. https://github.com/TeamMsgExtractor/msg-extractor
|
|
@@ -125,6 +125,7 @@ refer to the usage information provided from the program's help dialog:
|
|
|
125
125
|
--glob, --wildcard Interpret all paths as having wildcards. Incompatible with --out-name.
|
|
126
126
|
--ignore-rtfde Ignores all errors thrown from RTFDE when trying to save. Useful for allowing fallback to continue when an exception happens.
|
|
127
127
|
--progress Shows what file the program is currently working on during it's progress.
|
|
128
|
+
-s, --stdin Read file from stdin (only works with one file at a time).
|
|
128
129
|
|
|
129
130
|
**To use this in your own script**, start by using:
|
|
130
131
|
|
|
@@ -277,8 +278,8 @@ your access to the newest major version of extract-msg.
|
|
|
277
278
|
.. |License: GPL v3| image:: https://img.shields.io/badge/License-GPLv3-blue.svg
|
|
278
279
|
:target: LICENSE.txt
|
|
279
280
|
|
|
280
|
-
.. |PyPI3| image:: https://img.shields.io/badge/pypi-0.
|
|
281
|
-
:target: https://pypi.org/project/extract-msg/0.
|
|
281
|
+
.. |PyPI3| image:: https://img.shields.io/badge/pypi-0.48.1-blue.svg
|
|
282
|
+
:target: https://pypi.org/project/extract-msg/0.48.1/
|
|
282
283
|
|
|
283
284
|
.. |PyPI2| image:: https://img.shields.io/badge/python-3.8+-brightgreen.svg
|
|
284
285
|
:target: https://www.python.org/downloads/release/python-3810/
|
|
@@ -61,7 +61,7 @@ refer to the usage information provided from the program's help dialog:
|
|
|
61
61
|
|
|
62
62
|
usage: extract_msg [-h] [--use-content-id] [--json] [--file-logging] [-v] [--log LOG] [--config CONFIGPATH] [--out OUTPATH] [--use-filename] [--dump-stdout] [--html] [--pdf] [--wk-path WKPATH] [--wk-options [WKOPTIONS ...]]
|
|
63
63
|
[--prepared-html] [--charset CHARSET] [--raw] [--rtf] [--allow-fallback] [--skip-body-not-found] [--zip ZIP] [--save-header] [--attachments-only] [--skip-hidden] [--no-folders] [--skip-embedded] [--extract-embedded]
|
|
64
|
-
[--overwrite-existing] [--skip-not-implemented] [--out-name OUTNAME | --glob] [--ignore-rtfde] [--progress]
|
|
64
|
+
[--overwrite-existing] [--skip-not-implemented] [--out-name OUTNAME | --glob] [--ignore-rtfde] [--progress] [-s]
|
|
65
65
|
msg [msg ...]
|
|
66
66
|
|
|
67
67
|
extract_msg: Extracts emails and attachments saved in Microsoft Outlook's .msg files. https://github.com/TeamMsgExtractor/msg-extractor
|
|
@@ -107,6 +107,7 @@ refer to the usage information provided from the program's help dialog:
|
|
|
107
107
|
--glob, --wildcard Interpret all paths as having wildcards. Incompatible with --out-name.
|
|
108
108
|
--ignore-rtfde Ignores all errors thrown from RTFDE when trying to save. Useful for allowing fallback to continue when an exception happens.
|
|
109
109
|
--progress Shows what file the program is currently working on during it's progress.
|
|
110
|
+
-s, --stdin Read file from stdin (only works with one file at a time).
|
|
110
111
|
|
|
111
112
|
**To use this in your own script**, start by using:
|
|
112
113
|
|
|
@@ -259,8 +260,8 @@ your access to the newest major version of extract-msg.
|
|
|
259
260
|
.. |License: GPL v3| image:: https://img.shields.io/badge/License-GPLv3-blue.svg
|
|
260
261
|
:target: LICENSE.txt
|
|
261
262
|
|
|
262
|
-
.. |PyPI3| image:: https://img.shields.io/badge/pypi-0.
|
|
263
|
-
:target: https://pypi.org/project/extract-msg/0.
|
|
263
|
+
.. |PyPI3| image:: https://img.shields.io/badge/pypi-0.48.1-blue.svg
|
|
264
|
+
:target: https://pypi.org/project/extract-msg/0.48.1/
|
|
264
265
|
|
|
265
266
|
.. |PyPI2| image:: https://img.shields.io/badge/python-3.8+-brightgreen.svg
|
|
266
267
|
:target: https://www.python.org/downloads/release/python-3810/
|
|
@@ -27,8 +27,8 @@ https://github.com/TeamMsgExtractor/msg-extractor
|
|
|
27
27
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
28
28
|
|
|
29
29
|
__author__ = 'Destiny Peterson & Matthew Walker'
|
|
30
|
-
__date__ = '
|
|
31
|
-
__version__ = '0.
|
|
30
|
+
__date__ = '2024-03-08'
|
|
31
|
+
__version__ = '0.48.1'
|
|
32
32
|
|
|
33
33
|
__all__ = [
|
|
34
34
|
# Modules:
|
|
@@ -10,12 +10,13 @@ import zipfile
|
|
|
10
10
|
|
|
11
11
|
from extract_msg import __doc__, openMsg, utils
|
|
12
12
|
from extract_msg.enums import ErrorBehavior
|
|
13
|
+
from typing import List
|
|
13
14
|
|
|
14
15
|
|
|
15
|
-
def main() -> None:
|
|
16
|
+
def main(argv : List[str]) -> None:
|
|
16
17
|
# Setup logging to stdout, indicate running from cli
|
|
17
18
|
CLI_LOGGING = 'extract_msg_cli'
|
|
18
|
-
args = utils.getCommandArgs(
|
|
19
|
+
args = utils.getCommandArgs(argv[1:])
|
|
19
20
|
|
|
20
21
|
# Determine where to save the files to.
|
|
21
22
|
currentDir = os.getcwd() # Store this in case the path changes.
|
|
@@ -111,4 +112,4 @@ def main() -> None:
|
|
|
111
112
|
_zip.close()
|
|
112
113
|
|
|
113
114
|
if __name__ == '__main__':
|
|
114
|
-
main()
|
|
115
|
+
main(sys.argv)
|
|
@@ -290,7 +290,7 @@ class AttachmentBase(abc.ABC):
|
|
|
290
290
|
|
|
291
291
|
def getNamedProp(self, propertyName: str, guid: str, default: _T = None) -> Union[Any, _T]:
|
|
292
292
|
"""
|
|
293
|
-
instance.namedProperties.get((propertyName, guid), default)
|
|
293
|
+
``instance.namedProperties.get((propertyName, guid), default)``
|
|
294
294
|
|
|
295
295
|
Can be overriden to create new behavior.
|
|
296
296
|
"""
|
|
@@ -400,7 +400,7 @@ class AttachmentBase(abc.ABC):
|
|
|
400
400
|
the filename this function should receive should be "__substg1.0_001A".
|
|
401
401
|
|
|
402
402
|
This should ALWAYS return a string if it was found, otherwise returns
|
|
403
|
-
None
|
|
403
|
+
``None``.
|
|
404
404
|
|
|
405
405
|
:raises ReferenceError: The associated ``MSGFile`` instance has been
|
|
406
406
|
garbage collected.
|
|
@@ -415,10 +415,11 @@ class AttachmentBase(abc.ABC):
|
|
|
415
415
|
class if it is found.
|
|
416
416
|
|
|
417
417
|
:param overrideClass: Class/function to use to morph the data that was
|
|
418
|
-
read. The data will be the first argument to the class's
|
|
419
|
-
|
|
420
|
-
the value is None
|
|
421
|
-
be called regardless, you should handle the data
|
|
418
|
+
read. The data will be the first argument to the class's
|
|
419
|
+
``__init__`` method or the function itself, if that is what is
|
|
420
|
+
provided. If the value is ``None``, this function is not called. If
|
|
421
|
+
you want it to be called regardless, you should handle the data
|
|
422
|
+
directly.
|
|
422
423
|
"""
|
|
423
424
|
value = self.getStream(streamID)
|
|
424
425
|
|
|
@@ -472,7 +473,7 @@ class AttachmentBase(abc.ABC):
|
|
|
472
473
|
the first item specifies what the second value will be.
|
|
473
474
|
"""
|
|
474
475
|
|
|
475
|
-
@
|
|
476
|
+
@cached_property
|
|
476
477
|
def attachmentEncoding(self) -> Optional[bytes]:
|
|
477
478
|
"""
|
|
478
479
|
The encoding information about the attachment object.
|
|
@@ -482,7 +483,7 @@ class AttachmentBase(abc.ABC):
|
|
|
482
483
|
"""
|
|
483
484
|
return self.getStream('__substg1.0_37020102')
|
|
484
485
|
|
|
485
|
-
@
|
|
486
|
+
@cached_property
|
|
486
487
|
def additionalInformation(self) -> Optional[str]:
|
|
487
488
|
"""
|
|
488
489
|
The additional information about the attachment.
|
|
@@ -494,7 +495,7 @@ class AttachmentBase(abc.ABC):
|
|
|
494
495
|
"""
|
|
495
496
|
return self.getStringStream('__substg1.0_370F')
|
|
496
497
|
|
|
497
|
-
@
|
|
498
|
+
@cached_property
|
|
498
499
|
def cid(self) -> Optional[str]:
|
|
499
500
|
"""
|
|
500
501
|
Returns the Content ID of the attachment, if it exists.
|
|
@@ -525,8 +526,25 @@ class AttachmentBase(abc.ABC):
|
|
|
525
526
|
|
|
526
527
|
@property
|
|
527
528
|
def contentId(self) -> Optional[str]:
|
|
529
|
+
"""
|
|
530
|
+
Alias of :attr:`cid`.
|
|
531
|
+
"""
|
|
528
532
|
return self.cid
|
|
529
533
|
|
|
534
|
+
@property
|
|
535
|
+
def createdAt(self) -> Optional[datetime.datetime]:
|
|
536
|
+
"""
|
|
537
|
+
Alias of :attr:`creationTime`.
|
|
538
|
+
"""
|
|
539
|
+
return self.creationTime
|
|
540
|
+
|
|
541
|
+
@cached_property
|
|
542
|
+
def creationTime(self) -> Optional[datetime.datetime]:
|
|
543
|
+
"""
|
|
544
|
+
The time the attachment was created.
|
|
545
|
+
"""
|
|
546
|
+
return self.getPropertyVal('30070040')
|
|
547
|
+
|
|
530
548
|
@property
|
|
531
549
|
@abc.abstractmethod
|
|
532
550
|
def data(self) -> Optional[object]:
|
|
@@ -536,7 +554,7 @@ class AttachmentBase(abc.ABC):
|
|
|
536
554
|
Returns ``None`` if there is no data to save.
|
|
537
555
|
"""
|
|
538
556
|
|
|
539
|
-
@
|
|
557
|
+
@cached_property
|
|
540
558
|
def dataType(self) -> Optional[Type[object]]:
|
|
541
559
|
"""
|
|
542
560
|
The class that the data type will use, if it can be retrieved.
|
|
@@ -559,14 +577,14 @@ class AttachmentBase(abc.ABC):
|
|
|
559
577
|
"""
|
|
560
578
|
return self.__dir
|
|
561
579
|
|
|
562
|
-
@
|
|
580
|
+
@cached_property
|
|
563
581
|
def displayName(self) -> Optional[str]:
|
|
564
582
|
"""
|
|
565
583
|
Returns the display name of the folder.
|
|
566
584
|
"""
|
|
567
585
|
return self.getStringStream('__substg1.0_3001')
|
|
568
586
|
|
|
569
|
-
@
|
|
587
|
+
@cached_property
|
|
570
588
|
def exceptionReplaceTime(self) -> Optional[datetime.datetime]:
|
|
571
589
|
"""
|
|
572
590
|
The original date and time at which the instance in the recurrence
|
|
@@ -576,48 +594,62 @@ class AttachmentBase(abc.ABC):
|
|
|
576
594
|
"""
|
|
577
595
|
return self.getPropertyVal('7FF90040')
|
|
578
596
|
|
|
579
|
-
@
|
|
597
|
+
@cached_property
|
|
580
598
|
def extension(self) -> Optional[str]:
|
|
581
599
|
"""
|
|
582
600
|
The reported extension for the file.
|
|
583
601
|
"""
|
|
584
602
|
return self.getStringStream('__substg1.0_3703')
|
|
585
603
|
|
|
586
|
-
@
|
|
604
|
+
@cached_property
|
|
587
605
|
def hidden(self) -> bool:
|
|
588
606
|
"""
|
|
589
607
|
Indicates whether an Attachment object is hidden from the end user.
|
|
590
608
|
"""
|
|
591
609
|
return bool(self.getPropertyVal('7FFE000B'))
|
|
592
610
|
|
|
593
|
-
@
|
|
611
|
+
@cached_property
|
|
594
612
|
def isAttachmentContactPhoto(self) -> bool:
|
|
595
613
|
"""
|
|
596
614
|
Whether the attachment is a contact photo for a Contact object.
|
|
597
615
|
"""
|
|
598
616
|
return bool(self.getPropertyVal('7FFF000B'))
|
|
599
617
|
|
|
600
|
-
@
|
|
618
|
+
@cached_property
|
|
619
|
+
def lastModificationTime(self) -> Optional[datetime.datetime]:
|
|
620
|
+
"""
|
|
621
|
+
The last time the attachment was modified.
|
|
622
|
+
"""
|
|
623
|
+
return self.getPropertyVal('30080040')
|
|
624
|
+
|
|
625
|
+
@cached_property
|
|
601
626
|
def longFilename(self) -> Optional[str]:
|
|
602
627
|
"""
|
|
603
628
|
Returns the long file name of the attachment, if it exists.
|
|
604
629
|
"""
|
|
605
630
|
return self.getStringStream('__substg1.0_3707')
|
|
606
631
|
|
|
607
|
-
@
|
|
632
|
+
@cached_property
|
|
608
633
|
def longPathname(self) -> Optional[str]:
|
|
609
634
|
"""
|
|
610
635
|
The fully qualified path and file name with extension.
|
|
611
636
|
"""
|
|
612
637
|
return self.getStringStream('__substg1.0_370D')
|
|
613
638
|
|
|
614
|
-
@
|
|
639
|
+
@cached_property
|
|
615
640
|
def mimetype(self) -> Optional[str]:
|
|
616
641
|
"""
|
|
617
642
|
The content-type mime header of the attachment, if specified.
|
|
618
643
|
"""
|
|
619
644
|
return tryGetMimetype(self, self.getStringStream('__substg1.0_370E'))
|
|
620
645
|
|
|
646
|
+
@property
|
|
647
|
+
def modifiedAt(self) -> Optional[datetime.datetime]:
|
|
648
|
+
"""
|
|
649
|
+
Alias of :attr:`lastModificationTime`.
|
|
650
|
+
"""
|
|
651
|
+
return self.lastModificationTime
|
|
652
|
+
|
|
621
653
|
@property
|
|
622
654
|
def msg(self) -> MSGFile:
|
|
623
655
|
"""
|
|
@@ -630,7 +662,7 @@ class AttachmentBase(abc.ABC):
|
|
|
630
662
|
raise ReferenceError('The MSGFile for this Attachment instance has been garbage collected.')
|
|
631
663
|
return msg
|
|
632
664
|
|
|
633
|
-
@
|
|
665
|
+
@cached_property
|
|
634
666
|
def name(self) -> Optional[str]:
|
|
635
667
|
"""
|
|
636
668
|
The best name available for the file.
|
|
@@ -649,7 +681,7 @@ class AttachmentBase(abc.ABC):
|
|
|
649
681
|
"""
|
|
650
682
|
return self.__namedProperties
|
|
651
683
|
|
|
652
|
-
@
|
|
684
|
+
@cached_property
|
|
653
685
|
def payloadClass(self) -> Optional[str]:
|
|
654
686
|
"""
|
|
655
687
|
The class name of an object that can display the contents of the
|
|
@@ -664,17 +696,18 @@ class AttachmentBase(abc.ABC):
|
|
|
664
696
|
"""
|
|
665
697
|
return self.__props
|
|
666
698
|
|
|
667
|
-
@
|
|
699
|
+
@cached_property
|
|
668
700
|
def renderingPosition(self) -> Optional[int]:
|
|
669
701
|
"""
|
|
670
702
|
The offset, in rendered characters, to use when rendering the attachment
|
|
671
703
|
within the main message text.
|
|
672
704
|
|
|
673
|
-
A value of 0xFFFFFFFF indicates a hidden attachment that is not to
|
|
705
|
+
A value of ``0xFFFFFFFF`` indicates a hidden attachment that is not to
|
|
706
|
+
be rendered.
|
|
674
707
|
"""
|
|
675
708
|
return self.getPropertyVal('370B0003')
|
|
676
709
|
|
|
677
|
-
@
|
|
710
|
+
@cached_property
|
|
678
711
|
def shortFilename(self) -> Optional[str]:
|
|
679
712
|
"""
|
|
680
713
|
The short file name of the attachment, if it exists.
|
|
@@ -202,7 +202,7 @@ def variableByteDecode(codecName: str, data, errors: str, decodeTable: Dict[int,
|
|
|
202
202
|
"""
|
|
203
203
|
Function for decoding variable-byte codecs that use one or two bytes per character.
|
|
204
204
|
|
|
205
|
-
Checks if a character is less than 0x80
|
|
205
|
+
Checks if a character is less than ``0x80``, mapping it directly if so.
|
|
206
206
|
Otherwise, it reads the next byte and combines the two before looking up the
|
|
207
207
|
new value.
|
|
208
208
|
|
|
@@ -674,6 +674,9 @@ class ErrorBehavior(enum.IntFlag):
|
|
|
674
674
|
* STANDARDS_VIOLATION: Silences StandardViolationError where acceptable.
|
|
675
675
|
* OLE_DEFECT_INCORRECT: Silences defects of type DEFECT_INCORRECT that are
|
|
676
676
|
enabled by default. This can lead to strange bugs.
|
|
677
|
+
* NAMED_NAME_STREAM: Silences errors caused by invalid indexes into the
|
|
678
|
+
name stream for named properties. Any properties with an invalid name will
|
|
679
|
+
simply be dropped.
|
|
677
680
|
* SUPPRESS_ALL: Silences all of the above.
|
|
678
681
|
"""
|
|
679
682
|
THROW = 0b000000
|
|
@@ -688,8 +691,10 @@ class ErrorBehavior(enum.IntFlag):
|
|
|
688
691
|
# General.
|
|
689
692
|
STANDARDS_VIOLATION = 0b010000
|
|
690
693
|
OLE_DEFECT_INCORRECT = 0b100000
|
|
694
|
+
# Named Properties
|
|
695
|
+
NAMED_NAME_STREAM = 0b1000000
|
|
691
696
|
|
|
692
|
-
SUPPRESS_ALL =
|
|
697
|
+
SUPPRESS_ALL = 0b1111111
|
|
693
698
|
|
|
694
699
|
|
|
695
700
|
|
|
@@ -11,7 +11,7 @@ import re
|
|
|
11
11
|
from typing import Generic, List, Optional, Type, TypeVar
|
|
12
12
|
|
|
13
13
|
from ..attachments import AttachmentBase, SignedAttachment
|
|
14
|
-
from ..enums import DeencapType, ErrorBehavior
|
|
14
|
+
from ..enums import AttachmentType, DeencapType, ErrorBehavior
|
|
15
15
|
from ..exceptions import StandardViolationError
|
|
16
16
|
from .message_base import MessageBase
|
|
17
17
|
from ..utils import inputToBytes, inputToString, unwrapMultipart
|
|
@@ -47,21 +47,42 @@ class MessageSignedBase(MessageBase, Generic[_T]):
|
|
|
47
47
|
:raises StandardViolationError: The standard for signed messages was
|
|
48
48
|
blatantly violated.
|
|
49
49
|
"""
|
|
50
|
-
|
|
50
|
+
# Set these to None to make error handling easier.
|
|
51
|
+
self._signedBody = None
|
|
52
|
+
self._signedHtmlBody = None
|
|
53
|
+
|
|
54
|
+
atts = self.rawAttachments
|
|
51
55
|
|
|
52
56
|
if len(atts) != 1:
|
|
53
57
|
if ErrorBehavior.STANDARDS_VIOLATION in self.errorBehavior:
|
|
54
58
|
if len(atts) == 0:
|
|
55
|
-
logger.error('Signed message has no attachments
|
|
56
|
-
self._sAttachments = []
|
|
57
|
-
self._signedBody = None
|
|
58
|
-
self._signedHtmlBody = None
|
|
59
|
+
logger.error('Standards Violation: Signed message has no attachments.')
|
|
59
60
|
return []
|
|
60
|
-
# If there is at least one attachment,
|
|
61
|
-
# first.
|
|
61
|
+
# If there is at least one attachment, log an error about it
|
|
62
|
+
# and then try to use the first one.
|
|
63
|
+
logger.error('Standards Violation: Signed message has more than one attachment. Attempting to use first one.')
|
|
62
64
|
else:
|
|
63
65
|
raise StandardViolationError('Signed messages without exactly 1 (regular) attachment constitute a violation of the standard.')
|
|
64
66
|
|
|
67
|
+
# If we are here, validate that the found attachment is acceptable.
|
|
68
|
+
if atts[0].type is not AttachmentType.DATA:
|
|
69
|
+
# This is unacceptable and the attachment cannot be used.
|
|
70
|
+
if ErrorBehavior.STANDARDS_VIOLATION in self.errorBehavior:
|
|
71
|
+
logger.error('Standards Violation: Attachment on signed message is unacceptable (not binary).')
|
|
72
|
+
return []
|
|
73
|
+
raise StandardViolationError('Signed messages *must* have a binary attachment. Signed attachments cannot be parsed otherwise.')
|
|
74
|
+
|
|
75
|
+
# Check the mimetype *directly*. Detection of mimetype through data is
|
|
76
|
+
# unacceptable for this check.
|
|
77
|
+
#temp = atts[0].getStringStream('__substg1.0_370E')
|
|
78
|
+
#if temp == 'multipart/signed':
|
|
79
|
+
## Do nothing, but this is how we detect that it is clear signed.
|
|
80
|
+
#pass
|
|
81
|
+
#else:
|
|
82
|
+
## Do nothing, but this is how we detect that it is *not* clear
|
|
83
|
+
# signed.
|
|
84
|
+
#pass
|
|
85
|
+
|
|
65
86
|
# We need to unwrap the multipart stream.
|
|
66
87
|
unwrapped = unwrapMultipart(atts[0].data)
|
|
67
88
|
|
|
@@ -117,7 +138,7 @@ class MessageSignedBase(MessageBase, Generic[_T]):
|
|
|
117
138
|
return htmlBody
|
|
118
139
|
|
|
119
140
|
@functools.cached_property
|
|
120
|
-
def
|
|
141
|
+
def rawAttachments(self) -> List[AttachmentBase]:
|
|
121
142
|
"""
|
|
122
143
|
A property to allow access to the non-signed attachments.
|
|
123
144
|
"""
|
|
@@ -83,8 +83,8 @@ class MSGFile:
|
|
|
83
83
|
:param errorBehavior: Optional, the behavior to use in the event of
|
|
84
84
|
certain types of errors. Uses the ``ErrorBehavior`` enum.
|
|
85
85
|
:param overrideEncoding: Optional, an encoding to use instead of the one
|
|
86
|
-
specified by the MSG file. If the value is "chardet" and you
|
|
87
|
-
the chardet module installed, an attempt will be made to
|
|
86
|
+
specified by the MSG file. If the value is ``"chardet"`` and you
|
|
87
|
+
have the ``chardet`` module installed, an attempt will be made to
|
|
88
88
|
auto-detect the encoding based on some of the string properties. Do
|
|
89
89
|
not report encoding errors caused by this.
|
|
90
90
|
:param treePath: Internal variable used for giving representation of the
|