extract-msg 0.48.2__py3-none-any.whl

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.
Files changed (95) hide show
  1. extract_msg/__init__.py +71 -0
  2. extract_msg/__main__.py +115 -0
  3. extract_msg/_rtf/__init__.py +21 -0
  4. extract_msg/_rtf/create_doc.py +29 -0
  5. extract_msg/_rtf/inject_rtf.py +174 -0
  6. extract_msg/_rtf/token.py +35 -0
  7. extract_msg/_rtf/tokenize_rtf.py +253 -0
  8. extract_msg/attachments/__init__.py +144 -0
  9. extract_msg/attachments/attachment.py +188 -0
  10. extract_msg/attachments/attachment_base.py +730 -0
  11. extract_msg/attachments/broken_att.py +42 -0
  12. extract_msg/attachments/custom_att.py +173 -0
  13. extract_msg/attachments/custom_att_handler/__init__.py +80 -0
  14. extract_msg/attachments/custom_att_handler/custom_handler.py +134 -0
  15. extract_msg/attachments/custom_att_handler/lnk_obj_att.py +109 -0
  16. extract_msg/attachments/custom_att_handler/outlook_image_dib.py +141 -0
  17. extract_msg/attachments/emb_msg_att.py +134 -0
  18. extract_msg/attachments/signed_att.py +234 -0
  19. extract_msg/attachments/unsupported_att.py +40 -0
  20. extract_msg/attachments/web_att.py +74 -0
  21. extract_msg/constants/__init__.py +294 -0
  22. extract_msg/constants/ps.py +46 -0
  23. extract_msg/constants/re.py +42 -0
  24. extract_msg/constants/st.py +110 -0
  25. extract_msg/data/logging-config/logging-nt.json +64 -0
  26. extract_msg/data/logging-config/logging-posix.json +64 -0
  27. extract_msg/encoding/__init__.py +277 -0
  28. extract_msg/encoding/_dt/__init__.py +4 -0
  29. extract_msg/encoding/_dt/_mac_ce.py +8 -0
  30. extract_msg/encoding/_dt/_mac_cyrillic.py +8 -0
  31. extract_msg/encoding/_dt/_mac_greek.py +8 -0
  32. extract_msg/encoding/_dt/_mac_iceland.py +8 -0
  33. extract_msg/encoding/_dt/_mac_turkish.py +8 -0
  34. extract_msg/encoding/_dt/_win874_dec.py +8 -0
  35. extract_msg/encoding/_dt/_win950_dec.py +6 -0
  36. extract_msg/encoding/utils.py +329 -0
  37. extract_msg/enums.py +2067 -0
  38. extract_msg/exceptions.py +170 -0
  39. extract_msg/msg_classes/__init__.py +49 -0
  40. extract_msg/msg_classes/appointment.py +195 -0
  41. extract_msg/msg_classes/calendar.py +92 -0
  42. extract_msg/msg_classes/calendar_base.py +496 -0
  43. extract_msg/msg_classes/contact.py +1335 -0
  44. extract_msg/msg_classes/journal.py +131 -0
  45. extract_msg/msg_classes/meeting_cancellation.py +108 -0
  46. extract_msg/msg_classes/meeting_exception.py +55 -0
  47. extract_msg/msg_classes/meeting_forward.py +115 -0
  48. extract_msg/msg_classes/meeting_related.py +65 -0
  49. extract_msg/msg_classes/meeting_request.py +189 -0
  50. extract_msg/msg_classes/meeting_response.py +74 -0
  51. extract_msg/msg_classes/message.py +12 -0
  52. extract_msg/msg_classes/message_base.py +1382 -0
  53. extract_msg/msg_classes/message_signed.py +17 -0
  54. extract_msg/msg_classes/message_signed_base.py +168 -0
  55. extract_msg/msg_classes/msg.py +1172 -0
  56. extract_msg/msg_classes/post.py +53 -0
  57. extract_msg/msg_classes/sticky_note.py +67 -0
  58. extract_msg/msg_classes/task.py +363 -0
  59. extract_msg/msg_classes/task_request.py +86 -0
  60. extract_msg/null_date.py +34 -0
  61. extract_msg/ole_writer.py +1086 -0
  62. extract_msg/open_msg.py +204 -0
  63. extract_msg/properties/__init__.py +23 -0
  64. extract_msg/properties/named.py +481 -0
  65. extract_msg/properties/prop.py +506 -0
  66. extract_msg/properties/properties_store.py +476 -0
  67. extract_msg/py.typed +0 -0
  68. extract_msg/recipient.py +362 -0
  69. extract_msg/structures/__init__.py +34 -0
  70. extract_msg/structures/_helpers.py +345 -0
  71. extract_msg/structures/business_card.py +422 -0
  72. extract_msg/structures/cfoas.py +108 -0
  73. extract_msg/structures/contact_link_entry.py +51 -0
  74. extract_msg/structures/dev_mode_a.py +621 -0
  75. extract_msg/structures/dv_target_device.py +168 -0
  76. extract_msg/structures/entry_id.py +697 -0
  77. extract_msg/structures/misc_id.py +222 -0
  78. extract_msg/structures/mon_stream.py +55 -0
  79. extract_msg/structures/odt.py +74 -0
  80. extract_msg/structures/ole_pres.py +302 -0
  81. extract_msg/structures/ole_stream_struct.py +117 -0
  82. extract_msg/structures/recurrence_pattern.py +199 -0
  83. extract_msg/structures/report_tag.py +127 -0
  84. extract_msg/structures/system_time.py +158 -0
  85. extract_msg/structures/time_zone_definition.py +111 -0
  86. extract_msg/structures/time_zone_struct.py +102 -0
  87. extract_msg/structures/toc_entry.py +137 -0
  88. extract_msg/structures/tz_rule.py +148 -0
  89. extract_msg/utils.py +1270 -0
  90. extract_msg-0.48.2.dist-info/LICENSE.txt +674 -0
  91. extract_msg-0.48.2.dist-info/METADATA +321 -0
  92. extract_msg-0.48.2.dist-info/RECORD +95 -0
  93. extract_msg-0.48.2.dist-info/WHEEL +5 -0
  94. extract_msg-0.48.2.dist-info/entry_points.txt +2 -0
  95. extract_msg-0.48.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,111 @@
