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,1335 @@
1
+ __all__ = [
2
+ 'Contact',
3
+ ]
4
+
5
+
6
+ import datetime
7
+ import functools
8
+ import io
9
+ import json
10
+
11
+ from typing import Dict, List, Optional, Set, Tuple, Union
12
+
13
+ from ..constants import HEADER_FORMAT_TYPE, ps
14
+ from ..enums import (
15
+ ContactLinkState, ElectronicAddressProperties, Gender,
16
+ InsecureFeatures, PostalAddressID
17
+ )
18
+ from ..exceptions import SecurityError
19
+ from .message_base import MessageBase
20
+ from ..structures.business_card import BusinessCardDisplayDefinition
21
+ from ..structures.entry_id import EntryID
22
+
23
+
24
+ # I would use TypeAlias, but my type checker *really* hates that.
25
+ _EMAIL_DICT = Dict[str, Optional[Union[str, EntryID]]]
26
+ _FAX_DICT = _EMAIL_DICT
27
+
28
+
29
+ class Contact(MessageBase):
30
+ """
31
+ Class used for parsing contacts.
32
+ """
33
+
34
+ def getJson(self) -> str:
35
+ # To save a lot of trouble and repetiion, just return a JSON version of
36
+ # the header format properties.
37
+ return json.dumps(self.headerFormatProperties)
38
+
39
+ @functools.cached_property
40
+ def account(self) -> Optional[str]:
41
+ """
42
+ The account name of the contact.
43
+ """
44
+ return self.getStringStream('__substg1.0_3A00')
45
+
46
+ @functools.cached_property
47
+ def addressBookProviderArrayType(self) -> Optional[ElectronicAddressProperties]:
48
+ """
49
+ A union of which Electronic Address properties are set on the contact.
50
+
51
+ Property is stored in the MSG file as a sinlge int. The result should be
52
+ a union of the flags specified by addressBookProviderEmailList.
53
+ """
54
+ return self.getNamedAs('8029', ps.PSETID_ADDRESS, ElectronicAddressProperties)
55
+
56
+ @functools.cached_property
57
+ def addressBookProviderEmailList(self) -> Optional[Set[ElectronicAddressProperties]]:
58
+ """
59
+ A set of which Electronic Address properties are set on the contact.
60
+ """
61
+ return self.getNamedAs('8028', ps.PSETID_ADDRESS, ElectronicAddressProperties.fromIter)
62
+
63
+ @functools.cached_property
64
+ def assistant(self) -> Optional[str]:
65
+ """
66
+ The name of the contact's assistant.
67
+ """
68
+ return self.getStringStream('__substg1.0_3A30')
69
+
70
+ @functools.cached_property
71
+ def assistantTelephoneNumber(self) -> Optional[str]:
72
+ """
73
+ Contains the telephone number of the contact's administrative assistant.
74
+ """
75
+ return self.getStringStream('__substg1.0_3A2E')
76
+
77
+ @functools.cached_property
78
+ def autoLog(self) -> bool:
79
+ """
80
+ Whether the client should create a Journal object for each action
81
+ associated with the Contact object.
82
+ """
83
+ return bool(self.getNamedProp('8025', ps.PSETID_ADDRESS))
84
+
85
+ @functools.cached_property
86
+ def billing(self) -> Optional[str]:
87
+ """
88
+ Billing information for the contact.
89
+ """
90
+ return self.getNamedProp('8535', ps.PSETID_COMMON)
91
+
92
+ @functools.cached_property
93
+ def birthday(self) -> Optional[datetime.datetime]:
94
+ """
95
+ The birthday of the contact at 11:59 UTC.
96
+ """
97
+ return self.getPropertyVal('3A420040')
98
+
99
+ @functools.cached_property
100
+ def birthdayEventEntryID(self) -> Optional[EntryID]:
101
+ """
102
+ The EntryID of an optional Appointement object that represents the
103
+ contact's birtday.
104
+ """
105
+ return self.getNamedAs('804D', ps.PSETID_ADDRESS, EntryID.autoCreate)
106
+
107
+ @functools.cached_property
108
+ def birthdayLocal(self) -> Optional[datetime.datetime]:
109
+ """
110
+ The birthday of the contact at 0:00 in the client's local time zone.
111
+ """
112
+ return self.getNamedProp('80DE', ps.PSETID_ADDRESS)
113
+
114
+ @functools.cached_property
115
+ def businessCard(self) -> bytes:
116
+ if InsecureFeatures.PIL_IMAGE_PARSING not in self.insecureFeatures:
117
+ return SecurityError('PIL_IMAGE_PARSING must be enabled to create a business card image.')
118
+ # First import PIL here so it's an optional dependency.
119
+ try:
120
+ import PIL.Image
121
+ import PIL.ImageDraw
122
+ except ImportError:
123
+ raise ImportError('PIL or Pillow is required for generating the business card.') from None
124
+
125
+ raise NotImplementedError('This function is not complete and as such is not yet functional. Please wait until later in the work cycle for this version.')
126
+
127
+ # See "contact business card details.txt" for details.
128
+ cardDef = self.businessCardDisplayDefinition
129
+ # First things first, let's make the image we will be placing everything
130
+ # onto.
131
+ im = PIL.Image.new('RGB', (250, 150), cardDef.backgroundColor)
132
+ # Create the ImageDraw instance so we can draw on it easily.
133
+ imDraw = PIL.ImageDraw.ImageDraw(im)
134
+
135
+ # Create the border of the image:
136
+ imDraw.rectangle(((0, 0), (249, 149)), outline = (109, 109, 109))
137
+
138
+
139
+ # Finally, return the image.
140
+ out = io.BytesIO()
141
+ im.save(out, 'png')
142
+ return out
143
+
144
+ @functools.cached_property
145
+ def businessCardCardPicture(self) -> Optional[bytes]:
146
+ """
147
+ The image to be used on a business card.
148
+
149
+ Must be either a PNG file or a JPEG file.
150
+ """
151
+ return self.getNamedProp('8041', ps.PSETID_ADDRESS)
152
+
153
+ @functools.cached_property
154
+ def businessCardDisplayDefinition(self) -> Optional[BusinessCardDisplayDefinition]:
155
+ """
156
+ Specifies the customization details for displaying a contact as a
157
+ business card.
158
+ """
159
+ return self.getNamedAs('8040', ps.PSETID_ADDRESS, BusinessCardDisplayDefinition)
160
+
161
+ @functools.cached_property
162
+ def businessFax(self) -> Optional[_FAX_DICT]:
163
+ """
164
+ Returns a ``dict`` of the data for the business fax.
165
+
166
+ Returns ``None`` if no fields are set.
167
+
168
+ Keys are "address_type", "email_address", "number",
169
+ "original_display_name", and "original_entry_id".
170
+ """
171
+ data = {
172
+ 'address_type': self.businessFaxAddressType,
173
+ 'email_address': self.businessFaxEmailAddress,
174
+ 'number': self.businessFaxNumber,
175
+ 'original_display_name': self.businessFaxOriginalDisplayName,
176
+ 'original_entry_id': self.businessFaxOriginalEntryId,
177
+ }
178
+ return data if any(data[x] for x in data) else None
179
+
180
+ @functools.cached_property
181
+ def businessFaxAddressType(self) -> Optional[str]:
182
+ """
183
+ The type of address for the fax.
184
+
185
+ MUST be set to "FAX" if present.
186
+ """
187
+ return self.getNamedProp('80C2', ps.PSETID_ADDRESS)
188
+
189
+ @functools.cached_property
190
+ def businessFaxEmailAddress(self) -> Optional[str]:
191
+ """
192
+ Contains a user-readable display name, followed by the "@" character,
193
+ followed by a fax number.
194
+ """
195
+ return self.getNamedProp('80C3', ps.PSETID_ADDRESS)
196
+
197
+ @functools.cached_property
198
+ def businessFaxNumber(self) -> Optional[str]:
199
+ """
200
+ Contains the number of the contact's business fax.
201
+ """
202
+ return self.getStringStream('__substg1.0_3A24')
203
+
204
+ @functools.cached_property
205
+ def businessFaxOriginalDisplayName(self) -> Optional[str]:
206
+ """
207
+ The normalized subject for the contact.
208
+ """
209
+ return self.getNamedProp('80C4', ps.PSETID_ADDRESS)
210
+
211
+ @functools.cached_property
212
+ def businessFaxOriginalEntryId(self) -> Optional[EntryID]:
213
+ """
214
+ The one-off EntryID corresponding to this fax address.
215
+ """
216
+ return self.getNamedAs('80C5', ps.PSETID_ADDRESS, EntryID.autoCreate)
217
+
218
+ @functools.cached_property
219
+ def businessTelephoneNumber(self) -> Optional[str]:
220
+ """
221
+ Contains the number of the contact's business telephone.
222
+ """
223
+ return self.getStringStream('__substg1.0_3A08')
224
+
225
+ @functools.cached_property
226
+ def businessTelephone2Number(self) -> Optional[Union[str, List[str]]]:
227
+ """
228
+ Contains the second number or numbers of the contact's business.
229
+ """
230
+ return self.getSingleOrMultipleString('__substg1.0_3A1B')
231
+
232
+ @functools.cached_property
233
+ def businessHomePage(self) -> Optional[str]:
234
+ """
235
+ Contains the url of the homepage of the contact's business.
236
+ """
237
+ return self.getStringStream('__substg1.0_3A51')
238
+
239
+ @functools.cached_property
240
+ def callbackTelephoneNumber(self) -> Optional[str]:
241
+ """
242
+ Contains the contact's callback telephone number.
243
+ """
244
+ return self.getStringStream('__substg1.0_3A02')
245
+
246
+ @functools.cached_property
247
+ def carTelephoneNumber(self) -> Optional[str]:
248
+ """
249
+ Contains the number of the contact's car telephone.
250
+ """
251
+ return self.getStringStream('__substg1.0_3A1E')
252
+
253
+ @functools.cached_property
254
+ def childrensNames(self) -> Optional[List[str]]:
255
+ """
256
+ A list of the named of the contact's children.
257
+ """
258
+ return self.getMultipleString('__substg1.0_3A58')
259
+
260
+ @functools.cached_property
261
+ def companyMainTelephoneNumber(self) -> Optional[str]:
262
+ """
263
+ Contains the number of the main telephone of the contact's company.
264
+ """
265
+ return self.getStringStream('__substg1.0_3A57')
266
+
267
+ @functools.cached_property
268
+ def companyName(self) -> Optional[str]:
269
+ """
270
+ The name of the company the contact works at.
271
+ """
272
+ return self.getStringStream('__substg1.0_3A16')
273
+
274
+ @functools.cached_property
275
+ def computerNetworkName(self) -> Optional[str]:
276
+ """
277
+ The name of the network to wwhich the contact's computer is connected.
278
+ """
279
+ return self.getStringStream('__substg1.0_3A49')
280
+
281
+ @functools.cached_property
282
+ def contactCharacterSet(self) -> Optional[int]:
283
+ """
284
+ The character set that is used for this Contact object.
285
+ """
286
+ return self.getNamedProp('8023', ps.PSETID_ADDRESS)
287
+
288
+ @functools.cached_property
289
+ def contactItemData(self) -> Optional[List[int]]:
290
+ """
291
+ Used to help display the contact information.
292
+ """
293
+ return self.getNamedProp('8007', ps.PSETID_ADDRESS)
294
+
295
+ @functools.cached_property
296
+ def contactLinkedGlobalAddressListEntryID(self) -> Optional[EntryID]:
297
+ """
298
+ The EntryID of the GAL object to which the duplicate contact is linked.
299
+ """
300
+ return self.getNamedAs('80E2', ps.PSETID_ADDRESS, EntryID.autoCreate)
301
+
302
+ @functools.cached_property
303
+ def contactLinkGlobalAddressListLinkID(self) -> Optional[str]:
304
+ """
305
+ The GUID of the GAL contact to which the duplicate contact is linked.
306
+ """
307
+ return self.getNamedProp('80E8', ps.PSETID_ADDRESS)
308
+
309
+ @functools.cached_property
310
+ def contactLinkGlobalAddressListLinkState(self) -> Optional[ContactLinkState]:
311
+ """
312
+ The state of linking between the GAL contact and the duplicate contact.
313
+ """
314
+ return self.getNamedAs('80E6', ps.PSETID_ADDRESS, ContactLinkState)
315
+
316
+ @functools.cached_property
317
+ def contactLinkLinkRejectHistory(self) -> Optional[List[bytes]]:
318
+ """
319
+ A list of any contacts that were previously rejected for linking with
320
+ the duplicate contact.
321
+ """
322
+ return self.getNamedProp('80E5', ps.PSETID_ADDRESS)
323
+
324
+ @functools.cached_property
325
+ def contactLinkSMTPAddressCache(self) -> Optional[List[str]]:
326
+ """
327
+ A list of the SMTP addresses that are used by the GAL contact that are
328
+ linked to the duplicate contact.
329
+ """
330
+ return self.getNamedProp('80E3', ps.PSETID_ADDRESS)
331
+
332
+ @functools.cached_property
333
+ def contactPhoto(self) -> Optional[bytes]:
334
+ """
335
+ The contact photo, if it exists.
336
+ """
337
+ if self.hasPicture:
338
+ if len(self.attachments) > 0:
339
+ contactPhotoAtt = next((att for att in self.attachments if att.isAttachmentContactPhoto), None)
340
+ if contactPhotoAtt:
341
+ return contactPhotoAtt.data
342
+ return None
343
+
344
+ @functools.cached_property
345
+ def contactUserField1(self) -> Optional[str]:
346
+ """
347
+ Used to store custom text for a business card.
348
+ """
349
+ return self.getNamedProp('804F', ps.PSETID_ADDRESS)
350
+
351
+ @functools.cached_property
352
+ def contactUserField2(self) -> Optional[str]:
353
+ """
354
+ Used to store custom text for a business card.
355
+ """
356
+ return self.getNamedProp('8050', ps.PSETID_ADDRESS)
357
+
358
+ @functools.cached_property
359
+ def contactUserField3(self) -> Optional[str]:
360
+ """
361
+ Used to store custom text for a business card.
362
+ """
363
+ return self.getNamedProp('8051', ps.PSETID_ADDRESS)
364
+
365
+ @functools.cached_property
366
+ def contactUserField4(self) -> Optional[str]:
367
+ """
368
+ Used to store custom text for a business card.
369
+ """
370
+ return self.getNamedProp('8052', ps.PSETID_ADDRESS)
371
+
372
+ @functools.cached_property
373
+ def customerID(self) -> Optional[str]:
374
+ """
375
+ The contact's customer ID number.
376
+ """
377
+ return self.getStringStream('__substg1.0_3A4A')
378
+
379
+ @functools.cached_property
380
+ def departmentName(self) -> Optional[str]:
381
+ """
382
+ The name of the department the contact works in.
383
+ """
384
+ return self.getStringStream('__substg1.0_3A18')
385
+
386
+ @functools.cached_property
387
+ def displayName(self) -> Optional[str]:
388
+ """
389
+ The full name of the contact.
390
+ """
391
+ return self.getStringStream('__substg1.0_3001')
392
+
393
+ @functools.cached_property
394
+ def displayNamePrefix(self) -> Optional[str]:
395
+ """
396
+ The contact's honorific title.
397
+ """
398
+ return self.getStringStream('__substg1.0_3A45')
399
+
400
+ @functools.cached_property
401
+ def email1(self) -> Optional[_EMAIL_DICT]:
402
+ """
403
+ Returns a ``dict`` of the data for email 1.
404
+
405
+ Returns ``None`` if no fields are set.
406
+
407
+ Keys are "address_type", "display_name", "email_address",
408
+ "original_display_name", and "original_entry_id".
409
+ """
410
+ data = {
411
+ 'address_type': self.email1AddressType,
412
+ 'display_name': self.email1DisplayName,
413
+ 'email_address': self.email1EmailAddress,
414
+ 'original_display_name': self.email1OriginalDisplayName,
415
+ 'original_entry_id': self.email1OriginalEntryId,
416
+ }
417
+ return data if any(data[x] for x in data) else None
418
+
419
+ @functools.cached_property
420
+ def email1AddressType(self) -> Optional[str]:
421
+ """
422
+ The address type of the first email address.
423
+ """
424
+ return self.getNamedProp('8082', ps.PSETID_ADDRESS)
425
+
426
+ @functools.cached_property
427
+ def email1DisplayName(self) -> Optional[str]:
428
+ """
429
+ The user-readable display name of the first email address.
430
+ """
431
+ return self.getNamedProp('8080', ps.PSETID_ADDRESS)
432
+
433
+ @functools.cached_property
434
+ def email1EmailAddress(self) -> Optional[str]:
435
+ """
436
+ The first email address.
437
+ """
438
+ return self.getNamedProp('8083', ps.PSETID_ADDRESS)
439
+
440
+ @functools.cached_property
441
+ def email1OriginalDisplayName(self) -> Optional[str]:
442
+ """
443
+ The first SMTP email address that corresponds to the first email address
444
+ for the contact.
445
+ """
446
+ return self.getNamedProp('8084', ps.PSETID_ADDRESS)
447
+
448
+ @functools.cached_property
449
+ def email1OriginalEntryId(self) -> Optional[EntryID]:
450
+ """
451
+ The EntryID of the object correspinding to this electronic address.
452
+ """
453
+ return self.getNamedAs('8085', ps.PSETID_ADDRESS, EntryID.autoCreate)
454
+
455
+ @functools.cached_property
456
+ def email2(self) -> Optional[_EMAIL_DICT]:
457
+ """
458
+ Returns a ``dict`` of the data for email 2.
459
+
460
+ Returns ``None`` if no fields are set.
461
+ """
462
+ data = {
463
+ 'address_type': self.email2AddressType,
464
+ 'display_name': self.email2DisplayName,
465
+ 'email_address': self.email2EmailAddress,
466
+ 'original_display_name': self.email2OriginalDisplayName,
467
+ 'original_entry_id': self.email2OriginalEntryId,
468
+ }
469
+ return data if any(data[x] for x in data) else None
470
+
471
+ @functools.cached_property
472
+ def email2AddressType(self) -> Optional[str]:
473
+ """
474
+ The address type of the second email address.
475
+ """
476
+ return self.getNamedProp('8092', ps.PSETID_ADDRESS)
477
+
478
+ @functools.cached_property
479
+ def email2DisplayName(self) -> Optional[str]:
480
+ """
481
+ The user-readable display name of the second email address.
482
+ """
483
+ return self.getNamedProp('8090', ps.PSETID_ADDRESS)
484
+
485
+ @functools.cached_property
486
+ def email2EmailAddress(self) -> Optional[str]:
487
+ """
488
+ The second email address.
489
+ """
490
+ return self.getNamedProp('8093', ps.PSETID_ADDRESS)
491
+
492
+ @functools.cached_property
493
+ def email2OriginalDisplayName(self) -> Optional[str]:
494
+ """
495
+ The second SMTP email address that corresponds to the second email
496
+ address for the contact.
497
+ """
498
+ return self.getNamedProp('8094', ps.PSETID_ADDRESS)
499
+
500
+ @functools.cached_property
501
+ def email2OriginalEntryId(self) -> Optional[EntryID]:
502
+ """
503
+ The EntryID of the object correspinding to this electronic address.
504
+ """
505
+ return self.getNamedAs('8095', ps.PSETID_ADDRESS, EntryID.autoCreate)
506
+
507
+ @functools.cached_property
508
+ def email3(self) -> Optional[_EMAIL_DICT]:
509
+ """
510
+ Returns a ``dict`` of the data for email 3.
511
+
512
+ Returns ``None`` if no fields are set.
513
+ """
514
+ data = {
515
+ 'address_type': self.email3AddressType,
516
+ 'display_name': self.email3DisplayName,
517
+ 'email_address': self.email3EmailAddress,
518
+ 'original_display_name': self.email3OriginalDisplayName,
519
+ 'original_entry_id': self.email3OriginalEntryId,
520
+ }
521
+ return data if any(data[x] for x in data) else None
522
+
523
+ @functools.cached_property
524
+ def email3AddressType(self) -> Optional[str]:
525
+ """
526
+ The address type of the third email address.
527
+ """
528
+ return self.getNamedProp('80A2', ps.PSETID_ADDRESS)
529
+
530
+ @functools.cached_property
531
+ def email3DisplayName(self) -> Optional[str]:
532
+ """
533
+ The user-readable display name of the third email address.
534
+ """
535
+ return self.getNamedProp('80A0', ps.PSETID_ADDRESS)
536
+
537
+ @functools.cached_property
538
+ def email3EmailAddress(self) -> Optional[str]:
539
+ """
540
+ The third email address.
541
+ """
542
+ return self.getNamedProp('80A3', ps.PSETID_ADDRESS)
543
+
544
+ @functools.cached_property
545
+ def email3OriginalDisplayName(self) -> Optional[str]:
546
+ """
547
+ The third SMTP email address that corresponds to the third email address
548
+ for the contact.
549
+ """
550
+ return self.getNamedProp('80A4', ps.PSETID_ADDRESS)
551
+
552
+ @functools.cached_property
553
+ def email3OriginalEntryId(self) -> Optional[EntryID]:
554
+ """
555
+ The EntryID of the object correspinding to this electronic address.
556
+ """
557
+ return self.getNamedAs('80A5', ps.PSETID_ADDRESS, EntryID.autoCreate)
558
+
559
+ @functools.cached_property
560
+ def emails(self) -> Tuple[Union[_EMAIL_DICT, None], Union[_EMAIL_DICT, None], Union[_EMAIL_DICT, None]]:
561
+ """
562
+ Returns a tuple of all the email ``dict``\\s.
563
+
564
+ Value for an email will be ``None`` if no fields were set.
565
+ """
566
+ return (self.email1, self.email2, self.email3)
567
+
568
+ @functools.cached_property
569
+ def faxNumbers(self) -> Dict[str, Optional[_FAX_DICT]]:
570
+ """
571
+ Returns a ``dict`` of the fax numbers.
572
+
573
+ Entry will be ``None`` if no fields were set.
574
+
575
+ Keys are "business", "home", and "primary".
576
+ """
577
+ return {
578
+ 'business': self.businessFax,
579
+ 'home': self.homeFax,
580
+ 'primary': self.primaryFax,
581
+ }
582
+
583
+ @functools.cached_property
584
+ def fileUnder(self) -> Optional[str]:
585
+ """
586
+ The name under which to file a contact when displaying a list of
587
+ contacts.
588
+ """
589
+ return self.getNamedProp('8005', ps.PSETID_ADDRESS)
590
+
591
+ @functools.cached_property
592
+ def fileUnderID(self) -> Optional[int]:
593
+ """
594
+ The format to use for fileUnder. See PidLidFileUnderId in [MS-OXOCNTC]
595
+ for details.
596
+ """
597
+ return self.getNamedProp('8006', ps.PSETID_ADDRESS)
598
+
599
+ @functools.cached_property
600
+ def freeBusyLocation(self) -> Optional[str]:
601
+ """
602
+ A URL path from which a client can retrieve free/busy status information
603
+ for the contact as an iCalendat file.
604
+ """
605
+ return self.getNamedProp('80D8', ps.PSETID_ADDRESS)
606
+
607
+ @functools.cached_property
608
+ def ftpSite(self) -> Optional[str]:
609
+ """
610
+ The contact's File Transfer Protocol url.
611
+ """
612
+ return self.getStringStream('__substg1.0_3A4C')
613
+
614
+ @functools.cached_property
615
+ def gender(self) -> Gender:
616
+ """
617
+ The gender of the contact.
618
+ """
619
+ return Gender(self.getPropertyVal('3A4D0002', 0))
620
+
621
+ @functools.cached_property
622
+ def generation(self) -> Optional[str]:
623
+ """
624
+ A generational abbreviation that follows the full name of the contact.
625
+ """
626
+ return self.getStringStream('__substg1.0_3A05')
627
+
628
+ @functools.cached_property
629
+ def givenName(self) -> Optional[str]:
630
+ """
631
+ The first name of the contact.
632
+ """
633
+ return self.getStringStream('__substg1.0_3A06')
634
+
635
+ @functools.cached_property
636
+ def governmentIDNumber(self) -> Optional[str]:
637
+ """
638
+ The contact's government ID number.
639
+ """
640
+ return self.getStringStream('__substg1.0_3A07')
641
+
642
+ @functools.cached_property
643
+ def hasPicture(self) -> bool:
644
+ """
645
+ Whether the contact has a contact photo.
646
+ """
647
+ return bool(self.getNamedProp('8015', ps.PSETID_ADDRESS))
648
+
649
+ @property
650
+ def headerFormatProperties(self) -> HEADER_FORMAT_TYPE:
651
+ def strListToStr(inp: Optional[Union[str, List[str]]]):
652
+ """
653
+ Small internal function for things that may return a string or list.
654
+ """
655
+ if inp is None or isinstance(inp, str):
656
+ return inp
657
+ else:
658
+ return ', '.join(inp)
659
+
660
+ # Checking outlook printing, default behavior is to completely omit
661
+ # *any* field that is not present. So while for extensability the
662
+ # option exists to have it be present even if no data is found, we are
663
+ # specifically not doing that.
664
+ return {
665
+ '-personal details-': {
666
+ 'Full Name': self.displayName,
667
+ 'Last Name': self.surname,
668
+ 'First Name': self.givenName,
669
+ 'Job Title': self.jobTitle,
670
+ 'Department': self.departmentName,
671
+ 'Company': self.companyName,
672
+ },
673
+ '-addresses-': {
674
+ 'Business Address': self.workAddress,
675
+ 'Home Address': self.homeAddress,
676
+ 'Other Address': self.otherAddress,
677
+ 'IM Address': self.instantMessagingAddress,
678
+ },
679
+ '-phone numbers-': {
680
+ 'Business': self.businessTelephoneNumber,
681
+ 'Business 2': strListToStr(self.businessTelephone2Number),
682
+ 'Assistant': self.assistantTelephoneNumber,
683
+ 'Company Main Phone': self.companyMainTelephoneNumber,
684
+ 'Home': self.homeTelephoneNumber,
685
+ 'Home 2': strListToStr(self.homeTelephone2Number),
686
+ 'Mobile': self.mobileTelephoneNumber,
687
+ 'Car': self.carTelephoneNumber,
688
+ 'Radio': self.radioTelephoneNumber,
689
+ 'Pager': self.pagerTelephoneNumber,
690
+ 'Callback': self.callbackTelephoneNumber,
691
+ 'Other': self.otherTelephoneNumber,
692
+ 'Primary Phone': self.primaryTelephoneNumber,
693
+ 'Telex': self.telexNumber,
694
+ 'TTY/TDD Phone': self.tddTelephoneNumber,
695
+ 'ISDN': self.isdnNumber,
696
+ 'Business Fax': self.businessFaxNumber,
697
+ 'Home Fax': self.homeFaxNumber,
698
+ },
699
+ '-emails-': {
700
+ 'Email': self.email1EmailAddress or self.email1OriginalDisplayName,
701
+ 'Email Display As': self.email1DisplayName,
702
+ 'Email 2': self.email2EmailAddress or self.email2OriginalDisplayName,
703
+ 'Email2 Display As': self.email2DisplayName,
704
+ 'Email 3': self.email3EmailAddress or self.email3OriginalDisplayName,
705
+ 'Email3 Display As': self.email3DisplayName,
706
+ },
707
+ '-other-': {
708
+ 'Birthday': self.birthday.__format__(self.dateFormat) if self.birthdayLocal else None,
709
+ 'Anniversary': self.weddingAnniversary.__format__(self.dateFormat) if self.weddingAnniversaryLocal else None,
710
+ 'Spouse/Partner': self.spouseName,
711
+ 'Profession': self.profession,
712
+ 'Children': strListToStr(self.childrensNames),
713
+ 'Hobbies': self.hobbies,
714
+ 'Assistant': self.assistant,
715
+ 'Web Page': self.webpageUrl,
716
+ },
717
+ }
718
+
719
+ @functools.cached_property
720
+ def hobbies(self) -> Optional[str]:
721
+ """
722
+ The hobies of the contact.
723
+ """
724
+ return self.getStringStream('__substg1.0_3A43')
725
+
726
+ @functools.cached_property
727
+ def homeAddress(self) -> Optional[str]:
728
+ """
729
+ The complete home address of the contact.
730
+ """
731
+ return self.getNamedProp('801A', ps.PSETID_ADDRESS)
732
+
733
+ @functools.cached_property
734
+ def homeAddressCountry(self) -> Optional[str]:
735
+ """
736
+ The country portion of the contact's home address.
737
+ """
738
+ return self.getStringStream('__substg1.0_3A5A')
739
+
740
+ @functools.cached_property
741
+ def homeAddressCountryCode(self) -> Optional[str]:
742
+ """
743
+ The country code portion of the contact's home address.
744
+ """
745
+ return self.getNamedProp('80DA', ps.PSETID_ADDRESS)
746
+
747
+ @functools.cached_property
748
+ def homeAddressLocality(self) -> Optional[str]:
749
+ """
750
+ The locality or city portion of the contact's home address.
751
+ """
752
+ return self.getStringStream('__substg1.0_3A59')
753
+
754
+ @functools.cached_property
755
+ def homeAddressPostalCode(self) -> Optional[str]:
756
+ """
757
+ The postal code portion of the contact's home address.
758
+ """
759
+ return self.getStringStream('__substg1.0_3A5B')
760
+
761
+ @functools.cached_property
762
+ def homeAddressPostOfficeBox(self) -> Optional[str]:
763
+ """
764
+ The number or identifier of the contact's home post office box.
765
+ """
766
+ return self.getStringStream('__substg1.0_3A5E')
767
+
768
+ @functools.cached_property
769
+ def homeAddressStateOrProvince(self) -> Optional[str]:
770
+ """
771
+ The state or province portion of the contact's home address.
772
+ """
773
+ return self.getStringStream('__substg1.0_3A5C')
774
+
775
+ @functools.cached_property
776
+ def homeAddressStreet(self) -> Optional[str]:
777
+ """
778
+ The street portion of the contact's home address.
779
+ """
780
+ return self.getStringStream('__substg1.0_3A5D')
781
+
782
+ @functools.cached_property
783
+ def homeFax(self) -> Optional[_FAX_DICT]:
784
+ """
785
+ Returns a ``dict`` of the data for the home fax.
786
+
787
+ Returns ``None`` if no fields are set.
788
+
789
+ Keys are "address_type", "email_address", "number",
790
+ "original_display_name", and "original_entry_id".
791
+ """
792
+ data = {
793
+ 'address_type': self.homeFaxAddressType,
794
+ 'email_address': self.homeFaxEmailAddress,
795
+ 'number': self.homeFaxNumber,
796
+ 'original_display_name': self.homeFaxOriginalDisplayName,
797
+ 'original_entry_id': self.homeFaxOriginalEntryId,
798
+ }
799
+ return data if any(data[x] for x in data) else None
800
+
801
+ @functools.cached_property
802
+ def homeFaxAddressType(self) -> Optional[str]:
803
+ """
804
+ The type of address for the fax. MUST be set to "FAX" if present.
805
+ """
806
+ return self.getNamedProp('80D2', ps.PSETID_ADDRESS)
807
+
808
+ @functools.cached_property
809
+ def homeFaxEmailAddress(self) -> Optional[str]:
810
+ """
811
+ Contains a user-readable display name, followed by the "@" character,
812
+ followed by a fax number.
813
+ """
814
+ return self.getNamedProp('80D3', ps.PSETID_ADDRESS)
815
+
816
+ @functools.cached_property
817
+ def homeFaxNumber(self) -> Optional[str]:
818
+ """
819
+ Contains the number of the contact's home fax.
820
+ """
821
+ return self.getStringStream('__substg1.0_3A25')
822
+
823
+ @functools.cached_property
824
+ def homeFaxOriginalDisplayName(self) -> Optional[str]:
825
+ """
826
+ The normalized subject for the contact.
827
+ """
828
+ return self.getNamedProp('80D4', ps.PSETID_ADDRESS)
829
+
830
+ @functools.cached_property
831
+ def homeFaxOriginalEntryId(self) -> Optional[EntryID]:
832
+ """
833
+ The one-off EntryID corresponding to this fax address.
834
+ """
835
+ return self.getNamedAs('80D5', ps.PSETID_ADDRESS, EntryID.autoCreate)
836
+
837
+ @functools.cached_property
838
+ def homeTelephoneNumber(self) -> Optional[str]:
839
+ """
840
+ The number of the contact's home telephone.
841
+ """
842
+ return self.getStringStream('__substg1.0_3A09')
843
+
844
+ @functools.cached_property
845
+ def homeTelephone2Number(self) -> Optional[Union[str, List[str]]]:
846
+ """
847
+ The number(s) of the contact's second home telephone.
848
+ """
849
+ return self.getSingleOrMultipleString('__substg1.0_3A2F')
850
+
851
+ @functools.cached_property
852
+ def initials(self) -> Optional[str]:
853
+ """
854
+ The initials of the contact.
855
+ """
856
+ return self.getStringStream('__substg1.0_3A0A')
857
+
858
+ @functools.cached_property
859
+ def instantMessagingAddress(self) -> Optional[str]:
860
+ """
861
+ The instant messaging address of the contact.
862
+ """
863
+ return self.getNamedProp('8062', ps.PSETID_ADDRESS)
864
+
865
+ @functools.cached_property
866
+ def isContactLinked(self) -> bool:
867
+ """
868
+ Whether the contact is linked to other contacts.
869
+ """
870
+ return bool(self.getNamedProp('80E0', ps.PSETID_ADDRESS))
871
+
872
+ @functools.cached_property
873
+ def isdnNumber(self) -> Optional[str]:
874
+ """
875
+ The Integrated Services Digital Network (ISDN) telephone number of the
876
+ contact.
877
+ """
878
+ return self.getStringStream('__substg1.0_3A2D')
879
+
880
+ @functools.cached_property
881
+ def jobTitle(self) -> Optional[str]:
882
+ """
883
+ The job title of the contact.
884
+ """
885
+ return self.getStringStream('__substg1.0_3A17')
886
+
887
+ @functools.cached_property
888
+ def language(self) -> Optional[str]:
889
+ """
890
+ The language that the contact uses.
891
+ """
892
+ return self.getStringStream('__substg1.0_3A0C')
893
+
894
+ @functools.cached_property
895
+ def lastModifiedBy(self) -> Optional[str]:
896
+ """
897
+ The name of the last user to modify the contact file.
898
+ """
899
+ return self.getStringStream('__substg1.0_3FFA')
900
+
901
+ @functools.cached_property
902
+ def location(self) -> Optional[str]:
903
+ """
904
+ The location of the contact.
905
+
906
+ For example, this could be the building or office number of the contact.
907
+ """
908
+ return self.getStringStream('__substg1.0_3A0D')
909
+
910
+ @functools.cached_property
911
+ def mailAddress(self) -> Optional[str]:
912
+ """
913
+ The complete mail address of the contact.
914
+ """
915
+ return self.getStringStream('__substg1.0_3A15')
916
+
917
+ @functools.cached_property
918
+ def mailAddressCountry(self) -> Optional[str]:
919
+ """
920
+ The country portion of the contact's mail address.
921
+ """
922
+ return self.getStringStream('__substg1.0_3A26')
923
+
924
+ @functools.cached_property
925
+ def mailAddressCountryCode(self) -> Optional[str]:
926
+ """
927
+ The country code portion of the contact's mail address.
928
+ """
929
+ return self.getNamedProp('80DD', ps.PSETID_ADDRESS)
930
+
931
+ @functools.cached_property
932
+ def mailAddressLocality(self) -> Optional[str]:
933
+ """
934
+ The locality or city portion of the contact's mail address.
935
+ """
936
+ return self.getStringStream('__substg1.0_3A27')
937
+
938
+ @functools.cached_property
939
+ def mailAddressPostalCode(self) -> Optional[str]:
940
+ """
941
+ The postal code portion of the contact's mail address.
942
+ """
943
+ return self.getStringStream('__substg1.0_3A2A')
944
+
945
+ @functools.cached_property
946
+ def mailAddressPostOfficeBox(self) -> Optional[str]:
947
+ """
948
+ The number or identifier of the contact's mail post office box.
949
+ """
950
+ return self.getStringStream('__substg1.0_3A2B')
951
+
952
+ @functools.cached_property
953
+ def mailAddressStateOrProvince(self) -> Optional[str]:
954
+ """
955
+ The state or province portion of the contact's mail address.
956
+ """
957
+ return self.getStringStream('__substg1.0_3A28')
958
+
959
+ @functools.cached_property
960
+ def mailAddressStreet(self) -> Optional[str]:
961
+ """
962
+ The street portion of the contact's mail address.
963
+ """
964
+ return self.getStringStream('__substg1.0_3A29')
965
+
966
+ @functools.cached_property
967
+ def managerName(self) -> Optional[str]:
968
+ """
969
+ The name of the contact's manager.
970
+ """
971
+ return self.getStringStream('__substg1.0_3A4E')
972
+
973
+ @functools.cached_property
974
+ def middleName(self) -> Optional[str]:
975
+ """
976
+ The middle name(s) of the contact.
977
+ """
978
+ return self.getStringStream('__substg1.0_3A44')
979
+
980
+ @functools.cached_property
981
+ def mobileTelephoneNumber(self) -> Optional[str]:
982
+ """
983
+ The mobile telephone number of the contact.
984
+ """
985
+ return self.getStringStream('__substg1.0_3A1C')
986
+
987
+ @functools.cached_property
988
+ def nickname(self) -> Optional[str]:
989
+ """
990
+ The nickname of the contanct.
991
+ """
992
+ return self.getStringStream('__substg1.0_3A4F')
993
+
994
+ @functools.cached_property
995
+ def officeLocation(self) -> Optional[str]:
996
+ """
997
+ The location of the office that the contact works in.
998
+ """
999
+ return self.getStringStream('__substg1.0_3A19')
1000
+
1001
+ @functools.cached_property
1002
+ def organizationalIDNumber(self) -> Optional[str]:
1003
+ """
1004
+ The organizational ID number for the contact, such as an employee ID
1005
+ number.
1006
+ """
1007
+ return self.getStringStream('__substg1.0_3A10')
1008
+
1009
+ @functools.cached_property
1010
+ def oscSyncEnabled(self) -> bool:
1011
+ """
1012
+ Whether contact synchronization with an external source (such as a
1013
+ social networking site) is handled by the server.
1014
+ """
1015
+ return bool(self.getPropertyVal('7C24000B'))
1016
+
1017
+ @functools.cached_property
1018
+ def otherAddress(self) -> Optional[str]:
1019
+ """
1020
+ The complete other address of the contact.
1021
+ """
1022
+ return self.getNamedProp('801C', ps.PSETID_ADDRESS)
1023
+
1024
+ @functools.cached_property
1025
+ def otherAddressCountry(self) -> Optional[str]:
1026
+ """
1027
+ The country portion of the contact's other address.
1028
+ """
1029
+ return self.getStringStream('__substg1.0_3A60')
1030
+
1031
+ @functools.cached_property
1032
+ def otherAddressCountryCode(self) -> Optional[str]:
1033
+ """
1034
+ The country code portion of the contact's other address.
1035
+ """
1036
+ return self.getNamedProp('80DC', ps.PSETID_ADDRESS)
1037
+
1038
+ @functools.cached_property
1039
+ def otherAddressLocality(self) -> Optional[str]:
1040
+ """
1041
+ The locality or city portion of the contact's other address.
1042
+ """
1043
+ return self.getStringStream('__substg1.0_3A5F')
1044
+
1045
+ @functools.cached_property
1046
+ def otherAddressPostalCode(self) -> Optional[str]:
1047
+ """
1048
+ The postal code portion of the contact's other address.
1049
+ """
1050
+ return self.getStringStream('__substg1.0_3A61')
1051
+
1052
+ @functools.cached_property
1053
+ def otherAddressPostOfficeBox(self) -> Optional[str]:
1054
+ """
1055
+ The number or identifier of the contact's other post office box.
1056
+ """
1057
+ return self.getStringStream('__substg1.0_3A64')
1058
+
1059
+ @functools.cached_property
1060
+ def otherAddressStateOrProvince(self) -> Optional[str]:
1061
+ """
1062
+ The state or province portion of the contact's other address.
1063
+ """
1064
+ return self.getStringStream('__substg1.0_3A62')
1065
+
1066
+ @functools.cached_property
1067
+ def otherAddressStreet(self) -> Optional[str]:
1068
+ """
1069
+ The street portion of the contact's other address.
1070
+ """
1071
+ return self.getStringStream('__substg1.0_3A63')
1072
+
1073
+ @functools.cached_property
1074
+ def otherTelephoneNumber(self) -> Optional[str]:
1075
+ """
1076
+ Contains the number of the contact's other telephone.
1077
+ """
1078
+ return self.getStringStream('__substg1.0_3A1F')
1079
+
1080
+ @functools.cached_property
1081
+ def pagerTelephoneNumber(self) -> Optional[str]:
1082
+ """
1083
+ The contact's pager telephone number.
1084
+ """
1085
+ return self.getStringStream('__substg1.0_3A21')
1086
+
1087
+ @functools.cached_property
1088
+ def personalHomePage(self) -> Optional[str]:
1089
+ """
1090
+ The contact's personal web page UL.
1091
+ """
1092
+ return self.getStringStream('__substg1.0_3A50')
1093
+
1094
+ @functools.cached_property
1095
+ def phoneticCompanyName(self) -> Optional[str]:
1096
+ """
1097
+ The phonetic pronunciation of the contact's company name.
1098
+ """
1099
+ return self.getNamedProp('802E', ps.PSETID_ADDRESS)
1100
+
1101
+ @functools.cached_property
1102
+ def phoneticGivenName(self) -> Optional[str]:
1103
+ """
1104
+ The phonetic pronunciation of the contact's given name.
1105
+ """
1106
+ return self.getNamedProp('802C', ps.PSETID_ADDRESS)
1107
+
1108
+ @functools.cached_property
1109
+ def phoneticSurname(self) -> Optional[str]:
1110
+ """
1111
+ The phonetic pronunciation of the given name of the contact.
1112
+ """
1113
+ return self.getNamedProp('802D', ps.PSETID_ADDRESS)
1114
+
1115
+ @functools.cached_property
1116
+ def postalAddressID(self) -> PostalAddressID:
1117
+ """
1118
+ Indicates which physical address is the Mailing Address for this
1119
+ contact.
1120
+ """
1121
+ return PostalAddressID(self.getNamedProp('8022', ps.PSETID_ADDRESS, 0))
1122
+
1123
+ @functools.cached_property
1124
+ def primaryFax(self) -> Optional[_FAX_DICT]:
1125
+ """
1126
+ Returns a ``dict`` of the data for the primary fax.
1127
+
1128
+ Returns ``None`` if no fields are set.
1129
+
1130
+ Keys are "address_type", "email_address", "number",
1131
+ "original_display_name", and "original_entry_id".
1132
+ """
1133
+ data = {
1134
+ 'address_type': self.primaryFaxAddressType,
1135
+ 'email_address': self.primaryFaxEmailAddress,
1136
+ 'number': self.primaryFaxNumber,
1137
+ 'original_display_name': self.primaryFaxOriginalDisplayName,
1138
+ 'original_entry_id': self.primaryFaxOriginalEntryId,
1139
+ }
1140
+ return data if any(data[x] for x in data) else None
1141
+
1142
+ @functools.cached_property
1143
+ def primaryFaxAddressType(self) -> Optional[str]:
1144
+ """
1145
+ The type of address for the fax. MUST be set to "FAX" if present.
1146
+ """
1147
+ return self.getNamedProp('80B2', ps.PSETID_ADDRESS)
1148
+
1149
+ @functools.cached_property
1150
+ def primaryFaxEmailAddress(self) -> Optional[str]:
1151
+ """
1152
+ Contains a user-readable display name, followed by the "@" character,
1153
+ followed by a fax number.
1154
+ """
1155
+ return self.getNamedProp('80B3', ps.PSETID_ADDRESS)
1156
+
1157
+ @functools.cached_property
1158
+ def primaryFaxNumber(self) -> Optional[str]:
1159
+ """
1160
+ Contains the number of the contact's primary fax.
1161
+ """
1162
+ return self.getStringStream('__substg1.0_3A23')
1163
+
1164
+ @functools.cached_property
1165
+ def primaryFaxOriginalDisplayName(self) -> Optional[str]:
1166
+ """
1167
+ The normalized subject for the contact.
1168
+ """
1169
+ return self.getNamedProp('80B4', ps.PSETID_ADDRESS)
1170
+
1171
+ @functools.cached_property
1172
+ def primaryFaxOriginalEntryId(self) -> Optional[EntryID]:
1173
+ """
1174
+ The one-off EntryID corresponding to this fax address.
1175
+ """
1176
+ return self.getNamedAs('80B5', ps.PSETID_ADDRESS, EntryID.autoCreate)
1177
+
1178
+ @functools.cached_property
1179
+ def primaryTelephoneNumber(self) -> Optional[str]:
1180
+ """
1181
+ Contains the number of the contact's primary telephone.
1182
+ """
1183
+ return self.getStringStream('__substg1.0_3A1A')
1184
+
1185
+ @functools.cached_property
1186
+ def profession(self) -> Optional[str]:
1187
+ """
1188
+ The profession of the contact.
1189
+ """
1190
+ return self.getStringStream('__substg1.0_3A46')
1191
+
1192
+ @functools.cached_property
1193
+ def radioTelephoneNumber(self) -> Optional[str]:
1194
+ """
1195
+ Contains the number of the contact's radio telephone.
1196
+ """
1197
+ return self.getStringStream('__substg1.0_3A1D')
1198
+
1199
+ @functools.cached_property
1200
+ def referenceEntryID(self) -> Optional[EntryID]:
1201
+ """
1202
+ Contains a value that is equal to the value of the EntryID of the
1203
+ Contact object unless the Contact object is a copy of an earlier
1204
+ original.
1205
+ """
1206
+ return self.getNamedAs('85BD', ps.PSETID_COMMON, EntryID.autoCreate)
1207
+
1208
+ @functools.cached_property
1209
+ def referredByName(self) -> Optional[str]:
1210
+ """
1211
+ The name of the person who referred this contact to the user.
1212
+ """
1213
+ return self.getStringStream('__substg1.0_3A47')
1214
+
1215
+ @functools.cached_property
1216
+ def spouseName(self) -> Optional[str]:
1217
+ """
1218
+ The name of the contact's spouse.
1219
+ """
1220
+ return self.getStringStream('__substg1.0_3A48')
1221
+
1222
+ @functools.cached_property
1223
+ def surname(self) -> Optional[str]:
1224
+ """
1225
+ The surname of the contact.
1226
+ """
1227
+ return self.getStringStream('__substg1.0_3A11')
1228
+
1229
+ @functools.cached_property
1230
+ def tddTelephoneNumber(self) -> Optional[str]:
1231
+ """
1232
+ The telephone number for the contact's text telephone (TTY) or
1233
+ telecommunication device for the deaf (TDD).
1234
+ """
1235
+ return self.getStringStream('__substg1.0_3A4B')
1236
+
1237
+ @functools.cached_property
1238
+ def telexNumber(self) -> Optional[Union[str, List[str]]]:
1239
+ """
1240
+ The contact's telex number(s).
1241
+ """
1242
+ return self.getSingleOrMultipleString('__substg1.0_3A2C')
1243
+
1244
+ @functools.cached_property
1245
+ def userX509Certificate(self) -> Optional[List[bytes]]:
1246
+ """
1247
+ A list of certificates for the contact.
1248
+ """
1249
+ return self.getMultipleBinary('3A70')
1250
+
1251
+ @functools.cached_property
1252
+ def weddingAnniversary(self) -> Optional[datetime.datetime]:
1253
+ """
1254
+ The wedding anniversary of the contact at 11:59 UTC.
1255
+ """
1256
+ return self.getPropertyVal('3A410040')
1257
+
1258
+ @functools.cached_property
1259
+ def weddingAnniversaryEventEntryID(self) -> Optional[EntryID]:
1260
+ """
1261
+ The EntryID of an optional Appointement object that represents the
1262
+ contact's wedding anniversary.
1263
+ """
1264
+ return self.getNamedAs('804E', ps.PSETID_ADDRESS, EntryID.autoCreate)
1265
+
1266
+ @functools.cached_property
1267
+ def weddingAnniversaryLocal(self) -> Optional[datetime.datetime]:
1268
+ """
1269
+ The wedding anniversary of the contact at 0:00 in the client's local
1270
+ time zone.
1271
+ """
1272
+ return self.getNamedProp('80DF', ps.PSETID_ADDRESS)
1273
+
1274
+ @functools.cached_property
1275
+ def webpageUrl(self) -> Optional[str]:
1276
+ """
1277
+ The contact's business web page url. SHOULD be the same as businessUrl.
1278
+ """
1279
+ return self.getNamedProp('802B', ps.PSETID_ADDRESS)
1280
+
1281
+ @functools.cached_property
1282
+ def workAddress(self) -> Optional[str]:
1283
+ """
1284
+ The complete work address of the contact.
1285
+ """
1286
+ return self.getNamedProp('801B', ps.PSETID_ADDRESS)
1287
+
1288
+ @functools.cached_property
1289
+ def workAddressCountry(self) -> Optional[str]:
1290
+ """
1291
+ The country portion of the contact's work address.
1292
+ """
1293
+ return self.getNamedProp('8049', ps.PSETID_ADDRESS)
1294
+
1295
+ @functools.cached_property
1296
+ def workAddressCountryCode(self) -> Optional[str]:
1297
+ """
1298
+ The country code portion of the contact's work address.
1299
+ """
1300
+ return self.getNamedProp('80DB', ps.PSETID_ADDRESS)
1301
+
1302
+ @functools.cached_property
1303
+ def workAddressLocality(self) -> Optional[str]:
1304
+ """
1305
+ The locality or city portion of the contact's work address.
1306
+ """
1307
+ return self.getNamedProp('8046', ps.PSETID_ADDRESS)
1308
+
1309
+ @functools.cached_property
1310
+ def workAddressPostalCode(self) -> Optional[str]:
1311
+ """
1312
+ The postal code portion of the contact's work address.
1313
+ """
1314
+ return self.getNamedProp('8048', ps.PSETID_ADDRESS)
1315
+
1316
+ @functools.cached_property
1317
+ def workAddressPostOfficeBox(self) -> Optional[str]:
1318
+ """
1319
+ The number or identifier of the contact's work post office box.
1320
+ """
1321
+ return self.getNamedProp('804A', ps.PSETID_ADDRESS)
1322
+
1323
+ @functools.cached_property
1324
+ def workAddressStateOrProvince(self) -> Optional[str]:
1325
+ """
1326
+ The state or province portion of the contact's work address.
1327
+ """
1328
+ return self.getNamedProp('8047', ps.PSETID_ADDRESS)
1329
+
1330
+ @functools.cached_property
1331
+ def workAddressStreet(self) -> Optional[str]:
1332
+ """
1333
+ The street portion of the contact's work address.
1334
+ """
1335
+ return self.getNamedProp('8045', ps.PSETID_ADDRESS)