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.
- extract_msg/__init__.py +71 -0
- extract_msg/__main__.py +115 -0
- extract_msg/_rtf/__init__.py +21 -0
- extract_msg/_rtf/create_doc.py +29 -0
- extract_msg/_rtf/inject_rtf.py +174 -0
- extract_msg/_rtf/token.py +35 -0
- extract_msg/_rtf/tokenize_rtf.py +253 -0
- extract_msg/attachments/__init__.py +144 -0
- extract_msg/attachments/attachment.py +188 -0
- extract_msg/attachments/attachment_base.py +730 -0
- extract_msg/attachments/broken_att.py +42 -0
- extract_msg/attachments/custom_att.py +173 -0
- extract_msg/attachments/custom_att_handler/__init__.py +80 -0
- extract_msg/attachments/custom_att_handler/custom_handler.py +134 -0
- extract_msg/attachments/custom_att_handler/lnk_obj_att.py +109 -0
- extract_msg/attachments/custom_att_handler/outlook_image_dib.py +141 -0
- extract_msg/attachments/emb_msg_att.py +134 -0
- extract_msg/attachments/signed_att.py +234 -0
- extract_msg/attachments/unsupported_att.py +40 -0
- extract_msg/attachments/web_att.py +74 -0
- extract_msg/constants/__init__.py +294 -0
- extract_msg/constants/ps.py +46 -0
- extract_msg/constants/re.py +42 -0
- extract_msg/constants/st.py +110 -0
- extract_msg/data/logging-config/logging-nt.json +64 -0
- extract_msg/data/logging-config/logging-posix.json +64 -0
- extract_msg/encoding/__init__.py +277 -0
- extract_msg/encoding/_dt/__init__.py +4 -0
- extract_msg/encoding/_dt/_mac_ce.py +8 -0
- extract_msg/encoding/_dt/_mac_cyrillic.py +8 -0
- extract_msg/encoding/_dt/_mac_greek.py +8 -0
- extract_msg/encoding/_dt/_mac_iceland.py +8 -0
- extract_msg/encoding/_dt/_mac_turkish.py +8 -0
- extract_msg/encoding/_dt/_win874_dec.py +8 -0
- extract_msg/encoding/_dt/_win950_dec.py +6 -0
- extract_msg/encoding/utils.py +329 -0
- extract_msg/enums.py +2067 -0
- extract_msg/exceptions.py +170 -0
- extract_msg/msg_classes/__init__.py +49 -0
- extract_msg/msg_classes/appointment.py +195 -0
- extract_msg/msg_classes/calendar.py +92 -0
- extract_msg/msg_classes/calendar_base.py +496 -0
- extract_msg/msg_classes/contact.py +1335 -0
- extract_msg/msg_classes/journal.py +131 -0
- extract_msg/msg_classes/meeting_cancellation.py +108 -0
- extract_msg/msg_classes/meeting_exception.py +55 -0
- extract_msg/msg_classes/meeting_forward.py +115 -0
- extract_msg/msg_classes/meeting_related.py +65 -0
- extract_msg/msg_classes/meeting_request.py +189 -0
- extract_msg/msg_classes/meeting_response.py +74 -0
- extract_msg/msg_classes/message.py +12 -0
- extract_msg/msg_classes/message_base.py +1382 -0
- extract_msg/msg_classes/message_signed.py +17 -0
- extract_msg/msg_classes/message_signed_base.py +168 -0
- extract_msg/msg_classes/msg.py +1172 -0
- extract_msg/msg_classes/post.py +53 -0
- extract_msg/msg_classes/sticky_note.py +67 -0
- extract_msg/msg_classes/task.py +363 -0
- extract_msg/msg_classes/task_request.py +86 -0
- extract_msg/null_date.py +34 -0
- extract_msg/ole_writer.py +1086 -0
- extract_msg/open_msg.py +204 -0
- extract_msg/properties/__init__.py +23 -0
- extract_msg/properties/named.py +481 -0
- extract_msg/properties/prop.py +506 -0
- extract_msg/properties/properties_store.py +476 -0
- extract_msg/py.typed +0 -0
- extract_msg/recipient.py +362 -0
- extract_msg/structures/__init__.py +34 -0
- extract_msg/structures/_helpers.py +345 -0
- extract_msg/structures/business_card.py +422 -0
- extract_msg/structures/cfoas.py +108 -0
- extract_msg/structures/contact_link_entry.py +51 -0
- extract_msg/structures/dev_mode_a.py +621 -0
- extract_msg/structures/dv_target_device.py +168 -0
- extract_msg/structures/entry_id.py +697 -0
- extract_msg/structures/misc_id.py +222 -0
- extract_msg/structures/mon_stream.py +55 -0
- extract_msg/structures/odt.py +74 -0
- extract_msg/structures/ole_pres.py +302 -0
- extract_msg/structures/ole_stream_struct.py +117 -0
- extract_msg/structures/recurrence_pattern.py +199 -0
- extract_msg/structures/report_tag.py +127 -0
- extract_msg/structures/system_time.py +158 -0
- extract_msg/structures/time_zone_definition.py +111 -0
- extract_msg/structures/time_zone_struct.py +102 -0
- extract_msg/structures/toc_entry.py +137 -0
- extract_msg/structures/tz_rule.py +148 -0
- extract_msg/utils.py +1270 -0
- extract_msg-0.48.2.dist-info/LICENSE.txt +674 -0
- extract_msg-0.48.2.dist-info/METADATA +321 -0
- extract_msg-0.48.2.dist-info/RECORD +95 -0
- extract_msg-0.48.2.dist-info/WHEEL +5 -0
- extract_msg-0.48.2.dist-info/entry_points.txt +2 -0
- extract_msg-0.48.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
__all__ = [
|
|
5
|
+
'PropertiesStore',
|
|
6
|
+
]
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
import copy
|
|
10
|
+
import datetime
|
|
11
|
+
import logging
|
|
12
|
+
import pprint
|
|
13
|
+
|
|
14
|
+
from typing import (
|
|
15
|
+
Any, Dict, Iterable, Iterator, List, Optional, Tuple, TypeVar, Union
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
from .. import constants
|
|
19
|
+
from ..enums import PropertiesType
|
|
20
|
+
from ..exceptions import NotWritableError
|
|
21
|
+
from .prop import createProp, FixedLengthProp, PropBase
|
|
22
|
+
from ..utils import divide
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
logger = logging.getLogger(__name__)
|
|
26
|
+
logger.addHandler(logging.NullHandler())
|
|
27
|
+
|
|
28
|
+
_T = TypeVar('_T')
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class PropertiesStore:
|
|
32
|
+
"""
|
|
33
|
+
Parser for msg properties files.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(self, data: Optional[bytes], type_: PropertiesType, writable: bool = False):
|
|
37
|
+
"""
|
|
38
|
+
Reads a properties stream or creates a brand new ``PropertiesStore``
|
|
39
|
+
object.
|
|
40
|
+
|
|
41
|
+
:param data: The bytes of the properties instance. Setting to ``None``
|
|
42
|
+
or empty bytes will cause the properties instance to not be valid
|
|
43
|
+
*unless* writable is set to ``True``. If that is the case, the
|
|
44
|
+
instance will be setup for creating a new properties stream.
|
|
45
|
+
:param type_: The type of properties stream this instance represents.
|
|
46
|
+
:param writable: Whether this properties stream should accept
|
|
47
|
+
modification.
|
|
48
|
+
"""
|
|
49
|
+
if not isinstance(type_, PropertiesType):
|
|
50
|
+
raise TypeError(':param type_: MUST be a value of PropertiesType.')
|
|
51
|
+
|
|
52
|
+
self.__type = type_
|
|
53
|
+
|
|
54
|
+
# Setup early variables.
|
|
55
|
+
self.__props: Dict[str, PropBase] = {}
|
|
56
|
+
# This maps short IDs to all properties that use that ID. More than one
|
|
57
|
+
# property with the same ID but a different type may exist.
|
|
58
|
+
self.__idMapping: Dict[str, List[str]] = {}
|
|
59
|
+
self.__naid = None
|
|
60
|
+
self.__nrid = None
|
|
61
|
+
self.__ac = None
|
|
62
|
+
self.__rc = None
|
|
63
|
+
self.__writable = writable
|
|
64
|
+
# Set this now and unset it if everything goes well.
|
|
65
|
+
self.__isError = True
|
|
66
|
+
|
|
67
|
+
# Check if data is None or empty bytes.
|
|
68
|
+
if not data:
|
|
69
|
+
# Two paths here. If writable, we are just meant to be creating a
|
|
70
|
+
# new storage for properties, so initialize and return. Otherwise,
|
|
71
|
+
# we're dealing with an error situation, but we want to silence it.
|
|
72
|
+
if writable:
|
|
73
|
+
self.__rawData = b''
|
|
74
|
+
if type_ is not PropertiesType.ATTACHMENT:
|
|
75
|
+
self.__naid = 0
|
|
76
|
+
self.__nrid = 0
|
|
77
|
+
self.__ac = 0
|
|
78
|
+
self.__rc = 0
|
|
79
|
+
return
|
|
80
|
+
|
|
81
|
+
if not isinstance(data, bytes):
|
|
82
|
+
raise TypeError(':param data: MUST be bytes or None.')
|
|
83
|
+
self.__rawData = data
|
|
84
|
+
|
|
85
|
+
if type_ == PropertiesType.MESSAGE:
|
|
86
|
+
skip = 32
|
|
87
|
+
self.__nrid, self.__naid, self.__rc, self.__ac = constants.st.ST_PROPSTORE_HEADER.unpack(data[:24])
|
|
88
|
+
elif type_ == PropertiesType.MESSAGE_EMBED:
|
|
89
|
+
skip = 24
|
|
90
|
+
self.__nrid, self.__naid, self.__rc, self.__ac = constants.st.ST_PROPSTORE_HEADER.unpack(data[:24])
|
|
91
|
+
else:
|
|
92
|
+
skip = 8
|
|
93
|
+
streams = divide(self.__rawData[skip:], 16)
|
|
94
|
+
for st in streams:
|
|
95
|
+
if len(st) == 16:
|
|
96
|
+
prop = createProp(st)
|
|
97
|
+
self.__props[prop.name] = prop
|
|
98
|
+
|
|
99
|
+
# Add the ID to our mapping list.
|
|
100
|
+
id_ = prop.name[:4]
|
|
101
|
+
if id_ not in self.__idMapping:
|
|
102
|
+
self.__idMapping[id_] = []
|
|
103
|
+
self.__idMapping[id_].append(prop.name)
|
|
104
|
+
else:
|
|
105
|
+
logger.warning(f'Found stream from divide that was not 16 bytes: {st}. Ignoring.')
|
|
106
|
+
self.__isError = False
|
|
107
|
+
|
|
108
|
+
def __bytes__(self) -> bytes:
|
|
109
|
+
return self.toBytes()
|
|
110
|
+
|
|
111
|
+
def __contains__(self, key: Any) -> bool:
|
|
112
|
+
return self.__props.__contains__(key)
|
|
113
|
+
|
|
114
|
+
def __delitem__(self, key: str) -> None:
|
|
115
|
+
"""
|
|
116
|
+
Removes an item using the del operator.
|
|
117
|
+
|
|
118
|
+
:raises KeyError: The key was not found.
|
|
119
|
+
:raises TypeError: The key was not a string.
|
|
120
|
+
"""
|
|
121
|
+
|
|
122
|
+
if not isinstance(key, str):
|
|
123
|
+
raise TypeError('Del operator can only remove a property by string.')
|
|
124
|
+
|
|
125
|
+
key = key.upper()
|
|
126
|
+
|
|
127
|
+
del self.__props[key]
|
|
128
|
+
|
|
129
|
+
# If the deletion was successful, we need to remove the related ID
|
|
130
|
+
# mapping.
|
|
131
|
+
shortKey = key[:4]
|
|
132
|
+
self.__idMapping[shortKey].remove(key)
|
|
133
|
+
if len(self.__idMapping[shortKey]) == 0:
|
|
134
|
+
del self.__idMapping[shortKey]
|
|
135
|
+
|
|
136
|
+
def __getitem__(self, key: Union[str, int]) -> PropBase:
|
|
137
|
+
if (found := self._mapId(key)):
|
|
138
|
+
return self.__props.__getitem__(found)
|
|
139
|
+
raise KeyError(key)
|
|
140
|
+
|
|
141
|
+
def __iter__(self) -> Iterator[str]:
|
|
142
|
+
return self.__props.__iter__()
|
|
143
|
+
|
|
144
|
+
def __len__(self) -> int:
|
|
145
|
+
"""
|
|
146
|
+
Returns the number of properties.
|
|
147
|
+
"""
|
|
148
|
+
return len(self.__props)
|
|
149
|
+
|
|
150
|
+
def __repr__(self) -> str:
|
|
151
|
+
return self.__props.__repr__()
|
|
152
|
+
|
|
153
|
+
def _mapId(self, id_: Union[int, str]) -> str:
|
|
154
|
+
"""
|
|
155
|
+
Converts an input into an appropriate property ID.
|
|
156
|
+
|
|
157
|
+
This is a complex function, allowing the user to specify an int or
|
|
158
|
+
string. If the input is a string that is not 4 characters, it is
|
|
159
|
+
returned. Otherwise, a series of checks will be
|
|
160
|
+
performed. If the input is an int that is less than ``0x10000``, it is
|
|
161
|
+
considered a property ID without a type and converted to a 4 character
|
|
162
|
+
hexadecimal string. Otherwise, it is converted to an 8 character
|
|
163
|
+
hexadecimal string and returned.
|
|
164
|
+
|
|
165
|
+
Once the input is a 4 character string from the other paths, it will
|
|
166
|
+
then be checked against the list of found property IDs, and the first
|
|
167
|
+
full ID will be returned.
|
|
168
|
+
|
|
169
|
+
If a valid conversion could not be done, returns an empty string.
|
|
170
|
+
|
|
171
|
+
All strings returned will be uppercase.
|
|
172
|
+
"""
|
|
173
|
+
# See if we need to convert to 4 character string and map or if we just
|
|
174
|
+
# need to return quickly.
|
|
175
|
+
if isinstance(id_, str):
|
|
176
|
+
id_ = id_.upper()
|
|
177
|
+
if len(id_) != 4:
|
|
178
|
+
return id_
|
|
179
|
+
elif isinstance(id_, int):
|
|
180
|
+
if id_ >= 0x10000:
|
|
181
|
+
return f'{id_:08X}'
|
|
182
|
+
else:
|
|
183
|
+
id_ = f'{id_:04X}'
|
|
184
|
+
else:
|
|
185
|
+
return ''
|
|
186
|
+
|
|
187
|
+
return self.__idMapping.get(id_, ('',))[0]
|
|
188
|
+
|
|
189
|
+
def addProperty(self, prop: PropBase, force: bool = False) -> None:
|
|
190
|
+
"""
|
|
191
|
+
Adds the property if it does not exist.
|
|
192
|
+
|
|
193
|
+
:param prop: The property to add.
|
|
194
|
+
:param force: If ``True``, the writable property will be ignored. This
|
|
195
|
+
will not be reflected when converting to ``bytes`` if the instance
|
|
196
|
+
is not readable.
|
|
197
|
+
|
|
198
|
+
:raises KeyError: A property already exists with the chosen name.
|
|
199
|
+
:raises NotWritableError: The method was used on an unwritable instance.
|
|
200
|
+
"""
|
|
201
|
+
if not (force or self.__writable):
|
|
202
|
+
raise
|
|
203
|
+
|
|
204
|
+
if prop.name in self.__props:
|
|
205
|
+
raise KeyError('A property with that name already exists.')
|
|
206
|
+
self.__props[prop.name.upper()] = prop
|
|
207
|
+
self.__idMapping.setdefault(prop.name[:4], list()).append(prop.name.upper())
|
|
208
|
+
|
|
209
|
+
def get(self, name: Union[str, int], default: _T = None) -> Union[PropBase, _T]:
|
|
210
|
+
"""
|
|
211
|
+
Retrieve the property of :param name:.
|
|
212
|
+
|
|
213
|
+
:returns: The property, or the value of :param default: if the property
|
|
214
|
+
could not be found.
|
|
215
|
+
"""
|
|
216
|
+
if (name := self._mapId(name)):
|
|
217
|
+
return self.__props.get(name, default)
|
|
218
|
+
else:
|
|
219
|
+
return default
|
|
220
|
+
|
|
221
|
+
def getProperties(self, id_: Union[str, int]) -> List[PropBase]:
|
|
222
|
+
"""
|
|
223
|
+
Gets all properties with the specified ID.
|
|
224
|
+
|
|
225
|
+
:param ID: An 4 digit hexadecimal string or an int that is less than
|
|
226
|
+
0x10000.
|
|
227
|
+
"""
|
|
228
|
+
if isinstance(id_, int):
|
|
229
|
+
if id_ >= 0x10000:
|
|
230
|
+
return []
|
|
231
|
+
else:
|
|
232
|
+
id_ = f'{id_:04X}'
|
|
233
|
+
elif isinstance(id_, str):
|
|
234
|
+
if len(id_) == 4:
|
|
235
|
+
id_ = id_.upper()
|
|
236
|
+
else:
|
|
237
|
+
return []
|
|
238
|
+
|
|
239
|
+
return [self[x] for x in self.__idMapping.get(id_, [])]
|
|
240
|
+
|
|
241
|
+
def getValue(self, name: Union[str, int], default: _T = None) -> Union[Any, _T]:
|
|
242
|
+
"""
|
|
243
|
+
Attempts to get the first property
|
|
244
|
+
"""
|
|
245
|
+
if isinstance(name, int):
|
|
246
|
+
if name >= 0x10000:
|
|
247
|
+
name = f'{name:08X}'
|
|
248
|
+
else:
|
|
249
|
+
name = f'{name:04X}'
|
|
250
|
+
if len(name) == 4:
|
|
251
|
+
for prop in self.getProperties(name):
|
|
252
|
+
if isinstance(prop, FixedLengthProp):
|
|
253
|
+
return prop.value
|
|
254
|
+
return default
|
|
255
|
+
elif len(name) == 8:
|
|
256
|
+
if (prop := self.get(name)):
|
|
257
|
+
if isinstance(prop, FixedLengthProp):
|
|
258
|
+
return prop.value
|
|
259
|
+
else:
|
|
260
|
+
return default
|
|
261
|
+
return default
|
|
262
|
+
else:
|
|
263
|
+
raise ValueError('Property name must be an int less than 0x100000000, a 4 character hex string, or an 8 character hex string.')
|
|
264
|
+
|
|
265
|
+
def items(self) -> Iterable[Tuple[str, PropBase]]:
|
|
266
|
+
return self.__props.items()
|
|
267
|
+
|
|
268
|
+
def keys(self) -> Iterable[str]:
|
|
269
|
+
return self.__props.keys()
|
|
270
|
+
|
|
271
|
+
def makeWritable(self) -> PropertiesStore:
|
|
272
|
+
"""
|
|
273
|
+
Returns a copy of this PropertiesStore object that allows modification.
|
|
274
|
+
|
|
275
|
+
If the instance is already writable, this will return the object.
|
|
276
|
+
"""
|
|
277
|
+
if self.__writable:
|
|
278
|
+
return self
|
|
279
|
+
return PropertiesStore(self.__rawData, self.__type, True)
|
|
280
|
+
|
|
281
|
+
def pprintKeys(self) -> None:
|
|
282
|
+
"""
|
|
283
|
+
Uses the pprint function on a sorted list of the keys.
|
|
284
|
+
"""
|
|
285
|
+
pprint.pprint(sorted(self.__props.keys()))
|
|
286
|
+
|
|
287
|
+
def removeProperty(self, nameOrProp: Union[str, PropBase]) -> None:
|
|
288
|
+
"""
|
|
289
|
+
Removes the property by name or by instance.
|
|
290
|
+
|
|
291
|
+
Due to possible ambiguities, this function does *not* accept an int
|
|
292
|
+
argument nor will it be able to find a property based on the 4 character
|
|
293
|
+
hex ID.
|
|
294
|
+
|
|
295
|
+
:raises KeyError: The property was not found.
|
|
296
|
+
:raises NotWritableError: The instance is not writable.
|
|
297
|
+
:raises TypeError: The type for :param nameOrProp: was wrong.
|
|
298
|
+
"""
|
|
299
|
+
if isinstance(nameOrProp, str):
|
|
300
|
+
del self[nameOrProp]
|
|
301
|
+
elif isinstance(nameOrProp, PropBase):
|
|
302
|
+
del self[nameOrProp.name]
|
|
303
|
+
else:
|
|
304
|
+
raise TypeError(f'Cannot remove property using type {type(nameOrProp)}.')
|
|
305
|
+
|
|
306
|
+
def toBytes(self) -> bytes:
|
|
307
|
+
if self.__writable:
|
|
308
|
+
# The reserved field is present on all of them.
|
|
309
|
+
ret = b'\x00' * 8
|
|
310
|
+
|
|
311
|
+
# Add additional fields depending on type.
|
|
312
|
+
if self.__type is not PropertiesType.ATTACHMENT:
|
|
313
|
+
ret += constants.st.ST_PROPSTORE_HEADER.pack(self.__nrid, self.__naid, self.__rc, self.__ac)
|
|
314
|
+
if self.__type is PropertiesType.MESSAGE:
|
|
315
|
+
ret += b'\x00' * 8
|
|
316
|
+
|
|
317
|
+
# Convert all the properties to bytes.
|
|
318
|
+
ret += b''.join(bytes(prop) for prop in self.__props.values())
|
|
319
|
+
|
|
320
|
+
return ret
|
|
321
|
+
else:
|
|
322
|
+
return self.__rawData
|
|
323
|
+
|
|
324
|
+
def values(self) -> Iterable[PropBase]:
|
|
325
|
+
return self.__props.values()
|
|
326
|
+
|
|
327
|
+
items.__doc__ = dict.items.__doc__
|
|
328
|
+
keys.__doc__ = dict.keys.__doc__
|
|
329
|
+
values.__doc__ = dict.values.__doc__
|
|
330
|
+
|
|
331
|
+
@property
|
|
332
|
+
def attachmentCount(self) -> int:
|
|
333
|
+
"""
|
|
334
|
+
The number of Attachment objects for the ``MSGFile`` object.
|
|
335
|
+
|
|
336
|
+
:raises NotWritableError: The setter was used on an unwritable instance.
|
|
337
|
+
:raises TypeError: The Properties instance is not for an ``MSGFile``
|
|
338
|
+
object.
|
|
339
|
+
"""
|
|
340
|
+
if self.__ac is None:
|
|
341
|
+
raise TypeError('Attachment properties do not contain an attachment count.')
|
|
342
|
+
return self.__ac
|
|
343
|
+
|
|
344
|
+
@attachmentCount.setter
|
|
345
|
+
def attachmentCount(self, value: int) -> None:
|
|
346
|
+
if not self.__writable:
|
|
347
|
+
raise NotWritableError('PropertiesStore object is not writable.')
|
|
348
|
+
|
|
349
|
+
if not isinstance(value, int):
|
|
350
|
+
raise TypeError(':property attachmentCount: must be an int.')
|
|
351
|
+
|
|
352
|
+
if self.__ac is None:
|
|
353
|
+
raise TypeError('Attachment properties do not contain an attachment count.')
|
|
354
|
+
|
|
355
|
+
self.__ac = value
|
|
356
|
+
|
|
357
|
+
@property
|
|
358
|
+
def date(self) -> Optional[datetime.datetime]:
|
|
359
|
+
"""
|
|
360
|
+
Returns the send date contained in the Properties file.
|
|
361
|
+
"""
|
|
362
|
+
try:
|
|
363
|
+
return self.__date
|
|
364
|
+
except AttributeError:
|
|
365
|
+
self.__date = None
|
|
366
|
+
if '00390040' in self:
|
|
367
|
+
dateValue = self.getValue('00390040')
|
|
368
|
+
# A date can be bytes if it fails to initialize, so we check it
|
|
369
|
+
# first.
|
|
370
|
+
if isinstance(dateValue, datetime.datetime):
|
|
371
|
+
self.__date = dateValue
|
|
372
|
+
return self.__date
|
|
373
|
+
|
|
374
|
+
@property
|
|
375
|
+
def isError(self) -> bool:
|
|
376
|
+
"""
|
|
377
|
+
Whether the instance is in an invalid state.
|
|
378
|
+
|
|
379
|
+
If the instance is not writable and was given no data, this will be
|
|
380
|
+
``True``.
|
|
381
|
+
"""
|
|
382
|
+
return self.__isError
|
|
383
|
+
|
|
384
|
+
@property
|
|
385
|
+
def nextAttachmentId(self) -> int:
|
|
386
|
+
"""
|
|
387
|
+
The ID to use for naming the next Attachment object storage if one is
|
|
388
|
+
created inside the .msg file.
|
|
389
|
+
|
|
390
|
+
:raises NotWritableError: The setter was used on an unwritable instance.
|
|
391
|
+
:raises TypeError: The Properties instance is not for an ``MSGFile``
|
|
392
|
+
object.
|
|
393
|
+
"""
|
|
394
|
+
if self.__naid is None:
|
|
395
|
+
raise TypeError('Attachment properties do not contain a next attachment ID.')
|
|
396
|
+
return self.__naid
|
|
397
|
+
|
|
398
|
+
@nextAttachmentId.setter
|
|
399
|
+
def nextAttachmentId(self, value: int) -> None:
|
|
400
|
+
if not self.__writable:
|
|
401
|
+
raise NotWritableError('PropertiesStore object is not writable.')
|
|
402
|
+
|
|
403
|
+
if not isinstance(value, int):
|
|
404
|
+
raise TypeError(':property nextAttachmentId: must be an int.')
|
|
405
|
+
|
|
406
|
+
if self.__ac is None:
|
|
407
|
+
raise TypeError('Attachment properties do not contain a next attachment ID.')
|
|
408
|
+
|
|
409
|
+
self.__naid = value
|
|
410
|
+
|
|
411
|
+
@property
|
|
412
|
+
def nextRecipientId(self) -> int:
|
|
413
|
+
"""
|
|
414
|
+
The ID to use for naming the next Recipient object storage if one is
|
|
415
|
+
created inside the .msg file.
|
|
416
|
+
|
|
417
|
+
:raises NotWritableError: The setter was used on an unwritable instance.
|
|
418
|
+
:raises TypeError: The Properties instance is not for an ``MSGFile``
|
|
419
|
+
object.
|
|
420
|
+
"""
|
|
421
|
+
if self.__nrid is None:
|
|
422
|
+
raise TypeError('Attachment properties do not contain a next recipient ID.')
|
|
423
|
+
return self.__nrid
|
|
424
|
+
|
|
425
|
+
@nextRecipientId.setter
|
|
426
|
+
def nextRecipientId(self, value: int) -> None:
|
|
427
|
+
if not self.__writable:
|
|
428
|
+
raise NotWritableError('PropertiesStore object is not writable.')
|
|
429
|
+
|
|
430
|
+
if not isinstance(value, int):
|
|
431
|
+
raise TypeError(':property nextRecipientId: must be an int.')
|
|
432
|
+
|
|
433
|
+
if self.__ac is None:
|
|
434
|
+
raise TypeError('Attachment properties do not contain a next recipient ID.')
|
|
435
|
+
|
|
436
|
+
self.__nrid = value
|
|
437
|
+
|
|
438
|
+
@property
|
|
439
|
+
def props(self) -> Dict[str, PropBase]:
|
|
440
|
+
"""
|
|
441
|
+
Returns a copy of the internal properties dict.
|
|
442
|
+
"""
|
|
443
|
+
return copy.deepcopy(self.__props)
|
|
444
|
+
|
|
445
|
+
@property
|
|
446
|
+
def recipientCount(self) -> int:
|
|
447
|
+
"""
|
|
448
|
+
The number of Recipient objects for the ``MSGFile`` object.
|
|
449
|
+
|
|
450
|
+
:raises NotWritableError: The setter was used on an unwritable instance.
|
|
451
|
+
:raises TypeError: The Properties instance is not for an ``MSGFile``
|
|
452
|
+
object.
|
|
453
|
+
"""
|
|
454
|
+
if self.__rc is None:
|
|
455
|
+
raise TypeError('Attachment properties do not contain a recipient count.')
|
|
456
|
+
return self.__rc
|
|
457
|
+
|
|
458
|
+
@recipientCount.setter
|
|
459
|
+
def recipientCount(self, value: int) -> None:
|
|
460
|
+
if not self.__writable:
|
|
461
|
+
raise NotWritableError('PropertiesStore object is not writable.')
|
|
462
|
+
|
|
463
|
+
if not isinstance(value, int):
|
|
464
|
+
raise TypeError(':property recipientCount: must be an int.')
|
|
465
|
+
|
|
466
|
+
if self.__ac is None:
|
|
467
|
+
raise TypeError('Attachment properties do not contain a recipient count.')
|
|
468
|
+
|
|
469
|
+
self.__nrid = value
|
|
470
|
+
|
|
471
|
+
@property
|
|
472
|
+
def writable(self) -> bool:
|
|
473
|
+
"""
|
|
474
|
+
Whether the instance accepts modification.
|
|
475
|
+
"""
|
|
476
|
+
return self.__writable
|
extract_msg/py.typed
ADDED
|
File without changes
|