1
+ __all__ = [
2
+ 'TimeZoneDefinition',
3
+ ]
4
+
5
+
6
+ from typing import List, Optional
7
+
8
+ from ..constants import st
9
+ from ._helpers import BytesReader
10
+ from .tz_rule import TZRule
11
+
12
+
13
+ class TimeZoneDefinition:
14
+ """
15
+ Structure for PidLidAppointmentTimeZoneDefinitionRecur from [MS-OXOCAL].
16
+ """
17
+
18
+ def __init__(self, data: Optional[bytes] = None):
19
+ if not data:
20
+ self.__majorVersion = 2
21
+ self.__minorVersion = 1
22
+ self.__keyName = ''
23
+ self.__rules = [TZRule()]
24
+ return
25
+ reader = BytesReader(data)
26
+ self.__majorVersion = reader.readUnsignedByte()
27
+ self.__minorVersion = reader.readUnsignedByte()
28
+ cbHeader = reader.readUnsignedShort()
29
+ reader.assertRead(b'\x02\x00')
30
+ cchKeyName = reader.readUnsignedShort()
31
+ self.__keyName = reader.read(2 * cchKeyName).decode('utf-16-le')
32
+ cRules = reader.readUnsignedShort()
33
+ if cRules < 1 or cRules > 1024:
34
+ raise ValueError('Value for cRules was out of range.')
35
+ self.__rules = [reader.readClass(TZRule) for _ in range(cRules)]
36
+
37
+ def __bytes__(self) -> bytes:
38
+ return self.toBytes()
39
+
40
+ def toBytes(self) -> bytes:
41
+ # Validate some of the data.
42
+ if len(self.__rules) < 1:
43
+ raise ValueError('Cannot pack a TimeZoneDefinition with no rules.')
44
+ if len(self.__rules) > 1024:
45
+ raise ValueError('TimeZoneDefintion can only have up to 1024 rules.')
46
+
47
+ ret = bytes((self.__majorVersion, self.__minorVersion))
48
+ ret += st.ST_LE_UI16.pack(6 + 2 * len(self.__keyName))
49
+ ret += b'\x02\x00'
50
+ ret += st.ST_LE_UI16.pack(2* len(self.__keyName))
51
+ ret += st.ST_LE_UI16.pack(len(self.__rules))
52
+ ret += b''.join(bytes(x) for x in self.__rules)
53
+
54
+ return ret
55
+
56
+ @property
57
+ def keyName(self) -> str:
58
+ """
59
+ The name of the associated time zone.
60
+
61
+ Not localized but instead set to the unique name of the desired time
62
+ zone.
63
+ """
64
+ return self.__keyName
65
+
66
+ @keyName.setter
67
+ def keyName(self, value: str) -> None:
68
+ value = str(value)
69
+ if len(value) > 260:
70
+ raise ValueError('Key name must be a string less than 261 characters.')
71
+
72
+ self.__keyName = value
73
+
74
+ @property
75
+ def majorVersion(self) -> int:
76
+ """
77
+ The major version.
78
+ """
79
+ return self.__majorVersion
80
+
81
+ @majorVersion.setter
82
+ def majorVersion(self, value: int) -> None:
83
+ if value > 255:
84
+ raise ValueError('Major version cannot be greater than 255')
85
+ if value < 0:
86
+ raise ValueError('Major version must be positive.')
87
+
88
+ self.__minorVersion = value
89
+
90
+ @property
91
+ def minorVersion(self) -> int:
92
+ """
93
+ The minor version.
94
+ """
95
+ return self.__minorVersion
96
+
97
+ @minorVersion.setter
98
+ def minorVersion(self, value: int) -> None:
99
+ if value > 255:
100
+ raise ValueError('Minor version cannot be greater than 255')
101
+ if value < 0:
102
+ raise ValueError('Minor version must be positive.')
103
+
104
+ self.__minorVersion = value
105
+
106
+ @property
107
+ def rules(self) -> List[TZRule]:
108
+ """
109
+ A tuple of TZRule structures that specifies a time zone.
110
+ """
111
+ return self.__rules
@@ -0,0 +1,102 @@
1
+ __all__ = [
2
+ 'TimeZoneStruct',
3
+ ]
4
+
5
+
6
+ from typing import Optional
7
+
8
+ from .. import constants
9
+ from .system_time import SystemTime
10
+
11
+
12
+ class TimeZoneStruct:
13
+ """
14
+ A TimeZoneStruct, as specified in [MS-OXOCAL].
15
+ """
16
+
17
+ def __init__(self, data: Optional[bytes] = None):
18
+ if not data:
19
+ self.__bias = 0
20
+ self.__standardBias = 0
21
+ self.__daylightBias = 0
22
+ self.__standardDate = SystemTime()
23
+ self.__daylightDate = SystemTime()
24
+
25
+ return
26
+ unpacked = constants.st.ST_TZ.unpack(data)
27
+ self.__bias = unpacked[0]
28
+ self.__standardBias = unpacked[1]
29
+ self.__daylightBias = unpacked[2]
30
+ self.__standardDate = SystemTime(unpacked[4])
31
+ self.__daylightDate = SystemTime(unpacked[6])
32
+
33
+ def __bytes__(self) -> bytes:
34
+ return self.toBytes()
35
+
36
+ def toBytes(self) -> bytes:
37
+ return constants.st.ST_TZ.pack(self.__bias,
38
+ self.__standardBias,
39
+ self.__daylightBias,
40
+ self.standardYear,
41
+ bytes(self.__standardDate),
42
+ self.daylightYear,
43
+ bytes(self.__daylightDate))
44
+
45
+ @property
46
+ def bias(self) -> int:
47
+ """
48
+ The time zone's offset in minutes from UTC.
49
+ """
50
+ return self.__bias
51
+
52
+ @property
53
+ def daylightBias(self) -> int:
54
+ """
55
+ The offset in minutes from the value of the bias field during daylight
56
+ saving time.
57
+ """
58
+ return self.__daylightBias
59
+
60
+ @property
61
+ def daylightDate(self) -> SystemTime:
62
+ """
63
+ The date and local time that indicate when to begin using the value
64
+ specified in the daylightBias field. Uses the same format as
65
+ standardDate.
66
+ """
67
+ return self.__daylightDate
68
+
69
+ @property
70
+ def daylightYear(self) -> int:
71
+ """
72
+ The value of the daylightDate field's year.
73
+ """
74
+ return self.__daylightDate.year
75
+
76
+ @property
77
+ def standardBias(self) -> int:
78
+ """
79
+ The offset in minutes from the value of the bias field during standard
80
+ time.
81
+ """
82
+ return self.__standardBias
83
+
84
+ @property
85
+ def standardDate(self) -> SystemTime:
86
+ """
87
+ The date and local time that indicate when to begin using the value
88
+ specified in the standardBias field. If the time zone does not support
89
+ daylight's savings time, the month member must be 0. If the year is not
90
+ 0, then it is an absolute date than only occurs once, otherwise it is a
91
+ relative date that occurs yearly.
92
+
93
+ See [MS-OXOCAL] for details.
94
+ """
95
+ return self.__standardDate
96
+
97
+ @property
98
+ def standardYear(self) -> int:
99
+ """
100
+ The value of the standardDate field's year.
101
+ """
102
+ return self.__standardDate.year
@@ -0,0 +1,137 @@
1
+ __all__ = [
2
+ 'TOCEntry',
3
+ ]
4
+
5
+
6
+ from typing import Optional, Union
7
+
8
+ from ._helpers import BytesReader
9
+ from .cfoas import ClipboardFormatOrAnsiString
10
+ from ..constants import st
11
+ from .dv_target_device import DVTargetDevice
12
+ from ..enums import ADVF, DVAspect
13
+
14
+
15
+ class TOCEntry:
16
+ def __init__(self, reader: Optional[Union[bytes, BytesReader]] = None):
17
+ if reader is None:
18
+ self.__clipFormat = ClipboardFormatOrAnsiString()
19
+ self.__aspect = 0
20
+ self.__lindex = 0
21
+ self.__tymed = 0
22
+ self.__advf = 0
23
+ self.__targetDevice = DVTargetDevice()
24
+ return
25
+
26
+ if isinstance(reader, bytes):
27
+ reader = BytesReader(reader)
28
+
29
+ self.__clipFormat = ClipboardFormatOrAnsiString(reader)
30
+ targetDeviceSize = reader.readUnsignedInt()
31
+ self.__aspect = reader.readUnsignedInt()
32
+ self.__lindex = reader.readUnsignedInt()
33
+ self.__tymed = reader.readUnsignedInt()
34
+ reader.read(12)
35
+ self.__advf = reader.readUnsignedInt()
36
+
37
+ # Based off the wording of the documentation, it seems like this can't
38
+ # actually be 0 bytes, so this should be fine.
39
+ self.__targetDevice = DVTargetDevice(reader.read(targetDeviceSize))
40
+
41
+
42
+ def __bytes__(self) -> bytes:
43
+ return self.toBytes()
44
+
45
+ def toBytes(self) -> bytes:
46
+ ret = bytes(self.__clipFormat)
47
+ td = bytes(self.__targetDevice)
48
+ ret += st.ST_LE_UI32.pack(len(td))
49
+ ret += st.ST_LE_UI32.pack(self.__aspect)
50
+ ret += st.ST_LE_UI32.pack(self.__lindex)
51
+ ret += st.ST_LE_UI32.pack(self.__tymed)
52
+ ret += b'\x00' * 12
53
+ ret += st.ST_LE_UI32.pack(self.__advf)
54
+ ret += b'\x00' * 4
55
+ ret += td
56
+
57
+ return ret
58
+
59
+ @property
60
+ def advf(self) -> Union[int, ADVF]:
61
+ """
62
+ An implementation specific hint on how to render the presentation data
63
+ on screen. May be ignored on processing.
64
+ """
65
+ return self.__advf
66
+
67
+ @advf.setter
68
+ def advf(self, val: Union[int, ADVF]) -> None:
69
+ if not isinstance(val, int):
70
+ raise TypeError(':property advf: must be an int.')
71
+ if val < 0:
72
+ raise ValueError(':property advf: must be positive.')
73
+ if val > 0xFFFFFFFF:
74
+ raise ValueError(':property advf: cannot be greater than 0xFFFFFFFF.')
75
+
76
+ self.__advf = val
77
+
78
+ @property
79
+ def ansiClipboardFormat(self) -> ClipboardFormatOrAnsiString:
80
+ return self.__clipFormat
81
+
82
+ @property
83
+ def aspect(self) -> Union[int, DVAspect]:
84
+ """
85
+ An implementation specific hint on how to render the presentation data
86
+ on screen. May be ignored on processing.
87
+ """
88
+ return self.__aspect
89
+
90
+ @aspect.setter
91
+ def aspect(self, val: Union[int, DVAspect]) -> None:
92
+ if not isinstance(val, int):
93
+ raise TypeError(':property aspect: must be an int.')
94
+ if val < 0:
95
+ raise ValueError(':property aspect: must be positive.')
96
+ if val > 0xFFFFFFFF:
97
+ raise ValueError(':property aspect: cannot be greater than 0xFFFFFFFF.')
98
+
99
+ self.__aspect = val
100
+
101
+ @property
102
+ def lindex(self) -> int:
103
+ """
104
+ An implementation specific hint on how to render the presentation data
105
+ on screen. May be ignored on processing.
106
+ """
107
+ return self.__lindex
108
+
109
+ @lindex.setter
110
+ def lindex(self, val: int) -> None:
111
+ if not isinstance(val, int):
112
+ raise TypeError(':property lindex: must be an int.')
113
+ if val < 0:
114
+ raise ValueError(':property lindex: must be positive.')
115
+ if val > 0xFFFFFFFF:
116
+ raise ValueError(':property lindex: cannot be greater than 0xFFFFFFFF.')
117
+
118
+ self.__lindex = val
119
+
120
+ @property
121
+ def targetDevice(self) -> DVTargetDevice:
122
+ return self.__targetDevice
123
+
124
+ @property
125
+ def tymed(self) -> int:
126
+ return self.__tymed
127
+
128
+ @tymed.setter
129
+ def tymed(self, val: int) -> None:
130
+ if not isinstance(val, int):
131
+ raise TypeError(':property lindex: must be an int.')
132
+ if val < 0:
133
+ raise ValueError(':property lindex: must be positive.')
134
+ if val > 0xFFFFFFFF:
135
+ raise ValueError(':property lindex: cannot be greater than 0xFFFFFFFF.')
136
+
137
+ self.__tymed = val
@@ -0,0 +1,148 @@
1
+ __all__ = [
2
+ 'TZRule',
3
+ ]
4
+
5
+
6
+ import logging
7
+
8
+ from struct import Struct
9
+ from typing import Final, final, Optional
10
+
11
+ from ..enums import TZFlag
12
+ from ._helpers import BytesReader
13
+ from .system_time import SystemTime
14
+
15
+
16
+ logger = logging.getLogger(__name__)
17
+ logger.addHandler(logging.NullHandler())
18
+
19
+
20
+ @final
21
+ class TZRule:
22
+ """
23
+ A TZRule structure, as defined in [MS-OXOCAL].
24
+ """
25
+
26
+ __SIZE__: int = 66
27
+ __struct: Final[Struct] = Struct('4B2H14x3i16s16s')
28
+
29
+ def __init__(self, data: Optional[bytes] = None):
30
+ if not data:
31
+ self.__majorVersion = 2
32
+ self.__minorVersion = 1
33
+ self.__flags = TZFlag(0)
34
+ self.__year = 0
35
+ self.__bias = 0
36
+ self.__standardBias = 0
37
+ self.__daylightBias = 0
38
+ self.__standardDate = SystemTime()
39
+ self.__daylightDate = SystemTime()
40
+ return
41
+
42
+ reader = BytesReader(data)
43
+ self.__majorVersion = reader.readUnsignedByte()
44
+ self.__minorVersion = reader.readUnsignedByte()
45
+ reader.assertRead(b'\x3E\x00')
46
+ self.__flags = TZFlag(reader.readUnsignedShort())
47
+ self.__year = reader.readUnsignedShort()
48
+ # This *MUST* be null, however I've seen Outlook not follow that. Simply
49
+ # log a warning about it even though it's a violation.
50
+ if any(b := reader.read(14)):
51
+ logger.warning(f'Read TZRule with non-null X section (got {b}).')
52
+ self.__bias = reader.readInt()
53
+ self.__standardBias = reader.readInt()
54
+ self.__daylightBias = reader.readInt()
55
+ self.__standardDate = SystemTime(reader.read(16))
56
+ self.__daylightDate = SystemTime(reader.read(16))
57
+
58
+ def __bytes__(self) -> bytes:
59
+ return self.toBytes()
60
+
61
+ def toBytes(self) -> bytes:
62
+ return self.__struct.pack(self.__majorVersion,
63
+ self.__minorVersion,
64
+ 62,
65
+ 0,
66
+ self.__flags,
67
+ self.__year,
68
+ self.__bias,
69
+ self.__standardBias,
70
+ self.__daylightBias,
71
+ bytes(self.__standardDate),
72
+ bytes(self.__daylightDate))
73
+
74
+ @property
75
+ def bias(self) -> int:
76
+ """
77
+ The time zone's offset in minutes from UTC.
78
+ """
79
+ return self.__bias
80
+
81
+ @property
82
+ def daylightBias(self) -> int:
83
+ """
84
+ The offset in minutes from the value of the bias field during daylight
85
+ saving time.
86
+ """
87
+ return self.__daylightBias
88
+
89
+ @property
90
+ def daylightDate(self) -> SystemTime:
91
+ """
92
+ The date and local time that indicate when to begin using the value
93
+ specified in the daylightBias field. Uses the same format as
94
+ standardDate.
95
+ """
96
+ return self.__daylightDate
97
+
98
+ @property
99
+ def flags(self) -> TZFlag:
100
+ """
101
+ The flags for this rule.
102
+ """
103
+ return self.__flags
104
+
105
+ @property
106
+ def majorVersion(self) -> int:
107
+ """
108
+ The major version.
109
+ """
110
+ return self.__majorVersion
111
+
112
+ @property
113
+ def minorVersion(self) -> int:
114
+ """
115
+ The minor version.
116
+ """
117
+ return self.__minorVersion
118
+
119
+ @property
120
+ def standardBias(self) -> int:
121
+ """
122
+ The offset in minutes from the value of the bias field during standard
123
+ time.
124
+ """
125
+ return self.__standardBias
126
+
127
+ @property
128
+ def standardDate(self) -> SystemTime:
129
+ """
130
+ The date and local time that indicate when to begin using the value
131
+ specified in the standardBias field. If the time zone does not support
132
+ daylight's savings time, the month member must be 0. If the year is not
133
+ 0, then it is an absolute date than only occurs once, otherwise it is a
134
+ relative date that occurs yearly.
135
+
136
+ See [MS-OXOCAL] for details.
137
+ """
138
+ return self.__standardDate
139
+
140
+ @property
141
+ def year(self) -> int:
142
+ """
143
+ The year this rule is scheduled to take place. A rule will remain in
144
+ effect from January 1 of it's year until January 1 of the next rule's
145
+ year field. If no rules exist for subsequent years, this rule will
146
+ remain in effect indefinately.
147
+ """
148
+ return self.__year