@backtomyfuture/exchange-cli-win32-ia32 0.1.10
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.
- package/bin/_internal/VCRUNTIME140.dll +0 -0
- package/bin/_internal/_asyncio.pyd +0 -0
- package/bin/_internal/_bz2.pyd +0 -0
- package/bin/_internal/_cffi_backend.cp312-win32.pyd +0 -0
- package/bin/_internal/_ctypes.pyd +0 -0
- package/bin/_internal/_decimal.pyd +0 -0
- package/bin/_internal/_elementtree.pyd +0 -0
- package/bin/_internal/_hashlib.pyd +0 -0
- package/bin/_internal/_lzma.pyd +0 -0
- package/bin/_internal/_multiprocessing.pyd +0 -0
- package/bin/_internal/_overlapped.pyd +0 -0
- package/bin/_internal/_queue.pyd +0 -0
- package/bin/_internal/_socket.pyd +0 -0
- package/bin/_internal/_ssl.pyd +0 -0
- package/bin/_internal/_uuid.pyd +0 -0
- package/bin/_internal/_wmi.pyd +0 -0
- package/bin/_internal/_zoneinfo.pyd +0 -0
- package/bin/_internal/ada92cb5d92a588d1b93__mypyc.cp312-win32.pyd +0 -0
- package/bin/_internal/base_library.zip +0 -0
- package/bin/_internal/certifi/cacert.pem +3959 -0
- package/bin/_internal/certifi/py.typed +0 -0
- package/bin/_internal/charset_normalizer/cd.cp312-win32.pyd +0 -0
- package/bin/_internal/charset_normalizer/md.cp312-win32.pyd +0 -0
- package/bin/_internal/click-8.4.2.dist-info/INSTALLER +1 -0
- package/bin/_internal/click-8.4.2.dist-info/METADATA +84 -0
- package/bin/_internal/click-8.4.2.dist-info/RECORD +40 -0
- package/bin/_internal/click-8.4.2.dist-info/WHEEL +4 -0
- package/bin/_internal/click-8.4.2.dist-info/licenses/LICENSE.txt +28 -0
- package/bin/_internal/cryptography/hazmat/bindings/_rust.pyd +0 -0
- package/bin/_internal/cryptography-48.0.1.dist-info/INSTALLER +1 -0
- package/bin/_internal/cryptography-48.0.1.dist-info/METADATA +110 -0
- package/bin/_internal/cryptography-48.0.1.dist-info/RECORD +195 -0
- package/bin/_internal/cryptography-48.0.1.dist-info/WHEEL +4 -0
- package/bin/_internal/cryptography-48.0.1.dist-info/licenses/LICENSE +3 -0
- package/bin/_internal/cryptography-48.0.1.dist-info/licenses/LICENSE.APACHE +202 -0
- package/bin/_internal/cryptography-48.0.1.dist-info/licenses/LICENSE.BSD +27 -0
- package/bin/_internal/cryptography-48.0.1.dist-info/sboms/cryptography-rust.cyclonedx.json +1332 -0
- package/bin/_internal/cryptography-48.0.1.dist-info/sboms/sbom.json +43 -0
- package/bin/_internal/exchangelib/__init__.py +120 -0
- package/bin/_internal/exchangelib/account.py +896 -0
- package/bin/_internal/exchangelib/attachments.py +268 -0
- package/bin/_internal/exchangelib/autodiscover/__init__.py +24 -0
- package/bin/_internal/exchangelib/autodiscover/cache.py +150 -0
- package/bin/_internal/exchangelib/autodiscover/discovery.py +491 -0
- package/bin/_internal/exchangelib/autodiscover/protocol.py +58 -0
- package/bin/_internal/exchangelib/configuration.py +106 -0
- package/bin/_internal/exchangelib/credentials.py +319 -0
- package/bin/_internal/exchangelib/errors.py +1710 -0
- package/bin/_internal/exchangelib/ewsdatetime.py +309 -0
- package/bin/_internal/exchangelib/extended_properties.py +311 -0
- package/bin/_internal/exchangelib/fields.py +1842 -0
- package/bin/_internal/exchangelib/folders/__init__.py +249 -0
- package/bin/_internal/exchangelib/folders/base.py +954 -0
- package/bin/_internal/exchangelib/folders/collections.py +576 -0
- package/bin/_internal/exchangelib/folders/known_folders.py +856 -0
- package/bin/_internal/exchangelib/folders/queryset.py +187 -0
- package/bin/_internal/exchangelib/folders/roots.py +390 -0
- package/bin/_internal/exchangelib/indexed_properties.py +96 -0
- package/bin/_internal/exchangelib/items/__init__.py +147 -0
- package/bin/_internal/exchangelib/items/base.py +241 -0
- package/bin/_internal/exchangelib/items/calendar_item.py +466 -0
- package/bin/_internal/exchangelib/items/contact.py +263 -0
- package/bin/_internal/exchangelib/items/item.py +413 -0
- package/bin/_internal/exchangelib/items/message.py +201 -0
- package/bin/_internal/exchangelib/items/post.py +38 -0
- package/bin/_internal/exchangelib/items/task.py +139 -0
- package/bin/_internal/exchangelib/properties.py +2364 -0
- package/bin/_internal/exchangelib/protocol.py +823 -0
- package/bin/_internal/exchangelib/queryset.py +691 -0
- package/bin/_internal/exchangelib/recurrence.py +349 -0
- package/bin/_internal/exchangelib/restriction.py +568 -0
- package/bin/_internal/exchangelib/services/__init__.py +117 -0
- package/bin/_internal/exchangelib/services/archive_item.py +33 -0
- package/bin/_internal/exchangelib/services/common.py +983 -0
- package/bin/_internal/exchangelib/services/convert_id.py +45 -0
- package/bin/_internal/exchangelib/services/copy_item.py +7 -0
- package/bin/_internal/exchangelib/services/create_attachment.py +34 -0
- package/bin/_internal/exchangelib/services/create_folder.py +45 -0
- package/bin/_internal/exchangelib/services/create_item.py +97 -0
- package/bin/_internal/exchangelib/services/create_user_configuration.py +19 -0
- package/bin/_internal/exchangelib/services/delete_attachment.py +28 -0
- package/bin/_internal/exchangelib/services/delete_folder.py +21 -0
- package/bin/_internal/exchangelib/services/delete_item.py +51 -0
- package/bin/_internal/exchangelib/services/delete_user_configuration.py +19 -0
- package/bin/_internal/exchangelib/services/empty_folder.py +25 -0
- package/bin/_internal/exchangelib/services/expand_dl.py +21 -0
- package/bin/_internal/exchangelib/services/export_items.py +27 -0
- package/bin/_internal/exchangelib/services/find_folder.py +80 -0
- package/bin/_internal/exchangelib/services/find_item.py +112 -0
- package/bin/_internal/exchangelib/services/find_people.py +106 -0
- package/bin/_internal/exchangelib/services/get_attachment.py +117 -0
- package/bin/_internal/exchangelib/services/get_delegate.py +45 -0
- package/bin/_internal/exchangelib/services/get_events.py +39 -0
- package/bin/_internal/exchangelib/services/get_folder.py +65 -0
- package/bin/_internal/exchangelib/services/get_item.py +41 -0
- package/bin/_internal/exchangelib/services/get_mail_tips.py +43 -0
- package/bin/_internal/exchangelib/services/get_persona.py +31 -0
- package/bin/_internal/exchangelib/services/get_room_lists.py +21 -0
- package/bin/_internal/exchangelib/services/get_rooms.py +21 -0
- package/bin/_internal/exchangelib/services/get_searchable_mailboxes.py +48 -0
- package/bin/_internal/exchangelib/services/get_server_time_zones.py +39 -0
- package/bin/_internal/exchangelib/services/get_streaming_events.py +102 -0
- package/bin/_internal/exchangelib/services/get_user_availability.py +67 -0
- package/bin/_internal/exchangelib/services/get_user_configuration.py +43 -0
- package/bin/_internal/exchangelib/services/get_user_oof_settings.py +40 -0
- package/bin/_internal/exchangelib/services/get_user_settings.py +87 -0
- package/bin/_internal/exchangelib/services/inbox_rules.py +104 -0
- package/bin/_internal/exchangelib/services/mark_as_junk.py +27 -0
- package/bin/_internal/exchangelib/services/move_folder.py +27 -0
- package/bin/_internal/exchangelib/services/move_item.py +28 -0
- package/bin/_internal/exchangelib/services/resolve_names.py +104 -0
- package/bin/_internal/exchangelib/services/send_item.py +26 -0
- package/bin/_internal/exchangelib/services/send_notification.py +43 -0
- package/bin/_internal/exchangelib/services/set_user_oof_settings.py +34 -0
- package/bin/_internal/exchangelib/services/subscribe.py +125 -0
- package/bin/_internal/exchangelib/services/sync_folder_hierarchy.py +95 -0
- package/bin/_internal/exchangelib/services/sync_folder_items.py +77 -0
- package/bin/_internal/exchangelib/services/unsubscribe.py +21 -0
- package/bin/_internal/exchangelib/services/update_folder.py +158 -0
- package/bin/_internal/exchangelib/services/update_item.py +113 -0
- package/bin/_internal/exchangelib/services/update_user_configuration.py +17 -0
- package/bin/_internal/exchangelib/services/upload_items.py +47 -0
- package/bin/_internal/exchangelib/settings.py +88 -0
- package/bin/_internal/exchangelib/transport.py +214 -0
- package/bin/_internal/exchangelib/util.py +894 -0
- package/bin/_internal/exchangelib/version.py +320 -0
- package/bin/_internal/exchangelib/winzone.py +662 -0
- package/bin/_internal/exchangelib-5.6.0.dist-info/INSTALLER +1 -0
- package/bin/_internal/exchangelib-5.6.0.dist-info/METADATA +77 -0
- package/bin/_internal/exchangelib-5.6.0.dist-info/RECORD +184 -0
- package/bin/_internal/exchangelib-5.6.0.dist-info/WHEEL +5 -0
- package/bin/_internal/exchangelib-5.6.0.dist-info/licenses/LICENSE +21 -0
- package/bin/_internal/exchangelib-5.6.0.dist-info/top_level.txt +1 -0
- package/bin/_internal/libcrypto-3.dll +0 -0
- package/bin/_internal/libffi-8.dll +0 -0
- package/bin/_internal/libssl-3.dll +0 -0
- package/bin/_internal/lxml/_elementpath.cp312-win32.pyd +0 -0
- package/bin/_internal/lxml/builder.cp312-win32.pyd +0 -0
- package/bin/_internal/lxml/etree.cp312-win32.pyd +0 -0
- package/bin/_internal/lxml/html/_difflib.cp312-win32.pyd +0 -0
- package/bin/_internal/lxml/html/diff.cp312-win32.pyd +0 -0
- package/bin/_internal/lxml/isoschematron/resources/rng/iso-schematron.rng +709 -0
- package/bin/_internal/lxml/isoschematron/resources/xsl/RNG2Schtrn.xsl +75 -0
- package/bin/_internal/lxml/isoschematron/resources/xsl/XSD2Schtrn.xsl +77 -0
- package/bin/_internal/lxml/isoschematron/resources/xsl/iso-schematron-xslt1/iso_abstract_expand.xsl +313 -0
- package/bin/_internal/lxml/isoschematron/resources/xsl/iso-schematron-xslt1/iso_dsdl_include.xsl +1160 -0
- package/bin/_internal/lxml/isoschematron/resources/xsl/iso-schematron-xslt1/iso_schematron_message.xsl +55 -0
- package/bin/_internal/lxml/isoschematron/resources/xsl/iso-schematron-xslt1/iso_schematron_skeleton_for_xslt1.xsl +1796 -0
- package/bin/_internal/lxml/isoschematron/resources/xsl/iso-schematron-xslt1/iso_svrl_for_xslt1.xsl +588 -0
- package/bin/_internal/lxml/isoschematron/resources/xsl/iso-schematron-xslt1/readme.txt +84 -0
- package/bin/_internal/lxml/objectify.cp312-win32.pyd +0 -0
- package/bin/_internal/lxml/sax.cp312-win32.pyd +0 -0
- package/bin/_internal/pyexpat.pyd +0 -0
- package/bin/_internal/python3.dll +0 -0
- package/bin/_internal/python312.dll +0 -0
- package/bin/_internal/select.pyd +0 -0
- package/bin/_internal/setuptools/_vendor/jaraco/text/Lorem ipsum.txt +2 -0
- package/bin/_internal/sspilib/raw/_context_attributes.pyd +0 -0
- package/bin/_internal/sspilib/raw/_credential.pyd +0 -0
- package/bin/_internal/sspilib/raw/_credential_attributes.pyd +0 -0
- package/bin/_internal/sspilib/raw/_message.pyd +0 -0
- package/bin/_internal/sspilib/raw/_ntstatus.pyd +0 -0
- package/bin/_internal/sspilib/raw/_security_buffer.pyd +0 -0
- package/bin/_internal/sspilib/raw/_security_context.pyd +0 -0
- package/bin/_internal/sspilib/raw/_security_package.pyd +0 -0
- package/bin/_internal/sspilib/raw/_text.pyd +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Abidjan +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Accra +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Addis_Ababa +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Algiers +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Asmara +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Asmera +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Bamako +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Bangui +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Banjul +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Bissau +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Blantyre +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Brazzaville +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Bujumbura +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Cairo +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Casablanca +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Ceuta +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Conakry +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Dakar +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Dar_es_Salaam +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Djibouti +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Douala +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/El_Aaiun +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Freetown +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Gaborone +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Harare +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Johannesburg +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Juba +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Kampala +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Khartoum +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Kigali +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Kinshasa +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Lagos +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Libreville +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Lome +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Luanda +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Lubumbashi +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Lusaka +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Malabo +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Maputo +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Maseru +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Mbabane +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Mogadishu +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Monrovia +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Nairobi +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Ndjamena +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Niamey +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Nouakchott +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Ouagadougou +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Porto-Novo +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Sao_Tome +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Timbuktu +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Tripoli +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Tunis +0 -0
- package/bin/_internal/tzdata/zoneinfo/Africa/Windhoek +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Adak +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Anchorage +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Anguilla +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Antigua +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Araguaina +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Argentina/Buenos_Aires +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Argentina/Catamarca +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Argentina/ComodRivadavia +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Argentina/Cordoba +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Argentina/Jujuy +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Argentina/La_Rioja +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Argentina/Mendoza +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Argentina/Rio_Gallegos +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Argentina/Salta +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Argentina/San_Juan +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Argentina/San_Luis +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Argentina/Tucuman +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Argentina/Ushuaia +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Aruba +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Asuncion +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Atikokan +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Atka +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Bahia +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Bahia_Banderas +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Barbados +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Belem +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Belize +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Blanc-Sablon +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Boa_Vista +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Bogota +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Boise +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Buenos_Aires +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Cambridge_Bay +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Campo_Grande +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Cancun +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Caracas +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Catamarca +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Cayenne +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Cayman +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Chicago +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Chihuahua +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Ciudad_Juarez +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Coral_Harbour +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Cordoba +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Costa_Rica +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Coyhaique +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Creston +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Cuiaba +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Curacao +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Danmarkshavn +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Dawson +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Dawson_Creek +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Denver +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Detroit +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Dominica +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Edmonton +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Eirunepe +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/El_Salvador +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Ensenada +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Fort_Nelson +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Fort_Wayne +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Fortaleza +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Glace_Bay +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Godthab +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Goose_Bay +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Grand_Turk +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Grenada +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Guadeloupe +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Guatemala +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Guayaquil +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Guyana +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Halifax +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Havana +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Hermosillo +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Indiana/Indianapolis +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Indiana/Knox +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Indiana/Marengo +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Indiana/Petersburg +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Indiana/Tell_City +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Indiana/Vevay +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Indiana/Vincennes +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Indiana/Winamac +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Indianapolis +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Inuvik +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Iqaluit +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Jamaica +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Jujuy +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Juneau +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Kentucky/Louisville +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Kentucky/Monticello +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Knox_IN +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Kralendijk +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/La_Paz +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Lima +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Los_Angeles +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Louisville +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Lower_Princes +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Maceio +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Managua +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Manaus +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Marigot +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Martinique +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Matamoros +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Mazatlan +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Mendoza +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Menominee +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Merida +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Metlakatla +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Mexico_City +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Miquelon +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Moncton +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Monterrey +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Montevideo +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Montreal +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Montserrat +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Nassau +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/New_York +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Nipigon +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Nome +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Noronha +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/North_Dakota/Beulah +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/North_Dakota/Center +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/North_Dakota/New_Salem +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Nuuk +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Ojinaga +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Panama +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Pangnirtung +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Paramaribo +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Phoenix +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Port-au-Prince +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Port_of_Spain +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Porto_Acre +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Porto_Velho +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Puerto_Rico +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Punta_Arenas +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Rainy_River +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Rankin_Inlet +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Recife +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Regina +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Resolute +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Rio_Branco +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Rosario +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Santa_Isabel +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Santarem +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Santiago +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Santo_Domingo +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Sao_Paulo +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Scoresbysund +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Shiprock +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Sitka +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/St_Barthelemy +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/St_Johns +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/St_Kitts +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/St_Lucia +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/St_Thomas +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/St_Vincent +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Swift_Current +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Tegucigalpa +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Thule +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Thunder_Bay +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Tijuana +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Toronto +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Tortola +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Vancouver +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Virgin +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Whitehorse +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Winnipeg +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Yakutat +0 -0
- package/bin/_internal/tzdata/zoneinfo/America/Yellowknife +0 -0
- package/bin/_internal/tzdata/zoneinfo/Antarctica/Casey +0 -0
- package/bin/_internal/tzdata/zoneinfo/Antarctica/Davis +0 -0
- package/bin/_internal/tzdata/zoneinfo/Antarctica/DumontDUrville +0 -0
- package/bin/_internal/tzdata/zoneinfo/Antarctica/Macquarie +0 -0
- package/bin/_internal/tzdata/zoneinfo/Antarctica/Mawson +0 -0
- package/bin/_internal/tzdata/zoneinfo/Antarctica/McMurdo +0 -0
- package/bin/_internal/tzdata/zoneinfo/Antarctica/Palmer +0 -0
- package/bin/_internal/tzdata/zoneinfo/Antarctica/Rothera +0 -0
- package/bin/_internal/tzdata/zoneinfo/Antarctica/South_Pole +0 -0
- package/bin/_internal/tzdata/zoneinfo/Antarctica/Syowa +0 -0
- package/bin/_internal/tzdata/zoneinfo/Antarctica/Troll +0 -0
- package/bin/_internal/tzdata/zoneinfo/Antarctica/Vostok +0 -0
- package/bin/_internal/tzdata/zoneinfo/Arctic/Longyearbyen +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Aden +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Almaty +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Amman +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Anadyr +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Aqtau +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Aqtobe +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Ashgabat +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Ashkhabad +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Atyrau +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Baghdad +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Bahrain +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Baku +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Bangkok +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Barnaul +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Beirut +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Bishkek +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Brunei +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Calcutta +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Chita +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Choibalsan +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Chongqing +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Chungking +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Colombo +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Dacca +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Damascus +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Dhaka +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Dili +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Dubai +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Dushanbe +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Famagusta +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Gaza +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Harbin +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Hebron +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Ho_Chi_Minh +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Hong_Kong +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Hovd +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Irkutsk +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Istanbul +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Jakarta +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Jayapura +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Jerusalem +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Kabul +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Kamchatka +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Karachi +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Kashgar +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Kathmandu +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Katmandu +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Khandyga +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Kolkata +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Krasnoyarsk +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Kuala_Lumpur +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Kuching +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Kuwait +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Macao +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Macau +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Magadan +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Makassar +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Manila +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Muscat +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Nicosia +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Novokuznetsk +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Novosibirsk +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Omsk +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Oral +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Phnom_Penh +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Pontianak +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Pyongyang +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Qatar +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Qostanay +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Qyzylorda +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Rangoon +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Riyadh +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Saigon +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Sakhalin +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Samarkand +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Seoul +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Shanghai +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Singapore +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Srednekolymsk +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Taipei +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Tashkent +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Tbilisi +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Tehran +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Tel_Aviv +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Thimbu +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Thimphu +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Tokyo +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Tomsk +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Ujung_Pandang +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Ulaanbaatar +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Ulan_Bator +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Urumqi +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Ust-Nera +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Vientiane +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Vladivostok +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Yakutsk +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Yangon +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Yekaterinburg +0 -0
- package/bin/_internal/tzdata/zoneinfo/Asia/Yerevan +0 -0
- package/bin/_internal/tzdata/zoneinfo/Atlantic/Azores +0 -0
- package/bin/_internal/tzdata/zoneinfo/Atlantic/Bermuda +0 -0
- package/bin/_internal/tzdata/zoneinfo/Atlantic/Canary +0 -0
- package/bin/_internal/tzdata/zoneinfo/Atlantic/Cape_Verde +0 -0
- package/bin/_internal/tzdata/zoneinfo/Atlantic/Faeroe +0 -0
- package/bin/_internal/tzdata/zoneinfo/Atlantic/Faroe +0 -0
- package/bin/_internal/tzdata/zoneinfo/Atlantic/Jan_Mayen +0 -0
- package/bin/_internal/tzdata/zoneinfo/Atlantic/Madeira +0 -0
- package/bin/_internal/tzdata/zoneinfo/Atlantic/Reykjavik +0 -0
- package/bin/_internal/tzdata/zoneinfo/Atlantic/South_Georgia +0 -0
- package/bin/_internal/tzdata/zoneinfo/Atlantic/St_Helena +0 -0
- package/bin/_internal/tzdata/zoneinfo/Atlantic/Stanley +0 -0
- package/bin/_internal/tzdata/zoneinfo/Australia/ACT +0 -0
- package/bin/_internal/tzdata/zoneinfo/Australia/Adelaide +0 -0
- package/bin/_internal/tzdata/zoneinfo/Australia/Brisbane +0 -0
- package/bin/_internal/tzdata/zoneinfo/Australia/Broken_Hill +0 -0
- package/bin/_internal/tzdata/zoneinfo/Australia/Canberra +0 -0
- package/bin/_internal/tzdata/zoneinfo/Australia/Currie +0 -0
- package/bin/_internal/tzdata/zoneinfo/Australia/Darwin +0 -0
- package/bin/_internal/tzdata/zoneinfo/Australia/Eucla +0 -0
- package/bin/_internal/tzdata/zoneinfo/Australia/Hobart +0 -0
- package/bin/_internal/tzdata/zoneinfo/Australia/LHI +0 -0
- package/bin/_internal/tzdata/zoneinfo/Australia/Lindeman +0 -0
- package/bin/_internal/tzdata/zoneinfo/Australia/Lord_Howe +0 -0
- package/bin/_internal/tzdata/zoneinfo/Australia/Melbourne +0 -0
- package/bin/_internal/tzdata/zoneinfo/Australia/NSW +0 -0
- package/bin/_internal/tzdata/zoneinfo/Australia/North +0 -0
- package/bin/_internal/tzdata/zoneinfo/Australia/Perth +0 -0
- package/bin/_internal/tzdata/zoneinfo/Australia/Queensland +0 -0
- package/bin/_internal/tzdata/zoneinfo/Australia/South +0 -0
- package/bin/_internal/tzdata/zoneinfo/Australia/Sydney +0 -0
- package/bin/_internal/tzdata/zoneinfo/Australia/Tasmania +0 -0
- package/bin/_internal/tzdata/zoneinfo/Australia/Victoria +0 -0
- package/bin/_internal/tzdata/zoneinfo/Australia/West +0 -0
- package/bin/_internal/tzdata/zoneinfo/Australia/Yancowinna +0 -0
- package/bin/_internal/tzdata/zoneinfo/Brazil/Acre +0 -0
- package/bin/_internal/tzdata/zoneinfo/Brazil/DeNoronha +0 -0
- package/bin/_internal/tzdata/zoneinfo/Brazil/East +0 -0
- package/bin/_internal/tzdata/zoneinfo/Brazil/West +0 -0
- package/bin/_internal/tzdata/zoneinfo/CET +0 -0
- package/bin/_internal/tzdata/zoneinfo/CST6CDT +0 -0
- package/bin/_internal/tzdata/zoneinfo/Canada/Atlantic +0 -0
- package/bin/_internal/tzdata/zoneinfo/Canada/Central +0 -0
- package/bin/_internal/tzdata/zoneinfo/Canada/Eastern +0 -0
- package/bin/_internal/tzdata/zoneinfo/Canada/Mountain +0 -0
- package/bin/_internal/tzdata/zoneinfo/Canada/Newfoundland +0 -0
- package/bin/_internal/tzdata/zoneinfo/Canada/Pacific +0 -0
- package/bin/_internal/tzdata/zoneinfo/Canada/Saskatchewan +0 -0
- package/bin/_internal/tzdata/zoneinfo/Canada/Yukon +0 -0
- package/bin/_internal/tzdata/zoneinfo/Chile/Continental +0 -0
- package/bin/_internal/tzdata/zoneinfo/Chile/EasterIsland +0 -0
- package/bin/_internal/tzdata/zoneinfo/Cuba +0 -0
- package/bin/_internal/tzdata/zoneinfo/EET +0 -0
- package/bin/_internal/tzdata/zoneinfo/EST +0 -0
- package/bin/_internal/tzdata/zoneinfo/EST5EDT +0 -0
- package/bin/_internal/tzdata/zoneinfo/Egypt +0 -0
- package/bin/_internal/tzdata/zoneinfo/Eire +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/GMT +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/GMT+0 +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/GMT+1 +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/GMT+10 +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/GMT+11 +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/GMT+12 +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/GMT+2 +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/GMT+3 +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/GMT+4 +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/GMT+5 +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/GMT+6 +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/GMT+7 +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/GMT+8 +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/GMT+9 +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/GMT-0 +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/GMT-1 +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/GMT-10 +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/GMT-11 +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/GMT-12 +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/GMT-13 +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/GMT-14 +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/GMT-2 +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/GMT-3 +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/GMT-4 +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/GMT-5 +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/GMT-6 +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/GMT-7 +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/GMT-8 +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/GMT-9 +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/GMT0 +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/Greenwich +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/UCT +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/UTC +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/Universal +0 -0
- package/bin/_internal/tzdata/zoneinfo/Etc/Zulu +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Amsterdam +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Andorra +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Astrakhan +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Athens +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Belfast +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Belgrade +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Berlin +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Bratislava +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Brussels +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Bucharest +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Budapest +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Busingen +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Chisinau +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Copenhagen +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Dublin +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Gibraltar +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Guernsey +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Helsinki +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Isle_of_Man +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Istanbul +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Jersey +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Kaliningrad +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Kiev +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Kirov +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Kyiv +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Lisbon +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Ljubljana +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/London +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Luxembourg +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Madrid +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Malta +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Mariehamn +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Minsk +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Monaco +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Moscow +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Nicosia +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Oslo +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Paris +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Podgorica +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Prague +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Riga +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Rome +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Samara +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/San_Marino +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Sarajevo +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Saratov +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Simferopol +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Skopje +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Sofia +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Stockholm +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Tallinn +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Tirane +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Tiraspol +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Ulyanovsk +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Uzhgorod +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Vaduz +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Vatican +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Vienna +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Vilnius +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Volgograd +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Warsaw +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Zagreb +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Zaporozhye +0 -0
- package/bin/_internal/tzdata/zoneinfo/Europe/Zurich +0 -0
- package/bin/_internal/tzdata/zoneinfo/Factory +0 -0
- package/bin/_internal/tzdata/zoneinfo/GB +0 -0
- package/bin/_internal/tzdata/zoneinfo/GB-Eire +0 -0
- package/bin/_internal/tzdata/zoneinfo/GMT +0 -0
- package/bin/_internal/tzdata/zoneinfo/GMT+0 +0 -0
- package/bin/_internal/tzdata/zoneinfo/GMT-0 +0 -0
- package/bin/_internal/tzdata/zoneinfo/GMT0 +0 -0
- package/bin/_internal/tzdata/zoneinfo/Greenwich +0 -0
- package/bin/_internal/tzdata/zoneinfo/HST +0 -0
- package/bin/_internal/tzdata/zoneinfo/Hongkong +0 -0
- package/bin/_internal/tzdata/zoneinfo/Iceland +0 -0
- package/bin/_internal/tzdata/zoneinfo/Indian/Antananarivo +0 -0
- package/bin/_internal/tzdata/zoneinfo/Indian/Chagos +0 -0
- package/bin/_internal/tzdata/zoneinfo/Indian/Christmas +0 -0
- package/bin/_internal/tzdata/zoneinfo/Indian/Cocos +0 -0
- package/bin/_internal/tzdata/zoneinfo/Indian/Comoro +0 -0
- package/bin/_internal/tzdata/zoneinfo/Indian/Kerguelen +0 -0
- package/bin/_internal/tzdata/zoneinfo/Indian/Mahe +0 -0
- package/bin/_internal/tzdata/zoneinfo/Indian/Maldives +0 -0
- package/bin/_internal/tzdata/zoneinfo/Indian/Mauritius +0 -0
- package/bin/_internal/tzdata/zoneinfo/Indian/Mayotte +0 -0
- package/bin/_internal/tzdata/zoneinfo/Indian/Reunion +0 -0
- package/bin/_internal/tzdata/zoneinfo/Iran +0 -0
- package/bin/_internal/tzdata/zoneinfo/Israel +0 -0
- package/bin/_internal/tzdata/zoneinfo/Jamaica +0 -0
- package/bin/_internal/tzdata/zoneinfo/Japan +0 -0
- package/bin/_internal/tzdata/zoneinfo/Kwajalein +0 -0
- package/bin/_internal/tzdata/zoneinfo/Libya +0 -0
- package/bin/_internal/tzdata/zoneinfo/MET +0 -0
- package/bin/_internal/tzdata/zoneinfo/MST +0 -0
- package/bin/_internal/tzdata/zoneinfo/MST7MDT +0 -0
- package/bin/_internal/tzdata/zoneinfo/Mexico/BajaNorte +0 -0
- package/bin/_internal/tzdata/zoneinfo/Mexico/BajaSur +0 -0
- package/bin/_internal/tzdata/zoneinfo/Mexico/General +0 -0
- package/bin/_internal/tzdata/zoneinfo/NZ +0 -0
- package/bin/_internal/tzdata/zoneinfo/NZ-CHAT +0 -0
- package/bin/_internal/tzdata/zoneinfo/Navajo +0 -0
- package/bin/_internal/tzdata/zoneinfo/PRC +0 -0
- package/bin/_internal/tzdata/zoneinfo/PST8PDT +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Apia +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Auckland +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Bougainville +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Chatham +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Chuuk +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Easter +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Efate +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Enderbury +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Fakaofo +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Fiji +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Funafuti +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Galapagos +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Gambier +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Guadalcanal +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Guam +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Honolulu +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Johnston +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Kanton +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Kiritimati +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Kosrae +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Kwajalein +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Majuro +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Marquesas +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Midway +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Nauru +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Niue +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Norfolk +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Noumea +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Pago_Pago +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Palau +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Pitcairn +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Pohnpei +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Ponape +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Port_Moresby +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Rarotonga +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Saipan +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Samoa +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Tahiti +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Tarawa +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Tongatapu +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Truk +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Wake +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Wallis +0 -0
- package/bin/_internal/tzdata/zoneinfo/Pacific/Yap +0 -0
- package/bin/_internal/tzdata/zoneinfo/Poland +0 -0
- package/bin/_internal/tzdata/zoneinfo/Portugal +0 -0
- package/bin/_internal/tzdata/zoneinfo/ROC +0 -0
- package/bin/_internal/tzdata/zoneinfo/ROK +0 -0
- package/bin/_internal/tzdata/zoneinfo/Singapore +0 -0
- package/bin/_internal/tzdata/zoneinfo/Turkey +0 -0
- package/bin/_internal/tzdata/zoneinfo/UCT +0 -0
- package/bin/_internal/tzdata/zoneinfo/US/Alaska +0 -0
- package/bin/_internal/tzdata/zoneinfo/US/Aleutian +0 -0
- package/bin/_internal/tzdata/zoneinfo/US/Arizona +0 -0
- package/bin/_internal/tzdata/zoneinfo/US/Central +0 -0
- package/bin/_internal/tzdata/zoneinfo/US/East-Indiana +0 -0
- package/bin/_internal/tzdata/zoneinfo/US/Eastern +0 -0
- package/bin/_internal/tzdata/zoneinfo/US/Hawaii +0 -0
- package/bin/_internal/tzdata/zoneinfo/US/Indiana-Starke +0 -0
- package/bin/_internal/tzdata/zoneinfo/US/Michigan +0 -0
- package/bin/_internal/tzdata/zoneinfo/US/Mountain +0 -0
- package/bin/_internal/tzdata/zoneinfo/US/Pacific +0 -0
- package/bin/_internal/tzdata/zoneinfo/US/Samoa +0 -0
- package/bin/_internal/tzdata/zoneinfo/UTC +0 -0
- package/bin/_internal/tzdata/zoneinfo/Universal +0 -0
- package/bin/_internal/tzdata/zoneinfo/W-SU +0 -0
- package/bin/_internal/tzdata/zoneinfo/WET +0 -0
- package/bin/_internal/tzdata/zoneinfo/Zulu +0 -0
- package/bin/_internal/tzdata/zoneinfo/iso3166.tab +279 -0
- package/bin/_internal/tzdata/zoneinfo/leapseconds +86 -0
- package/bin/_internal/tzdata/zoneinfo/tzdata.zi +4180 -0
- package/bin/_internal/tzdata/zoneinfo/zone.tab +448 -0
- package/bin/_internal/tzdata/zoneinfo/zone1970.tab +375 -0
- package/bin/_internal/tzdata/zoneinfo/zonenow.tab +299 -0
- package/bin/_internal/tzdata/zones +598 -0
- package/bin/_internal/unicodedata.pyd +0 -0
- package/bin/exchange-cli.exe +0 -0
- package/package.json +20 -0
|
@@ -0,0 +1,2364 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
import binascii
|
|
3
|
+
import codecs
|
|
4
|
+
import datetime
|
|
5
|
+
import logging
|
|
6
|
+
import struct
|
|
7
|
+
from inspect import getmro
|
|
8
|
+
from threading import Lock
|
|
9
|
+
|
|
10
|
+
from .errors import (
|
|
11
|
+
AutoDiscoverFailed,
|
|
12
|
+
ErrorInternalServerError,
|
|
13
|
+
ErrorNonExistentMailbox,
|
|
14
|
+
ErrorOrganizationNotFederated,
|
|
15
|
+
ErrorServerBusy,
|
|
16
|
+
InvalidTypeError,
|
|
17
|
+
)
|
|
18
|
+
from .fields import (
|
|
19
|
+
WEEKDAY_NAMES,
|
|
20
|
+
AddressListField,
|
|
21
|
+
AssociatedCalendarItemIdField,
|
|
22
|
+
Base64Field,
|
|
23
|
+
BooleanField,
|
|
24
|
+
CharField,
|
|
25
|
+
CharListField,
|
|
26
|
+
Choice,
|
|
27
|
+
ChoiceField,
|
|
28
|
+
DateTimeBackedDateField,
|
|
29
|
+
DateTimeField,
|
|
30
|
+
DictionaryField,
|
|
31
|
+
EmailAddressField,
|
|
32
|
+
EmailField,
|
|
33
|
+
EnumField,
|
|
34
|
+
EnumListField,
|
|
35
|
+
EWSElementField,
|
|
36
|
+
EWSElementListField,
|
|
37
|
+
ExtendedPropertyField,
|
|
38
|
+
Field,
|
|
39
|
+
FieldPath,
|
|
40
|
+
FlaggedForActionField,
|
|
41
|
+
FolderActionField,
|
|
42
|
+
FreeBusyStatusField,
|
|
43
|
+
GenericEventListField,
|
|
44
|
+
IdElementField,
|
|
45
|
+
IdField,
|
|
46
|
+
ImportanceField,
|
|
47
|
+
IntegerField,
|
|
48
|
+
InvalidField,
|
|
49
|
+
InvalidFieldForVersion,
|
|
50
|
+
MailboxField,
|
|
51
|
+
MessageField,
|
|
52
|
+
RecipientAddressField,
|
|
53
|
+
ReferenceItemIdField,
|
|
54
|
+
RoutingTypeField,
|
|
55
|
+
SensitivityField,
|
|
56
|
+
SubField,
|
|
57
|
+
TextField,
|
|
58
|
+
TimeDeltaField,
|
|
59
|
+
TimeField,
|
|
60
|
+
TransitionListField,
|
|
61
|
+
TypeValueField,
|
|
62
|
+
UnknownEntriesField,
|
|
63
|
+
)
|
|
64
|
+
from .util import ANS, MNS, TNS, create_element, get_xml_attr, set_xml_value, value_to_xml_text
|
|
65
|
+
from .version import EXCHANGE_2013, Build, Version
|
|
66
|
+
|
|
67
|
+
log = logging.getLogger(__name__)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class Fields(list):
|
|
71
|
+
"""A collection type for the FIELDS class attribute. Works like a list but supports fast lookup by name."""
|
|
72
|
+
|
|
73
|
+
def __init__(self, *fields):
|
|
74
|
+
super().__init__(fields)
|
|
75
|
+
self._dict = {}
|
|
76
|
+
for f in fields:
|
|
77
|
+
# Check for duplicate field names
|
|
78
|
+
if f.name in self._dict:
|
|
79
|
+
raise ValueError(f"Field {f!r} is a duplicate")
|
|
80
|
+
self._dict[f.name] = f
|
|
81
|
+
|
|
82
|
+
def __getitem__(self, idx_or_slice):
|
|
83
|
+
# Support fast lookup by name. Make sure slicing returns an instance of this class
|
|
84
|
+
if isinstance(idx_or_slice, str):
|
|
85
|
+
return self._dict[idx_or_slice]
|
|
86
|
+
if isinstance(idx_or_slice, int):
|
|
87
|
+
return super().__getitem__(idx_or_slice)
|
|
88
|
+
res = super().__getitem__(idx_or_slice)
|
|
89
|
+
return self.__class__(*res)
|
|
90
|
+
|
|
91
|
+
def __add__(self, other):
|
|
92
|
+
# Make sure addition returns an instance of this class
|
|
93
|
+
res = super().__add__(other)
|
|
94
|
+
return self.__class__(*res)
|
|
95
|
+
|
|
96
|
+
def __iadd__(self, other):
|
|
97
|
+
for f in other:
|
|
98
|
+
self.append(f)
|
|
99
|
+
return self
|
|
100
|
+
|
|
101
|
+
def __contains__(self, item):
|
|
102
|
+
return item in self._dict
|
|
103
|
+
|
|
104
|
+
def copy(self):
|
|
105
|
+
return self.__class__(*self)
|
|
106
|
+
|
|
107
|
+
def index_by_name(self, field_name):
|
|
108
|
+
for i, f in enumerate(self):
|
|
109
|
+
if f.name == field_name:
|
|
110
|
+
return i
|
|
111
|
+
raise ValueError(f"Unknown field name {field_name!r}")
|
|
112
|
+
|
|
113
|
+
def insert(self, index, field):
|
|
114
|
+
if field.name in self._dict:
|
|
115
|
+
raise ValueError(f"Field {field!r} is a duplicate")
|
|
116
|
+
super().insert(index, field)
|
|
117
|
+
self._dict[field.name] = field
|
|
118
|
+
|
|
119
|
+
def remove(self, field):
|
|
120
|
+
super().remove(field)
|
|
121
|
+
del self._dict[field.name]
|
|
122
|
+
|
|
123
|
+
def append(self, field):
|
|
124
|
+
super().append(field)
|
|
125
|
+
self._dict[field.name] = field
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class Body(str):
|
|
129
|
+
"""Helper to mark the 'body' field as a complex attribute.
|
|
130
|
+
|
|
131
|
+
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/body
|
|
132
|
+
"""
|
|
133
|
+
|
|
134
|
+
body_type = "Text"
|
|
135
|
+
|
|
136
|
+
def __add__(self, other):
|
|
137
|
+
# Make sure Body('') + 'foo' returns a Body type
|
|
138
|
+
return self.__class__(super().__add__(other))
|
|
139
|
+
|
|
140
|
+
def __mod__(self, other):
|
|
141
|
+
# Make sure Body('%s') % 'foo' returns a Body type
|
|
142
|
+
return self.__class__(super().__mod__(other))
|
|
143
|
+
|
|
144
|
+
def format(self, *args, **kwargs):
|
|
145
|
+
# Make sure Body('{}').format('foo') returns a Body type
|
|
146
|
+
return self.__class__(super().format(*args, **kwargs))
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
class HTMLBody(Body):
|
|
150
|
+
"""Helper to mark the 'body' field as a complex attribute.
|
|
151
|
+
|
|
152
|
+
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/body
|
|
153
|
+
"""
|
|
154
|
+
|
|
155
|
+
body_type = "HTML"
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
class UID(bytes):
|
|
159
|
+
"""Helper class to encode Calendar UIDs. See issue #453. Example:
|
|
160
|
+
|
|
161
|
+
class GlobalObjectId(ExtendedProperty):
|
|
162
|
+
distinguished_property_set_id = 'Meeting'
|
|
163
|
+
property_id = 3
|
|
164
|
+
property_type = 'Binary'
|
|
165
|
+
|
|
166
|
+
CalendarItem.register('global_object_id', GlobalObjectId)
|
|
167
|
+
account.calendar.filter(global_object_id=UID('261cbc18-1f65-5a0a-bd11-23b1e224cc2f'))
|
|
168
|
+
"""
|
|
169
|
+
|
|
170
|
+
_HEADER = binascii.hexlify(
|
|
171
|
+
bytearray((0x04, 0x00, 0x00, 0x00, 0x82, 0x00, 0xE0, 0x00, 0x74, 0xC5, 0xB7, 0x10, 0x1A, 0x82, 0xE0, 0x08))
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
_EXCEPTION_REPLACEMENT_TIME = binascii.hexlify(bytearray((0, 0, 0, 0)))
|
|
175
|
+
|
|
176
|
+
_CREATION_TIME = binascii.hexlify(bytearray((0, 0, 0, 0, 0, 0, 0, 0)))
|
|
177
|
+
|
|
178
|
+
_RESERVED = binascii.hexlify(bytearray((0, 0, 0, 0, 0, 0, 0, 0)))
|
|
179
|
+
|
|
180
|
+
# https://docs.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-oxocal/1d3aac05-a7b9-45cc-a213-47f0a0a2c5c1
|
|
181
|
+
# https://docs.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-asemail/e7424ddc-dd10-431e-a0b7-5c794863370e
|
|
182
|
+
# https://stackoverflow.com/questions/42259122
|
|
183
|
+
# https://stackoverflow.com/questions/33757805
|
|
184
|
+
|
|
185
|
+
def __new__(cls, uid):
|
|
186
|
+
payload = binascii.hexlify(bytearray(f"vCal-Uid\x01\x00\x00\x00{uid}\x00".encode("ascii")))
|
|
187
|
+
length = binascii.hexlify(bytearray(struct.pack("<I", int(len(payload) / 2))))
|
|
188
|
+
encoding = b"".join(
|
|
189
|
+
[cls._HEADER, cls._EXCEPTION_REPLACEMENT_TIME, cls._CREATION_TIME, cls._RESERVED, length, payload]
|
|
190
|
+
)
|
|
191
|
+
return super().__new__(cls, codecs.decode(encoding, "hex"))
|
|
192
|
+
|
|
193
|
+
@classmethod
|
|
194
|
+
def to_global_object_id(cls, uid):
|
|
195
|
+
"""Converts a UID as returned by EWS to GlobalObjectId format"""
|
|
196
|
+
return binascii.unhexlify(uid)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def _mangle(field_name):
|
|
200
|
+
return f"__{field_name}"
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
class EWSMeta(type, metaclass=abc.ABCMeta):
|
|
204
|
+
def __new__(mcs, name, bases, kwargs):
|
|
205
|
+
# Collect fields defined directly on the class
|
|
206
|
+
local_fields = Fields()
|
|
207
|
+
for k in tuple(kwargs.keys()):
|
|
208
|
+
v = kwargs[k]
|
|
209
|
+
if isinstance(v, Field):
|
|
210
|
+
v.name = k
|
|
211
|
+
local_fields.append(v)
|
|
212
|
+
del kwargs[k]
|
|
213
|
+
|
|
214
|
+
# Build a list of fields defined on this and all base classes
|
|
215
|
+
base_fields = Fields()
|
|
216
|
+
for base in bases:
|
|
217
|
+
if hasattr(base, "FIELDS"):
|
|
218
|
+
base_fields += base.FIELDS
|
|
219
|
+
|
|
220
|
+
# FIELDS defined on a model overrides the base class fields
|
|
221
|
+
fields = kwargs.get("FIELDS", base_fields) + local_fields
|
|
222
|
+
|
|
223
|
+
# Include all fields as class attributes, so we can use them as instance attributes
|
|
224
|
+
kwargs.update({_mangle(f.name): f for f in fields})
|
|
225
|
+
|
|
226
|
+
# Calculate __slots__ so we don't have to hard-code it on the model
|
|
227
|
+
kwargs["__slots__"] = tuple(f.name for f in fields if f.name not in base_fields) + kwargs.get("__slots__", ())
|
|
228
|
+
|
|
229
|
+
# FIELDS is mentioned in docs and expected by internal code. Add it here, but only if the class has its own
|
|
230
|
+
# fields. Otherwise, we want the implicit FIELDS from the base class (used for injecting custom fields on the
|
|
231
|
+
# Folder class, making the custom field available for subclasses).
|
|
232
|
+
if local_fields:
|
|
233
|
+
kwargs["FIELDS"] = fields
|
|
234
|
+
klass = super().__new__(mcs, name, bases, kwargs)
|
|
235
|
+
klass._slots_keys = mcs._get_slots_keys(klass)
|
|
236
|
+
return klass
|
|
237
|
+
|
|
238
|
+
@staticmethod
|
|
239
|
+
def _get_slots_keys(klass):
|
|
240
|
+
seen = set()
|
|
241
|
+
keys = []
|
|
242
|
+
for c in reversed(getmro(klass)):
|
|
243
|
+
if not hasattr(c, "__slots__"):
|
|
244
|
+
continue
|
|
245
|
+
for k in c.__slots__:
|
|
246
|
+
if k in seen:
|
|
247
|
+
# We allow duplicate keys because we don't want to require subclasses of e.g.
|
|
248
|
+
# ExtendedProperty to define an empty __slots__ class attribute.
|
|
249
|
+
continue
|
|
250
|
+
keys.append(k)
|
|
251
|
+
seen.add(k)
|
|
252
|
+
return keys
|
|
253
|
+
|
|
254
|
+
def __getattribute__(cls, k):
|
|
255
|
+
"""Return Field instances via their mangled class attribute"""
|
|
256
|
+
try:
|
|
257
|
+
return super().__getattribute__("__dict__")[_mangle(k)]
|
|
258
|
+
except KeyError:
|
|
259
|
+
return super().__getattribute__(k)
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
class EWSElement(metaclass=EWSMeta):
|
|
263
|
+
"""Base class for all XML element implementations."""
|
|
264
|
+
|
|
265
|
+
ELEMENT_NAME = None # The name of the XML tag
|
|
266
|
+
FIELDS = Fields() # A list of attributes supported by this item class, ordered the same way as in EWS documentation
|
|
267
|
+
NAMESPACE = TNS # The XML tag namespace. Either TNS or MNS
|
|
268
|
+
|
|
269
|
+
_fields_lock = Lock()
|
|
270
|
+
|
|
271
|
+
def __init__(self, **kwargs):
|
|
272
|
+
for f in self.FIELDS:
|
|
273
|
+
setattr(self, f.name, kwargs.pop(f.name, None))
|
|
274
|
+
if kwargs:
|
|
275
|
+
raise AttributeError(f"{sorted(kwargs.keys())!r} are invalid kwargs for this class")
|
|
276
|
+
|
|
277
|
+
def __setattr__(self, key, value):
|
|
278
|
+
# Avoid silently accepting spelling errors to field names that are not set via __init__. We need to be able to
|
|
279
|
+
# set values for predefined and registered fields, whatever non-field attributes this class defines, and
|
|
280
|
+
# property setters.
|
|
281
|
+
if key in self.FIELDS:
|
|
282
|
+
return super().__setattr__(key, value)
|
|
283
|
+
if key in self._slots_keys:
|
|
284
|
+
return super().__setattr__(key, value)
|
|
285
|
+
if hasattr(self, key):
|
|
286
|
+
# Property setters
|
|
287
|
+
return super().__setattr__(key, value)
|
|
288
|
+
raise AttributeError(
|
|
289
|
+
f"{key!r} is not a valid attribute. See {self.__class__.__name__}.FIELDS for valid field names"
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
def clean(self, version=None):
|
|
293
|
+
# Validate attribute values using the field validator
|
|
294
|
+
for f in self.FIELDS:
|
|
295
|
+
if version and not f.supports_version(version):
|
|
296
|
+
continue
|
|
297
|
+
if isinstance(f, ExtendedPropertyField) and not hasattr(self, f.name):
|
|
298
|
+
# The extended field may have been registered after this item was created. Set default values.
|
|
299
|
+
setattr(self, f.name, f.clean(None, version=version))
|
|
300
|
+
continue
|
|
301
|
+
val = getattr(self, f.name)
|
|
302
|
+
setattr(self, f.name, f.clean(val, version=version))
|
|
303
|
+
|
|
304
|
+
@staticmethod
|
|
305
|
+
def _clear(elem):
|
|
306
|
+
# Clears an XML element to reduce memory consumption
|
|
307
|
+
elem.clear()
|
|
308
|
+
# Don't attempt to clean up previous siblings. We may not have parsed them yet.
|
|
309
|
+
parent = elem.getparent()
|
|
310
|
+
if parent is None:
|
|
311
|
+
return
|
|
312
|
+
parent.remove(elem)
|
|
313
|
+
|
|
314
|
+
@classmethod
|
|
315
|
+
def from_xml(cls, elem, account):
|
|
316
|
+
kwargs = {f.name: f.from_xml(elem=elem, account=account) for f in cls.FIELDS}
|
|
317
|
+
cls._clear(elem)
|
|
318
|
+
return cls(**kwargs)
|
|
319
|
+
|
|
320
|
+
def to_xml(self, version):
|
|
321
|
+
self.clean(version=version)
|
|
322
|
+
# WARNING: The order of addition of XML elements is VERY important. Exchange expects XML elements in a
|
|
323
|
+
# specific, non-documented order and will fail with meaningless errors if the order is wrong.
|
|
324
|
+
|
|
325
|
+
# Collect attributes
|
|
326
|
+
attrs = {}
|
|
327
|
+
for f in self.attribute_fields():
|
|
328
|
+
if f.is_read_only:
|
|
329
|
+
continue
|
|
330
|
+
value = getattr(self, f.name)
|
|
331
|
+
if value is None or (f.is_list and not value):
|
|
332
|
+
continue
|
|
333
|
+
attrs[f.field_uri] = value_to_xml_text(getattr(self, f.name))
|
|
334
|
+
|
|
335
|
+
# Create element with attributes
|
|
336
|
+
elem = create_element(self.request_tag(), attrs=attrs)
|
|
337
|
+
|
|
338
|
+
# Add elements and values
|
|
339
|
+
for f in self.supported_fields(version=version):
|
|
340
|
+
if f.is_read_only:
|
|
341
|
+
continue
|
|
342
|
+
value = getattr(self, f.name)
|
|
343
|
+
if value is None or (f.is_list and not value):
|
|
344
|
+
continue
|
|
345
|
+
set_xml_value(elem, f.to_xml(value, version=version))
|
|
346
|
+
return elem
|
|
347
|
+
|
|
348
|
+
@classmethod
|
|
349
|
+
def request_tag(cls):
|
|
350
|
+
if not cls.ELEMENT_NAME:
|
|
351
|
+
raise ValueError(f"Class {cls} is missing the ELEMENT_NAME attribute")
|
|
352
|
+
return {
|
|
353
|
+
TNS: f"t:{cls.ELEMENT_NAME}",
|
|
354
|
+
MNS: f"m:{cls.ELEMENT_NAME}",
|
|
355
|
+
}[cls.NAMESPACE]
|
|
356
|
+
|
|
357
|
+
@classmethod
|
|
358
|
+
def response_tag(cls):
|
|
359
|
+
if not cls.NAMESPACE:
|
|
360
|
+
raise ValueError(f"Class {cls} is missing the NAMESPACE attribute")
|
|
361
|
+
if not cls.ELEMENT_NAME:
|
|
362
|
+
raise ValueError(f"Class {cls} is missing the ELEMENT_NAME attribute")
|
|
363
|
+
return f"{{{cls.NAMESPACE}}}{cls.ELEMENT_NAME}"
|
|
364
|
+
|
|
365
|
+
@classmethod
|
|
366
|
+
def attribute_fields(cls):
|
|
367
|
+
return tuple(f for f in cls.FIELDS if f.is_attribute)
|
|
368
|
+
|
|
369
|
+
@classmethod
|
|
370
|
+
def supported_fields(cls, version):
|
|
371
|
+
"""Return the fields supported by the given server version."""
|
|
372
|
+
|
|
373
|
+
return tuple(f for f in cls.FIELDS if not f.is_attribute and f.supports_version(version))
|
|
374
|
+
|
|
375
|
+
@classmethod
|
|
376
|
+
def get_field_by_fieldname(cls, fieldname):
|
|
377
|
+
try:
|
|
378
|
+
return cls.FIELDS[fieldname]
|
|
379
|
+
except KeyError:
|
|
380
|
+
raise InvalidField(f"{fieldname!r} is not a valid field name on {cls.__name__}")
|
|
381
|
+
|
|
382
|
+
@classmethod
|
|
383
|
+
def validate_field(cls, field, version):
|
|
384
|
+
"""Take a list of fieldnames, Field or FieldPath objects pointing to item fields, and check that they are
|
|
385
|
+
valid for the given version.
|
|
386
|
+
|
|
387
|
+
:param field:
|
|
388
|
+
:param version:
|
|
389
|
+
"""
|
|
390
|
+
# Allow both Field and FieldPath instances and string field paths as input
|
|
391
|
+
if isinstance(field, str):
|
|
392
|
+
field = cls.get_field_by_fieldname(fieldname=field)
|
|
393
|
+
elif isinstance(field, FieldPath):
|
|
394
|
+
field = field.field
|
|
395
|
+
cls.get_field_by_fieldname(fieldname=field.name) # Will raise if field name is invalid
|
|
396
|
+
if not field.supports_version(version):
|
|
397
|
+
# The field exists but is not valid for this version
|
|
398
|
+
raise InvalidFieldForVersion(
|
|
399
|
+
f"Field {field.name!r} only supports server versions from {field.supported_from or '*'} to "
|
|
400
|
+
f"{field.deprecated_from or '*'} (server has {version})"
|
|
401
|
+
)
|
|
402
|
+
|
|
403
|
+
@classmethod
|
|
404
|
+
def add_field(cls, field, insert_after):
|
|
405
|
+
"""Insert a new field at the preferred place in the tuple and update the slots cache.
|
|
406
|
+
|
|
407
|
+
:param field:
|
|
408
|
+
:param insert_after:
|
|
409
|
+
"""
|
|
410
|
+
with cls._fields_lock:
|
|
411
|
+
idx = cls.FIELDS.index_by_name(insert_after) + 1
|
|
412
|
+
# This class may not have its own FIELDS attribute. Make sure not to edit an attribute belonging to a parent
|
|
413
|
+
# class.
|
|
414
|
+
cls.FIELDS.insert(idx, field)
|
|
415
|
+
setattr(cls, _mangle(field.name), field)
|
|
416
|
+
|
|
417
|
+
@classmethod
|
|
418
|
+
def remove_field(cls, field):
|
|
419
|
+
"""Remove the given field and update the slots cache.
|
|
420
|
+
|
|
421
|
+
:param field:
|
|
422
|
+
"""
|
|
423
|
+
with cls._fields_lock:
|
|
424
|
+
# This class may not have its own FIELDS attribute. Make sure not to edit an attribute belonging to a parent
|
|
425
|
+
# class.
|
|
426
|
+
cls.FIELDS.remove(field)
|
|
427
|
+
delattr(cls, _mangle(field.name))
|
|
428
|
+
|
|
429
|
+
def __eq__(self, other):
|
|
430
|
+
return hash(self) == hash(other)
|
|
431
|
+
|
|
432
|
+
def __hash__(self):
|
|
433
|
+
return hash(
|
|
434
|
+
tuple(tuple(getattr(self, f.name) or ()) if f.is_list else getattr(self, f.name) for f in self.FIELDS)
|
|
435
|
+
)
|
|
436
|
+
|
|
437
|
+
def _field_vals(self):
|
|
438
|
+
field_vals = [] # Keep sorting
|
|
439
|
+
for f in self.FIELDS:
|
|
440
|
+
val = getattr(self, f.name)
|
|
441
|
+
if isinstance(f, EnumField) and isinstance(val, int):
|
|
442
|
+
val = f.as_string(val)
|
|
443
|
+
field_vals.append((f.name, val))
|
|
444
|
+
return field_vals
|
|
445
|
+
|
|
446
|
+
def __str__(self):
|
|
447
|
+
args_str = ", ".join(f"{name}={val!r}" for name, val in self._field_vals() if val is not None)
|
|
448
|
+
return f"{self.__class__.__name__}({args_str})"
|
|
449
|
+
|
|
450
|
+
def __repr__(self):
|
|
451
|
+
args_str = ", ".join(f"{name}={val!r}" for name, val in self._field_vals())
|
|
452
|
+
return f"{self.__class__.__name__}({args_str})"
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
class MessageHeader(EWSElement):
|
|
456
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/internetmessageheader"""
|
|
457
|
+
|
|
458
|
+
ELEMENT_NAME = "InternetMessageHeader"
|
|
459
|
+
|
|
460
|
+
name = TextField(field_uri="HeaderName", is_attribute=True)
|
|
461
|
+
value = SubField()
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
class BaseItemId(EWSElement, metaclass=EWSMeta):
|
|
465
|
+
"""Base class for ItemId elements."""
|
|
466
|
+
|
|
467
|
+
ID_ATTR = None
|
|
468
|
+
CHANGEKEY_ATTR = None
|
|
469
|
+
|
|
470
|
+
def __init__(self, *args, **kwargs):
|
|
471
|
+
if not kwargs:
|
|
472
|
+
# Allow to set attributes without keyword
|
|
473
|
+
kwargs = dict(zip(self._slots_keys, args))
|
|
474
|
+
super().__init__(**kwargs)
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
class ItemId(BaseItemId):
|
|
478
|
+
"""'id' and 'changekey' are UUIDs generated by Exchange.
|
|
479
|
+
|
|
480
|
+
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/itemid
|
|
481
|
+
"""
|
|
482
|
+
|
|
483
|
+
ELEMENT_NAME = "ItemId"
|
|
484
|
+
ID_ATTR = "Id"
|
|
485
|
+
CHANGEKEY_ATTR = "ChangeKey"
|
|
486
|
+
|
|
487
|
+
id = IdField(field_uri=ID_ATTR, is_required=True)
|
|
488
|
+
changekey = IdField(field_uri=CHANGEKEY_ATTR, is_required=False)
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
class ParentItemId(ItemId):
|
|
492
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/parentitemid"""
|
|
493
|
+
|
|
494
|
+
ELEMENT_NAME = "ParentItemId"
|
|
495
|
+
NAMESPACE = MNS
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
class RootItemId(BaseItemId):
|
|
499
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/rootitemid"""
|
|
500
|
+
|
|
501
|
+
ELEMENT_NAME = "RootItemId"
|
|
502
|
+
NAMESPACE = MNS
|
|
503
|
+
ID_ATTR = "RootItemId"
|
|
504
|
+
CHANGEKEY_ATTR = "RootItemChangeKey"
|
|
505
|
+
|
|
506
|
+
id = IdField(field_uri=ID_ATTR, is_required=True)
|
|
507
|
+
changekey = IdField(field_uri=CHANGEKEY_ATTR, is_required=True)
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
class AssociatedCalendarItemId(ItemId):
|
|
511
|
+
"""MSDN:
|
|
512
|
+
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/associatedcalendaritemid
|
|
513
|
+
"""
|
|
514
|
+
|
|
515
|
+
ELEMENT_NAME = "AssociatedCalendarItemId"
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
class ConversationId(ItemId):
|
|
519
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/conversationid"""
|
|
520
|
+
|
|
521
|
+
ELEMENT_NAME = "ConversationId"
|
|
522
|
+
|
|
523
|
+
# ChangeKey attribute is sometimes required, see MSDN link
|
|
524
|
+
|
|
525
|
+
|
|
526
|
+
class ParentFolderId(ItemId):
|
|
527
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/parentfolderid"""
|
|
528
|
+
|
|
529
|
+
ELEMENT_NAME = "ParentFolderId"
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
class ReferenceItemId(ItemId):
|
|
533
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/referenceitemid"""
|
|
534
|
+
|
|
535
|
+
ELEMENT_NAME = "ReferenceItemId"
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
class PersonaId(ItemId):
|
|
539
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/personaid"""
|
|
540
|
+
|
|
541
|
+
ELEMENT_NAME = "PersonaId"
|
|
542
|
+
NAMESPACE = MNS
|
|
543
|
+
|
|
544
|
+
@classmethod
|
|
545
|
+
def response_tag(cls):
|
|
546
|
+
# This element is in MNS in the request and TNS in the response...
|
|
547
|
+
return f"{{{TNS}}}{cls.ELEMENT_NAME}"
|
|
548
|
+
|
|
549
|
+
|
|
550
|
+
class SourceId(ItemId):
|
|
551
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/sourceid"""
|
|
552
|
+
|
|
553
|
+
ELEMENT_NAME = "SourceId"
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
class FolderId(ItemId):
|
|
557
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/folderid"""
|
|
558
|
+
|
|
559
|
+
ELEMENT_NAME = "FolderId"
|
|
560
|
+
|
|
561
|
+
|
|
562
|
+
class RecurringMasterItemId(BaseItemId):
|
|
563
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/recurringmasteritemid"""
|
|
564
|
+
|
|
565
|
+
ELEMENT_NAME = "RecurringMasterItemId"
|
|
566
|
+
ID_ATTR = "OccurrenceId"
|
|
567
|
+
CHANGEKEY_ATTR = "ChangeKey"
|
|
568
|
+
|
|
569
|
+
id = IdField(field_uri=ID_ATTR, is_required=True)
|
|
570
|
+
changekey = IdField(field_uri=CHANGEKEY_ATTR, is_required=False)
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
class OccurrenceItemId(BaseItemId):
|
|
574
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/occurrenceitemid"""
|
|
575
|
+
|
|
576
|
+
ELEMENT_NAME = "OccurrenceItemId"
|
|
577
|
+
ID_ATTR = "RecurringMasterId"
|
|
578
|
+
CHANGEKEY_ATTR = "ChangeKey"
|
|
579
|
+
|
|
580
|
+
id = IdField(field_uri=ID_ATTR, is_required=True)
|
|
581
|
+
changekey = IdField(field_uri=CHANGEKEY_ATTR, is_required=False)
|
|
582
|
+
instance_index = IntegerField(field_uri="InstanceIndex", is_attribute=True, is_required=True, min=1)
|
|
583
|
+
|
|
584
|
+
|
|
585
|
+
class MovedItemId(ItemId):
|
|
586
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/moveditemid"""
|
|
587
|
+
|
|
588
|
+
ELEMENT_NAME = "MovedItemId"
|
|
589
|
+
NAMESPACE = MNS
|
|
590
|
+
|
|
591
|
+
@classmethod
|
|
592
|
+
def id_from_xml(cls, elem):
|
|
593
|
+
item = cls.from_xml(elem=elem, account=None)
|
|
594
|
+
return item.id, item.changekey
|
|
595
|
+
|
|
596
|
+
|
|
597
|
+
class OldItemId(ItemId):
|
|
598
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/oldfolderid"""
|
|
599
|
+
|
|
600
|
+
ELEMENT_NAME = "OldItemId"
|
|
601
|
+
|
|
602
|
+
|
|
603
|
+
class OldFolderId(FolderId):
|
|
604
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/olditemid"""
|
|
605
|
+
|
|
606
|
+
ELEMENT_NAME = "OldFolderId"
|
|
607
|
+
|
|
608
|
+
|
|
609
|
+
class OldParentFolderId(ParentFolderId):
|
|
610
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/oldparentfolderid"""
|
|
611
|
+
|
|
612
|
+
ELEMENT_NAME = "OldParentFolderId"
|
|
613
|
+
|
|
614
|
+
|
|
615
|
+
class Mailbox(EWSElement):
|
|
616
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/mailbox"""
|
|
617
|
+
|
|
618
|
+
ELEMENT_NAME = "Mailbox"
|
|
619
|
+
MAILBOX = "Mailbox"
|
|
620
|
+
ONE_OFF = "OneOff"
|
|
621
|
+
MAILBOX_TYPE_CHOICES = {
|
|
622
|
+
Choice(MAILBOX),
|
|
623
|
+
Choice("PublicDL"),
|
|
624
|
+
Choice("PrivateDL"),
|
|
625
|
+
Choice("Contact"),
|
|
626
|
+
Choice("PublicFolder"),
|
|
627
|
+
Choice("Unknown"),
|
|
628
|
+
Choice(ONE_OFF),
|
|
629
|
+
Choice("GroupMailbox", supported_from=EXCHANGE_2013),
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
name = TextField(field_uri="Name")
|
|
633
|
+
email_address = EmailAddressField(field_uri="EmailAddress")
|
|
634
|
+
# RoutingType values are not restricted:
|
|
635
|
+
# https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/routingtype-emailaddresstype
|
|
636
|
+
routing_type = TextField(field_uri="RoutingType", default="SMTP")
|
|
637
|
+
mailbox_type = ChoiceField(field_uri="MailboxType", choices=MAILBOX_TYPE_CHOICES, default=MAILBOX)
|
|
638
|
+
item_id = EWSElementField(value_cls=ItemId)
|
|
639
|
+
|
|
640
|
+
def clean(self, version=None):
|
|
641
|
+
super().clean(version=version)
|
|
642
|
+
|
|
643
|
+
if self.mailbox_type != self.ONE_OFF and not self.email_address and not self.item_id:
|
|
644
|
+
# A OneOff Mailbox (a one-off member of a personal distribution list) may lack these fields, but other
|
|
645
|
+
# Mailboxes require at least one. See also "Remarks" section of
|
|
646
|
+
# https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/mailbox
|
|
647
|
+
raise ValueError(f"Mailbox type {self.mailbox_type!r} must have either 'email_address' or 'item_id' set")
|
|
648
|
+
|
|
649
|
+
def __hash__(self):
|
|
650
|
+
# Exchange may add 'mailbox_type' and 'name' on insert. We're satisfied if the item_id or email address matches.
|
|
651
|
+
if self.item_id:
|
|
652
|
+
return hash(self.item_id)
|
|
653
|
+
if self.email_address:
|
|
654
|
+
return hash(self.email_address.lower())
|
|
655
|
+
return super().__hash__()
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
class DLMailbox(Mailbox):
|
|
659
|
+
"""Like Mailbox, but creates elements in the 'messages' namespace when sending requests."""
|
|
660
|
+
|
|
661
|
+
NAMESPACE = MNS
|
|
662
|
+
|
|
663
|
+
|
|
664
|
+
class SendingAs(Mailbox):
|
|
665
|
+
"""Like Mailbox, but creates elements in the 'messages' namespace when sending requests.
|
|
666
|
+
|
|
667
|
+
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/sendingas
|
|
668
|
+
"""
|
|
669
|
+
|
|
670
|
+
ELEMENT_NAME = "SendingAs"
|
|
671
|
+
NAMESPACE = MNS
|
|
672
|
+
|
|
673
|
+
|
|
674
|
+
class RecipientAddress(Mailbox):
|
|
675
|
+
"""Like Mailbox, but with a different tag name.
|
|
676
|
+
|
|
677
|
+
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/recipientaddress
|
|
678
|
+
"""
|
|
679
|
+
|
|
680
|
+
ELEMENT_NAME = "RecipientAddress"
|
|
681
|
+
|
|
682
|
+
|
|
683
|
+
class EmailAddress(Mailbox):
|
|
684
|
+
"""Like Mailbox, but with a different tag name.
|
|
685
|
+
|
|
686
|
+
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/emailaddress-emailaddresstype
|
|
687
|
+
"""
|
|
688
|
+
|
|
689
|
+
ELEMENT_NAME = "EmailAddress"
|
|
690
|
+
|
|
691
|
+
|
|
692
|
+
class Address(Mailbox):
|
|
693
|
+
"""Like Mailbox, but with a different tag name.
|
|
694
|
+
|
|
695
|
+
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/address-emailaddresstype
|
|
696
|
+
"""
|
|
697
|
+
|
|
698
|
+
ELEMENT_NAME = "Address"
|
|
699
|
+
|
|
700
|
+
|
|
701
|
+
class AvailabilityMailbox(EWSElement):
|
|
702
|
+
"""Like Mailbox, but with slightly different attributes.
|
|
703
|
+
|
|
704
|
+
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/mailbox-availability
|
|
705
|
+
"""
|
|
706
|
+
|
|
707
|
+
ELEMENT_NAME = "Mailbox"
|
|
708
|
+
|
|
709
|
+
name = TextField(field_uri="Name")
|
|
710
|
+
email_address = EmailAddressField(field_uri="Address", is_required=True)
|
|
711
|
+
# RoutingType values restricted to EX and SMTP:
|
|
712
|
+
# https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/routingtype-emailaddress
|
|
713
|
+
routing_type = RoutingTypeField(field_uri="RoutingType")
|
|
714
|
+
|
|
715
|
+
def __hash__(self):
|
|
716
|
+
# Exchange may add 'name' on insert. We're satisfied if the email address matches.
|
|
717
|
+
if self.email_address:
|
|
718
|
+
return hash(self.email_address.lower())
|
|
719
|
+
return super().__hash__()
|
|
720
|
+
|
|
721
|
+
@classmethod
|
|
722
|
+
def from_mailbox(cls, mailbox):
|
|
723
|
+
if not isinstance(mailbox, Mailbox):
|
|
724
|
+
raise InvalidTypeError("mailbox", mailbox, Mailbox)
|
|
725
|
+
return cls(name=mailbox.name, email_address=mailbox.email_address, routing_type=mailbox.routing_type)
|
|
726
|
+
|
|
727
|
+
|
|
728
|
+
class Email(AvailabilityMailbox):
|
|
729
|
+
"""Like AvailabilityMailbox, but with a different tag name.
|
|
730
|
+
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/email-emailaddresstype
|
|
731
|
+
"""
|
|
732
|
+
|
|
733
|
+
ELEMENT_NAME = "Email"
|
|
734
|
+
|
|
735
|
+
|
|
736
|
+
class MailboxData(EWSElement):
|
|
737
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/mailboxdata"""
|
|
738
|
+
|
|
739
|
+
ELEMENT_NAME = "MailboxData"
|
|
740
|
+
ATTENDEE_TYPES = {"Optional", "Organizer", "Required", "Resource", "Room"}
|
|
741
|
+
|
|
742
|
+
email = EmailField()
|
|
743
|
+
attendee_type = ChoiceField(field_uri="AttendeeType", choices={Choice(c) for c in ATTENDEE_TYPES})
|
|
744
|
+
exclude_conflicts = BooleanField(field_uri="ExcludeConflicts")
|
|
745
|
+
|
|
746
|
+
|
|
747
|
+
class DistinguishedFolderId(FolderId):
|
|
748
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/distinguishedfolderid"""
|
|
749
|
+
|
|
750
|
+
ELEMENT_NAME = "DistinguishedFolderId"
|
|
751
|
+
|
|
752
|
+
mailbox = MailboxField()
|
|
753
|
+
|
|
754
|
+
@classmethod
|
|
755
|
+
def from_xml(cls, elem, account):
|
|
756
|
+
return cls(id=elem.text or None)
|
|
757
|
+
|
|
758
|
+
def clean(self, version=None):
|
|
759
|
+
from .folders import PublicFoldersRoot
|
|
760
|
+
|
|
761
|
+
super().clean(version=version)
|
|
762
|
+
if self.id == PublicFoldersRoot.DISTINGUISHED_FOLDER_ID:
|
|
763
|
+
# Avoid "ErrorInvalidOperation: It is not valid to specify a mailbox with the public folder root" from EWS
|
|
764
|
+
self.mailbox = None
|
|
765
|
+
elif not self.mailbox:
|
|
766
|
+
raise ValueError(f"DistinguishedFolderId {self.id} must have a mailbox")
|
|
767
|
+
|
|
768
|
+
|
|
769
|
+
class TimeWindow(EWSElement):
|
|
770
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/timewindow"""
|
|
771
|
+
|
|
772
|
+
ELEMENT_NAME = "TimeWindow"
|
|
773
|
+
|
|
774
|
+
start = DateTimeField(field_uri="StartTime", is_required=True)
|
|
775
|
+
end = DateTimeField(field_uri="EndTime", is_required=True)
|
|
776
|
+
|
|
777
|
+
def clean(self, version=None):
|
|
778
|
+
if self.start >= self.end:
|
|
779
|
+
raise ValueError(f"'start' must be less than 'end' ({self.start} -> {self.end})")
|
|
780
|
+
super().clean(version=version)
|
|
781
|
+
|
|
782
|
+
|
|
783
|
+
class FreeBusyViewOptions(EWSElement):
|
|
784
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/freebusyviewoptions"""
|
|
785
|
+
|
|
786
|
+
ELEMENT_NAME = "FreeBusyViewOptions"
|
|
787
|
+
REQUESTED_VIEWS = {"MergedOnly", "FreeBusy", "FreeBusyMerged", "Detailed", "DetailedMerged"}
|
|
788
|
+
|
|
789
|
+
time_window = EWSElementField(value_cls=TimeWindow, is_required=True)
|
|
790
|
+
# Interval value is in minutes
|
|
791
|
+
merged_free_busy_interval = IntegerField(
|
|
792
|
+
field_uri="MergedFreeBusyIntervalInMinutes", min=5, max=1440, default=30, is_required=True
|
|
793
|
+
)
|
|
794
|
+
requested_view = ChoiceField(
|
|
795
|
+
field_uri="RequestedView", choices={Choice(c) for c in REQUESTED_VIEWS}, is_required=True
|
|
796
|
+
) # Choice('None') is also valid, but only for responses
|
|
797
|
+
|
|
798
|
+
|
|
799
|
+
class Attendee(EWSElement):
|
|
800
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/attendee"""
|
|
801
|
+
|
|
802
|
+
ELEMENT_NAME = "Attendee"
|
|
803
|
+
RESPONSE_TYPES = {"Unknown", "Organizer", "Tentative", "Accept", "Decline", "NoResponseReceived"}
|
|
804
|
+
|
|
805
|
+
mailbox = MailboxField(is_required=True)
|
|
806
|
+
response_type = ChoiceField(
|
|
807
|
+
field_uri="ResponseType", choices={Choice(c) for c in RESPONSE_TYPES}, default="Unknown"
|
|
808
|
+
)
|
|
809
|
+
last_response_time = DateTimeField(field_uri="LastResponseTime")
|
|
810
|
+
proposed_start = DateTimeField(field_uri="ProposedStart")
|
|
811
|
+
proposed_end = DateTimeField(field_uri="ProposedEnd")
|
|
812
|
+
|
|
813
|
+
def __hash__(self):
|
|
814
|
+
return hash(self.mailbox)
|
|
815
|
+
|
|
816
|
+
|
|
817
|
+
class TimeZoneTransition(EWSElement, metaclass=EWSMeta):
|
|
818
|
+
"""Base class for StandardTime and DaylightTime classes."""
|
|
819
|
+
|
|
820
|
+
bias = IntegerField(field_uri="Bias", is_required=True) # Offset from the default bias, in minutes
|
|
821
|
+
time = TimeField(field_uri="Time", is_required=True)
|
|
822
|
+
occurrence = IntegerField(field_uri="DayOrder", is_required=True) # n'th occurrence of weekday in iso_month
|
|
823
|
+
iso_month = IntegerField(field_uri="Month", is_required=True)
|
|
824
|
+
weekday = EnumField(field_uri="DayOfWeek", enum=WEEKDAY_NAMES, is_required=True)
|
|
825
|
+
# 'Year' is not implemented yet
|
|
826
|
+
|
|
827
|
+
@classmethod
|
|
828
|
+
def from_xml(cls, elem, account):
|
|
829
|
+
res = super().from_xml(elem=elem, account=account)
|
|
830
|
+
# Some parts of EWS use '5' to mean 'last occurrence in month', others use '-1'. Let's settle on '5' because
|
|
831
|
+
# only '5' is accepted in requests.
|
|
832
|
+
if res.occurrence == -1:
|
|
833
|
+
res.occurrence = 5
|
|
834
|
+
return res
|
|
835
|
+
|
|
836
|
+
def clean(self, version=None):
|
|
837
|
+
super().clean(version=version)
|
|
838
|
+
if self.occurrence == -1:
|
|
839
|
+
# See from_xml()
|
|
840
|
+
self.occurrence = 5
|
|
841
|
+
|
|
842
|
+
|
|
843
|
+
class StandardTime(TimeZoneTransition):
|
|
844
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/standardtime"""
|
|
845
|
+
|
|
846
|
+
ELEMENT_NAME = "StandardTime"
|
|
847
|
+
|
|
848
|
+
|
|
849
|
+
class DaylightTime(TimeZoneTransition):
|
|
850
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/daylighttime"""
|
|
851
|
+
|
|
852
|
+
ELEMENT_NAME = "DaylightTime"
|
|
853
|
+
|
|
854
|
+
|
|
855
|
+
class TimeZone(EWSElement):
|
|
856
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/timezone-availability"""
|
|
857
|
+
|
|
858
|
+
ELEMENT_NAME = "TimeZone"
|
|
859
|
+
|
|
860
|
+
bias = IntegerField(field_uri="Bias", is_required=True) # Standard (non-DST) offset from UTC, in minutes
|
|
861
|
+
standard_time = EWSElementField(value_cls=StandardTime)
|
|
862
|
+
daylight_time = EWSElementField(value_cls=DaylightTime)
|
|
863
|
+
|
|
864
|
+
def to_server_timezone(self, timezones, for_year):
|
|
865
|
+
"""Return the Microsoft timezone ID corresponding to this timezone. There may not be a match at all, and there
|
|
866
|
+
may be multiple matches. If so, return a random timezone ID.
|
|
867
|
+
|
|
868
|
+
:param timezones: A list of server timezones, as returned by
|
|
869
|
+
Protocol.get_timezones(return_full_timezone_data=True)
|
|
870
|
+
:param for_year: return: A Microsoft timezone ID, as a string
|
|
871
|
+
|
|
872
|
+
:return: A Microsoft timezone ID, as a string
|
|
873
|
+
"""
|
|
874
|
+
candidates = set()
|
|
875
|
+
for tz_definition in timezones:
|
|
876
|
+
candidate = self.from_server_timezone(
|
|
877
|
+
tz_definition=tz_definition,
|
|
878
|
+
for_year=for_year,
|
|
879
|
+
)
|
|
880
|
+
if candidate == self:
|
|
881
|
+
log.debug("Found exact candidate: %s (%s)", tz_definition.id, tz_definition.name)
|
|
882
|
+
# We prefer this timezone over anything else. Return immediately.
|
|
883
|
+
return tz_definition.id
|
|
884
|
+
# Reduce list based on base bias and standard / daylight bias values
|
|
885
|
+
if candidate.bias != self.bias:
|
|
886
|
+
continue
|
|
887
|
+
if candidate.standard_time is None:
|
|
888
|
+
if self.standard_time is not None:
|
|
889
|
+
continue
|
|
890
|
+
else:
|
|
891
|
+
if self.standard_time is None:
|
|
892
|
+
continue
|
|
893
|
+
if candidate.standard_time.bias != self.standard_time.bias:
|
|
894
|
+
continue
|
|
895
|
+
if candidate.daylight_time is None:
|
|
896
|
+
if self.daylight_time is not None:
|
|
897
|
+
continue
|
|
898
|
+
else:
|
|
899
|
+
if self.daylight_time is None:
|
|
900
|
+
continue
|
|
901
|
+
if candidate.daylight_time.bias != self.daylight_time.bias:
|
|
902
|
+
continue
|
|
903
|
+
log.debug("Found candidate with matching biases: %s (%s)", tz_definition.id, tz_definition.name)
|
|
904
|
+
candidates.add(tz_definition.id)
|
|
905
|
+
if not candidates:
|
|
906
|
+
raise ValueError("No server timezones match this timezone definition")
|
|
907
|
+
if len(candidates) == 1:
|
|
908
|
+
log.info("Could not find an exact timezone match for %s. Selecting the best candidate", self)
|
|
909
|
+
else:
|
|
910
|
+
log.warning("Could not find an exact timezone match for %s. Selecting a random candidate", self)
|
|
911
|
+
return candidates.pop()
|
|
912
|
+
|
|
913
|
+
@classmethod
|
|
914
|
+
def from_server_timezone(cls, tz_definition, for_year):
|
|
915
|
+
# Creates a TimeZone object from the result of a GetServerTimeZones call with full timezone data
|
|
916
|
+
std_time, daylight_time, period = tz_definition.get_std_and_dst(for_year=for_year)
|
|
917
|
+
return cls(bias=period.bias_in_minutes, standard_time=std_time, daylight_time=daylight_time)
|
|
918
|
+
|
|
919
|
+
|
|
920
|
+
class CalendarView(EWSElement):
|
|
921
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/calendarview"""
|
|
922
|
+
|
|
923
|
+
ELEMENT_NAME = "CalendarView"
|
|
924
|
+
NAMESPACE = MNS
|
|
925
|
+
|
|
926
|
+
start = DateTimeField(field_uri="StartDate", is_required=True, is_attribute=True)
|
|
927
|
+
end = DateTimeField(field_uri="EndDate", is_required=True, is_attribute=True)
|
|
928
|
+
max_items = IntegerField(field_uri="MaxEntriesReturned", min=1, is_attribute=True)
|
|
929
|
+
|
|
930
|
+
def clean(self, version=None):
|
|
931
|
+
super().clean(version=version)
|
|
932
|
+
if self.end < self.start:
|
|
933
|
+
raise ValueError("'start' must be before 'end'")
|
|
934
|
+
|
|
935
|
+
|
|
936
|
+
class CalendarEventDetails(EWSElement):
|
|
937
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/calendareventdetails"""
|
|
938
|
+
|
|
939
|
+
ELEMENT_NAME = "CalendarEventDetails"
|
|
940
|
+
|
|
941
|
+
id = CharField(field_uri="ID")
|
|
942
|
+
subject = CharField(field_uri="Subject")
|
|
943
|
+
location = CharField(field_uri="Location")
|
|
944
|
+
is_meeting = BooleanField(field_uri="IsMeeting")
|
|
945
|
+
is_recurring = BooleanField(field_uri="IsRecurring")
|
|
946
|
+
is_exception = BooleanField(field_uri="IsException")
|
|
947
|
+
is_reminder_set = BooleanField(field_uri="IsReminderSet")
|
|
948
|
+
is_private = BooleanField(field_uri="IsPrivate")
|
|
949
|
+
|
|
950
|
+
|
|
951
|
+
class CalendarEvent(EWSElement):
|
|
952
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/calendarevent"""
|
|
953
|
+
|
|
954
|
+
ELEMENT_NAME = "CalendarEvent"
|
|
955
|
+
|
|
956
|
+
start = DateTimeField(field_uri="StartTime")
|
|
957
|
+
end = DateTimeField(field_uri="EndTime")
|
|
958
|
+
busy_type = FreeBusyStatusField(field_uri="BusyType", is_required=True, default="Busy")
|
|
959
|
+
details = EWSElementField(value_cls=CalendarEventDetails)
|
|
960
|
+
|
|
961
|
+
|
|
962
|
+
class WorkingPeriod(EWSElement):
|
|
963
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/workingperiod"""
|
|
964
|
+
|
|
965
|
+
ELEMENT_NAME = "WorkingPeriod"
|
|
966
|
+
|
|
967
|
+
weekdays = EnumListField(field_uri="DayOfWeek", enum=WEEKDAY_NAMES, is_required=True)
|
|
968
|
+
start = TimeField(field_uri="StartTimeInMinutes", is_required=True)
|
|
969
|
+
end = TimeField(field_uri="EndTimeInMinutes", is_required=True)
|
|
970
|
+
|
|
971
|
+
|
|
972
|
+
class FreeBusyView(EWSElement):
|
|
973
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/freebusyview"""
|
|
974
|
+
|
|
975
|
+
ELEMENT_NAME = "FreeBusyView"
|
|
976
|
+
NAMESPACE = MNS
|
|
977
|
+
view_type = ChoiceField(
|
|
978
|
+
field_uri="FreeBusyViewType",
|
|
979
|
+
choices={
|
|
980
|
+
Choice("None"),
|
|
981
|
+
Choice("MergedOnly"),
|
|
982
|
+
Choice("FreeBusy"),
|
|
983
|
+
Choice("FreeBusyMerged"),
|
|
984
|
+
Choice("Detailed"),
|
|
985
|
+
Choice("DetailedMerged"),
|
|
986
|
+
},
|
|
987
|
+
is_required=True,
|
|
988
|
+
)
|
|
989
|
+
# A string of digits. Each digit points to a position in .fields.FREE_BUSY_CHOICES
|
|
990
|
+
merged = CharField(field_uri="MergedFreeBusy")
|
|
991
|
+
calendar_events = EWSElementListField(field_uri="CalendarEventArray", value_cls=CalendarEvent)
|
|
992
|
+
# WorkingPeriod is located inside the WorkingPeriodArray element which is inside the WorkingHours element
|
|
993
|
+
working_hours = EWSElementListField(field_uri="WorkingPeriodArray", value_cls=WorkingPeriod)
|
|
994
|
+
# TimeZone is also inside the WorkingHours element. It contains information about the timezone which the
|
|
995
|
+
# account is located in.
|
|
996
|
+
working_hours_timezone = EWSElementField(value_cls=TimeZone)
|
|
997
|
+
|
|
998
|
+
@classmethod
|
|
999
|
+
def from_xml(cls, elem, account):
|
|
1000
|
+
kwargs = {}
|
|
1001
|
+
working_hours_elem = elem.find(f"{{{TNS}}}WorkingHours")
|
|
1002
|
+
for f in cls.FIELDS:
|
|
1003
|
+
if f.name in ("working_hours", "working_hours_timezone"):
|
|
1004
|
+
if working_hours_elem is None:
|
|
1005
|
+
continue
|
|
1006
|
+
kwargs[f.name] = f.from_xml(elem=working_hours_elem, account=account)
|
|
1007
|
+
continue
|
|
1008
|
+
kwargs[f.name] = f.from_xml(elem=elem, account=account)
|
|
1009
|
+
cls._clear(elem)
|
|
1010
|
+
return cls(**kwargs)
|
|
1011
|
+
|
|
1012
|
+
|
|
1013
|
+
class RoomList(Mailbox):
|
|
1014
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/roomlist"""
|
|
1015
|
+
|
|
1016
|
+
ELEMENT_NAME = "RoomList"
|
|
1017
|
+
NAMESPACE = MNS
|
|
1018
|
+
|
|
1019
|
+
@classmethod
|
|
1020
|
+
def response_tag(cls):
|
|
1021
|
+
# In a GetRoomLists response, room lists are delivered as Address elements. See
|
|
1022
|
+
# https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/address-emailaddresstype
|
|
1023
|
+
return f"{{{TNS}}}Address"
|
|
1024
|
+
|
|
1025
|
+
|
|
1026
|
+
class Room(Mailbox):
|
|
1027
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/room"""
|
|
1028
|
+
|
|
1029
|
+
ELEMENT_NAME = "Room"
|
|
1030
|
+
|
|
1031
|
+
@classmethod
|
|
1032
|
+
def from_xml(cls, elem, account):
|
|
1033
|
+
id_elem = elem.find(f"{{{TNS}}}Id")
|
|
1034
|
+
item_id_elem = id_elem.find(ItemId.response_tag())
|
|
1035
|
+
kwargs = dict(
|
|
1036
|
+
name=get_xml_attr(id_elem, f"{{{TNS}}}Name"),
|
|
1037
|
+
email_address=get_xml_attr(id_elem, f"{{{TNS}}}EmailAddress"),
|
|
1038
|
+
mailbox_type=get_xml_attr(id_elem, f"{{{TNS}}}MailboxType"),
|
|
1039
|
+
item_id=ItemId.from_xml(elem=item_id_elem, account=account) if item_id_elem else None,
|
|
1040
|
+
)
|
|
1041
|
+
cls._clear(elem)
|
|
1042
|
+
return cls(**kwargs)
|
|
1043
|
+
|
|
1044
|
+
|
|
1045
|
+
class Member(EWSElement):
|
|
1046
|
+
"""MSDN:
|
|
1047
|
+
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/member-ex15websvcsotherref
|
|
1048
|
+
"""
|
|
1049
|
+
|
|
1050
|
+
ELEMENT_NAME = "Member"
|
|
1051
|
+
|
|
1052
|
+
mailbox = MailboxField(is_required=True)
|
|
1053
|
+
status = ChoiceField(
|
|
1054
|
+
field_uri="Status", choices={Choice("Unrecognized"), Choice("Normal"), Choice("Demoted")}, default="Normal"
|
|
1055
|
+
)
|
|
1056
|
+
|
|
1057
|
+
def __hash__(self):
|
|
1058
|
+
return hash(self.mailbox)
|
|
1059
|
+
|
|
1060
|
+
|
|
1061
|
+
class UserId(EWSElement):
|
|
1062
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/userid"""
|
|
1063
|
+
|
|
1064
|
+
ELEMENT_NAME = "UserId"
|
|
1065
|
+
|
|
1066
|
+
sid = CharField(field_uri="SID")
|
|
1067
|
+
primary_smtp_address = EmailAddressField(field_uri="PrimarySmtpAddress")
|
|
1068
|
+
display_name = CharField(field_uri="DisplayName")
|
|
1069
|
+
distinguished_user = ChoiceField(field_uri="DistinguishedUser", choices={Choice("Default"), Choice("Anonymous")})
|
|
1070
|
+
external_user_identity = CharField(field_uri="ExternalUserIdentity")
|
|
1071
|
+
|
|
1072
|
+
|
|
1073
|
+
class BasePermission(EWSElement, metaclass=EWSMeta):
|
|
1074
|
+
"""Base class for the Permission and CalendarPermission classes"""
|
|
1075
|
+
|
|
1076
|
+
PERMISSION_ENUM = {Choice("None"), Choice("Owned"), Choice("All")}
|
|
1077
|
+
|
|
1078
|
+
can_create_items = BooleanField(field_uri="CanCreateItems", default=False)
|
|
1079
|
+
can_create_subfolders = BooleanField(field_uri="CanCreateSubfolders", default=False)
|
|
1080
|
+
is_folder_owner = BooleanField(field_uri="IsFolderOwner", default=False)
|
|
1081
|
+
is_folder_visible = BooleanField(field_uri="IsFolderVisible", default=False)
|
|
1082
|
+
is_folder_contact = BooleanField(field_uri="IsFolderContact", default=False)
|
|
1083
|
+
edit_items = ChoiceField(field_uri="EditItems", choices=PERMISSION_ENUM, default="None")
|
|
1084
|
+
delete_items = ChoiceField(field_uri="DeleteItems", choices=PERMISSION_ENUM, default="None")
|
|
1085
|
+
read_items = ChoiceField(field_uri="ReadItems", choices={Choice("None"), Choice("FullDetails")}, default="None")
|
|
1086
|
+
user_id = EWSElementField(value_cls=UserId, is_required=True)
|
|
1087
|
+
|
|
1088
|
+
|
|
1089
|
+
class Permission(BasePermission):
|
|
1090
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/permission"""
|
|
1091
|
+
|
|
1092
|
+
ELEMENT_NAME = "Permission"
|
|
1093
|
+
LEVEL_CHOICES = (
|
|
1094
|
+
"None",
|
|
1095
|
+
"Owner",
|
|
1096
|
+
"PublishingEditor",
|
|
1097
|
+
"Editor",
|
|
1098
|
+
"PublishingAuthor",
|
|
1099
|
+
"Author",
|
|
1100
|
+
"NoneditingAuthor",
|
|
1101
|
+
"Reviewer",
|
|
1102
|
+
"Contributor",
|
|
1103
|
+
"Custom",
|
|
1104
|
+
)
|
|
1105
|
+
|
|
1106
|
+
permission_level = ChoiceField(
|
|
1107
|
+
field_uri="CalendarPermissionLevel", choices={Choice(c) for c in LEVEL_CHOICES}, default=LEVEL_CHOICES[0]
|
|
1108
|
+
)
|
|
1109
|
+
|
|
1110
|
+
|
|
1111
|
+
class CalendarPermission(BasePermission):
|
|
1112
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/calendarpermission"""
|
|
1113
|
+
|
|
1114
|
+
ELEMENT_NAME = "CalendarPermission"
|
|
1115
|
+
LEVEL_CHOICES = (
|
|
1116
|
+
"None",
|
|
1117
|
+
"Owner",
|
|
1118
|
+
"PublishingEditor",
|
|
1119
|
+
"Editor",
|
|
1120
|
+
"PublishingAuthor",
|
|
1121
|
+
"Author",
|
|
1122
|
+
"NoneditingAuthor",
|
|
1123
|
+
"Reviewer",
|
|
1124
|
+
"Contributor",
|
|
1125
|
+
"FreeBusyTimeOnly",
|
|
1126
|
+
"FreeBusyTimeAndSubjectAndLocation",
|
|
1127
|
+
"Custom",
|
|
1128
|
+
)
|
|
1129
|
+
|
|
1130
|
+
calendar_permission_level = ChoiceField(
|
|
1131
|
+
field_uri="CalendarPermissionLevel", choices={Choice(c) for c in LEVEL_CHOICES}, default=LEVEL_CHOICES[0]
|
|
1132
|
+
)
|
|
1133
|
+
|
|
1134
|
+
|
|
1135
|
+
class PermissionSet(EWSElement):
|
|
1136
|
+
"""MSDN:
|
|
1137
|
+
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/permissionset-permissionsettype
|
|
1138
|
+
and
|
|
1139
|
+
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/permissionset-calendarpermissionsettype
|
|
1140
|
+
"""
|
|
1141
|
+
|
|
1142
|
+
# For simplicity, we implement the two distinct but equally names elements as one class.
|
|
1143
|
+
ELEMENT_NAME = "PermissionSet"
|
|
1144
|
+
|
|
1145
|
+
permissions = EWSElementListField(field_uri="Permissions", value_cls=Permission)
|
|
1146
|
+
calendar_permissions = EWSElementListField(field_uri="CalendarPermissions", value_cls=CalendarPermission)
|
|
1147
|
+
unknown_entries = UnknownEntriesField(field_uri="UnknownEntries")
|
|
1148
|
+
|
|
1149
|
+
|
|
1150
|
+
class EffectiveRights(EWSElement):
|
|
1151
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/effectiverights"""
|
|
1152
|
+
|
|
1153
|
+
ELEMENT_NAME = "EffectiveRights"
|
|
1154
|
+
|
|
1155
|
+
create_associated = BooleanField(field_uri="CreateAssociated", default=False)
|
|
1156
|
+
create_contents = BooleanField(field_uri="CreateContents", default=False)
|
|
1157
|
+
create_hierarchy = BooleanField(field_uri="CreateHierarchy", default=False)
|
|
1158
|
+
delete = BooleanField(field_uri="Delete", default=False)
|
|
1159
|
+
modify = BooleanField(field_uri="Modify", default=False)
|
|
1160
|
+
read = BooleanField(field_uri="Read", default=False)
|
|
1161
|
+
view_private_items = BooleanField(field_uri="ViewPrivateItems", default=False)
|
|
1162
|
+
|
|
1163
|
+
def __contains__(self, item):
|
|
1164
|
+
return getattr(self, item, False)
|
|
1165
|
+
|
|
1166
|
+
|
|
1167
|
+
class DelegatePermissions(EWSElement):
|
|
1168
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/delegatepermissions"""
|
|
1169
|
+
|
|
1170
|
+
ELEMENT_NAME = "DelegatePermissions"
|
|
1171
|
+
PERMISSION_LEVEL_CHOICES = {
|
|
1172
|
+
Choice("None"),
|
|
1173
|
+
Choice("Editor"),
|
|
1174
|
+
Choice("Reviewer"),
|
|
1175
|
+
Choice("Author"),
|
|
1176
|
+
Choice("Custom"),
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
calendar_folder_permission_level = ChoiceField(
|
|
1180
|
+
field_uri="CalendarFolderPermissionLevel", choices=PERMISSION_LEVEL_CHOICES, default="None"
|
|
1181
|
+
)
|
|
1182
|
+
tasks_folder_permission_level = ChoiceField(
|
|
1183
|
+
field_uri="TasksFolderPermissionLevel", choices=PERMISSION_LEVEL_CHOICES, default="None"
|
|
1184
|
+
)
|
|
1185
|
+
inbox_folder_permission_level = ChoiceField(
|
|
1186
|
+
field_uri="InboxFolderPermissionLevel", choices=PERMISSION_LEVEL_CHOICES, default="None"
|
|
1187
|
+
)
|
|
1188
|
+
contacts_folder_permission_level = ChoiceField(
|
|
1189
|
+
field_uri="ContactsFolderPermissionLevel", choices=PERMISSION_LEVEL_CHOICES, default="None"
|
|
1190
|
+
)
|
|
1191
|
+
notes_folder_permission_level = ChoiceField(
|
|
1192
|
+
field_uri="NotesFolderPermissionLevel", choices=PERMISSION_LEVEL_CHOICES, default="None"
|
|
1193
|
+
)
|
|
1194
|
+
journal_folder_permission_level = ChoiceField(
|
|
1195
|
+
field_uri="JournalFolderPermissionLevel", choices=PERMISSION_LEVEL_CHOICES, default="None"
|
|
1196
|
+
)
|
|
1197
|
+
|
|
1198
|
+
|
|
1199
|
+
class DelegateUser(EWSElement):
|
|
1200
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/delegateuser"""
|
|
1201
|
+
|
|
1202
|
+
ELEMENT_NAME = "DelegateUser"
|
|
1203
|
+
NAMESPACE = MNS
|
|
1204
|
+
|
|
1205
|
+
user_id = EWSElementField(value_cls=UserId)
|
|
1206
|
+
delegate_permissions = EWSElementField(value_cls=DelegatePermissions)
|
|
1207
|
+
receive_copies_of_meeting_messages = BooleanField(field_uri="ReceiveCopiesOfMeetingMessages", default=False)
|
|
1208
|
+
view_private_items = BooleanField(field_uri="ViewPrivateItems", default=False)
|
|
1209
|
+
|
|
1210
|
+
|
|
1211
|
+
class SearchableMailbox(EWSElement):
|
|
1212
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/searchablemailbox"""
|
|
1213
|
+
|
|
1214
|
+
ELEMENT_NAME = "SearchableMailbox"
|
|
1215
|
+
|
|
1216
|
+
guid = CharField(field_uri="Guid")
|
|
1217
|
+
primary_smtp_address = EmailAddressField(field_uri="PrimarySmtpAddress")
|
|
1218
|
+
is_external = BooleanField(field_uri="IsExternalMailbox")
|
|
1219
|
+
external_email = EmailAddressField(field_uri="ExternalEmailAddress")
|
|
1220
|
+
display_name = CharField(field_uri="DisplayName")
|
|
1221
|
+
is_membership_group = BooleanField(field_uri="IsMembershipGroup")
|
|
1222
|
+
reference_id = CharField(field_uri="ReferenceId")
|
|
1223
|
+
|
|
1224
|
+
|
|
1225
|
+
class FailedMailbox(EWSElement):
|
|
1226
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/failedmailbox"""
|
|
1227
|
+
|
|
1228
|
+
ELEMENT_NAME = "FailedMailbox"
|
|
1229
|
+
|
|
1230
|
+
mailbox = CharField(field_uri="Mailbox")
|
|
1231
|
+
error_code = IntegerField(field_uri="ErrorCode")
|
|
1232
|
+
error_message = CharField(field_uri="ErrorMessage")
|
|
1233
|
+
is_archive = BooleanField(field_uri="IsArchive")
|
|
1234
|
+
|
|
1235
|
+
|
|
1236
|
+
# MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/mailtipsrequested
|
|
1237
|
+
MAIL_TIPS_TYPES = (
|
|
1238
|
+
"All",
|
|
1239
|
+
"OutOfOfficeMessage",
|
|
1240
|
+
"MailboxFullStatus",
|
|
1241
|
+
"CustomMailTip",
|
|
1242
|
+
"ExternalMemberCount",
|
|
1243
|
+
"TotalMemberCount",
|
|
1244
|
+
"MaxMessageSize",
|
|
1245
|
+
"DeliveryRestriction",
|
|
1246
|
+
"ModerationStatus",
|
|
1247
|
+
"InvalidRecipient",
|
|
1248
|
+
)
|
|
1249
|
+
|
|
1250
|
+
|
|
1251
|
+
class OutOfOffice(EWSElement):
|
|
1252
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/outofoffice"""
|
|
1253
|
+
|
|
1254
|
+
ELEMENT_NAME = "OutOfOffice"
|
|
1255
|
+
|
|
1256
|
+
reply_body = MessageField(field_uri="ReplyBody")
|
|
1257
|
+
start = DateTimeField(field_uri="StartTime", is_required=False)
|
|
1258
|
+
end = DateTimeField(field_uri="EndTime", is_required=False)
|
|
1259
|
+
|
|
1260
|
+
@classmethod
|
|
1261
|
+
def duration_to_start_end(cls, elem, account):
|
|
1262
|
+
kwargs = {}
|
|
1263
|
+
duration = elem.find(f"{{{TNS}}}Duration")
|
|
1264
|
+
if duration is not None:
|
|
1265
|
+
for attr in ("start", "end"):
|
|
1266
|
+
f = cls.get_field_by_fieldname(attr)
|
|
1267
|
+
kwargs[attr] = f.from_xml(elem=duration, account=account)
|
|
1268
|
+
return kwargs
|
|
1269
|
+
|
|
1270
|
+
@classmethod
|
|
1271
|
+
def from_xml(cls, elem, account):
|
|
1272
|
+
kwargs = {}
|
|
1273
|
+
for attr in ("reply_body",):
|
|
1274
|
+
f = cls.get_field_by_fieldname(attr)
|
|
1275
|
+
kwargs[attr] = f.from_xml(elem=elem, account=account)
|
|
1276
|
+
kwargs.update(cls.duration_to_start_end(elem=elem, account=account))
|
|
1277
|
+
cls._clear(elem)
|
|
1278
|
+
return cls(**kwargs)
|
|
1279
|
+
|
|
1280
|
+
|
|
1281
|
+
class MailTips(EWSElement):
|
|
1282
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/mailtips"""
|
|
1283
|
+
|
|
1284
|
+
ELEMENT_NAME = "MailTips"
|
|
1285
|
+
NAMESPACE = MNS
|
|
1286
|
+
|
|
1287
|
+
recipient_address = RecipientAddressField()
|
|
1288
|
+
pending_mail_tips = ChoiceField(field_uri="PendingMailTips", choices={Choice(c) for c in MAIL_TIPS_TYPES})
|
|
1289
|
+
out_of_office = EWSElementField(value_cls=OutOfOffice)
|
|
1290
|
+
mailbox_full = BooleanField(field_uri="MailboxFull")
|
|
1291
|
+
custom_mail_tip = TextField(field_uri="CustomMailTip")
|
|
1292
|
+
total_member_count = IntegerField(field_uri="TotalMemberCount")
|
|
1293
|
+
external_member_count = IntegerField(field_uri="ExternalMemberCount")
|
|
1294
|
+
max_message_size = IntegerField(field_uri="MaxMessageSize")
|
|
1295
|
+
delivery_restricted = BooleanField(field_uri="DeliveryRestricted")
|
|
1296
|
+
is_moderated = BooleanField(field_uri="IsModerated")
|
|
1297
|
+
invalid_recipient = BooleanField(field_uri="InvalidRecipient")
|
|
1298
|
+
|
|
1299
|
+
|
|
1300
|
+
ENTRY_ID = "EntryId" # The base64-encoded PR_ENTRYID property
|
|
1301
|
+
EWS_ID = "EwsId" # The EWS format used in Exchange 2007 SP1 and later
|
|
1302
|
+
EWS_LEGACY_ID = "EwsLegacyId" # The EWS format used in Exchange 2007 before SP1
|
|
1303
|
+
HEX_ENTRY_ID = "HexEntryId" # The hexadecimal representation of the PR_ENTRYID property
|
|
1304
|
+
OWA_ID = "OwaId" # The OWA format for Exchange 2007 and 2010
|
|
1305
|
+
STORE_ID = "StoreId" # The Exchange Store format
|
|
1306
|
+
# IdFormat enum
|
|
1307
|
+
ID_FORMATS = (ENTRY_ID, EWS_ID, EWS_LEGACY_ID, HEX_ENTRY_ID, OWA_ID, STORE_ID)
|
|
1308
|
+
|
|
1309
|
+
|
|
1310
|
+
class AlternateId(EWSElement):
|
|
1311
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/alternateid"""
|
|
1312
|
+
|
|
1313
|
+
ELEMENT_NAME = "AlternateId"
|
|
1314
|
+
|
|
1315
|
+
id = CharField(field_uri="Id", is_required=True, is_attribute=True)
|
|
1316
|
+
format = ChoiceField(
|
|
1317
|
+
field_uri="Format", is_required=True, is_attribute=True, choices={Choice(c) for c in ID_FORMATS}
|
|
1318
|
+
)
|
|
1319
|
+
mailbox = EmailAddressField(field_uri="Mailbox", is_required=True, is_attribute=True)
|
|
1320
|
+
is_archive = BooleanField(field_uri="IsArchive", is_required=False, is_attribute=True)
|
|
1321
|
+
|
|
1322
|
+
@classmethod
|
|
1323
|
+
def response_tag(cls):
|
|
1324
|
+
# This element is in TNS in the request and MNS in the response...
|
|
1325
|
+
return f"{{{MNS}}}{cls.ELEMENT_NAME}"
|
|
1326
|
+
|
|
1327
|
+
|
|
1328
|
+
class AlternatePublicFolderId(EWSElement):
|
|
1329
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/alternatepublicfolderid"""
|
|
1330
|
+
|
|
1331
|
+
ELEMENT_NAME = "AlternatePublicFolderId"
|
|
1332
|
+
|
|
1333
|
+
folder_id = CharField(field_uri="FolderId", is_required=True, is_attribute=True)
|
|
1334
|
+
format = ChoiceField(
|
|
1335
|
+
field_uri="Format", is_required=True, is_attribute=True, choices={Choice(c) for c in ID_FORMATS}
|
|
1336
|
+
)
|
|
1337
|
+
|
|
1338
|
+
|
|
1339
|
+
class AlternatePublicFolderItemId(EWSElement):
|
|
1340
|
+
"""MSDN:
|
|
1341
|
+
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/alternatepublicfolderitemid
|
|
1342
|
+
"""
|
|
1343
|
+
|
|
1344
|
+
ELEMENT_NAME = "AlternatePublicFolderItemId"
|
|
1345
|
+
|
|
1346
|
+
folder_id = CharField(field_uri="FolderId", is_required=True, is_attribute=True)
|
|
1347
|
+
format = ChoiceField(
|
|
1348
|
+
field_uri="Format", is_required=True, is_attribute=True, choices={Choice(c) for c in ID_FORMATS}
|
|
1349
|
+
)
|
|
1350
|
+
item_id = CharField(field_uri="ItemId", is_required=True, is_attribute=True)
|
|
1351
|
+
|
|
1352
|
+
|
|
1353
|
+
class FieldURI(EWSElement):
|
|
1354
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/fielduri"""
|
|
1355
|
+
|
|
1356
|
+
ELEMENT_NAME = "FieldURI"
|
|
1357
|
+
|
|
1358
|
+
field_uri = CharField(field_uri="FieldURI", is_attribute=True, is_required=True)
|
|
1359
|
+
|
|
1360
|
+
|
|
1361
|
+
class IndexedFieldURI(EWSElement):
|
|
1362
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/indexedfielduri"""
|
|
1363
|
+
|
|
1364
|
+
ELEMENT_NAME = "IndexedFieldURI"
|
|
1365
|
+
|
|
1366
|
+
field_uri = CharField(field_uri="FieldURI", is_attribute=True, is_required=True)
|
|
1367
|
+
field_index = CharField(field_uri="FieldIndex", is_attribute=True, is_required=True)
|
|
1368
|
+
|
|
1369
|
+
|
|
1370
|
+
class ExtendedFieldURI(EWSElement):
|
|
1371
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/extendedfielduri"""
|
|
1372
|
+
|
|
1373
|
+
ELEMENT_NAME = "ExtendedFieldURI"
|
|
1374
|
+
|
|
1375
|
+
distinguished_property_set_id = CharField(field_uri="DistinguishedPropertySetId", is_attribute=True)
|
|
1376
|
+
property_set_id = CharField(field_uri="PropertySetId", is_attribute=True)
|
|
1377
|
+
property_tag = CharField(field_uri="PropertyTag", is_attribute=True)
|
|
1378
|
+
property_name = CharField(field_uri="PropertyName", is_attribute=True)
|
|
1379
|
+
property_id = CharField(field_uri="PropertyId", is_attribute=True)
|
|
1380
|
+
property_type = CharField(field_uri="PropertyType", is_attribute=True)
|
|
1381
|
+
|
|
1382
|
+
|
|
1383
|
+
class ExceptionFieldURI(EWSElement):
|
|
1384
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/exceptionfielduri"""
|
|
1385
|
+
|
|
1386
|
+
ELEMENT_NAME = "ExceptionFieldURI"
|
|
1387
|
+
|
|
1388
|
+
field_uri = CharField(field_uri="FieldURI", is_attribute=True, is_required=True)
|
|
1389
|
+
|
|
1390
|
+
|
|
1391
|
+
class CompleteName(EWSElement):
|
|
1392
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/completename"""
|
|
1393
|
+
|
|
1394
|
+
ELEMENT_NAME = "CompleteName"
|
|
1395
|
+
|
|
1396
|
+
title = CharField(field_uri="Title")
|
|
1397
|
+
first_name = CharField(field_uri="FirstName")
|
|
1398
|
+
middle_name = CharField(field_uri="MiddleName")
|
|
1399
|
+
last_name = CharField(field_uri="LastName")
|
|
1400
|
+
suffix = CharField(field_uri="Suffix")
|
|
1401
|
+
initials = CharField(field_uri="Initials")
|
|
1402
|
+
full_name = CharField(field_uri="FullName")
|
|
1403
|
+
nickname = CharField(field_uri="Nickname")
|
|
1404
|
+
yomi_first_name = CharField(field_uri="YomiFirstName")
|
|
1405
|
+
yomi_last_name = CharField(field_uri="YomiLastName")
|
|
1406
|
+
|
|
1407
|
+
|
|
1408
|
+
class ReminderMessageData(EWSElement):
|
|
1409
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/remindermessagedata"""
|
|
1410
|
+
|
|
1411
|
+
ELEMENT_NAME = "ReminderMessageData"
|
|
1412
|
+
|
|
1413
|
+
reminder_text = CharField(field_uri="ReminderText")
|
|
1414
|
+
location = CharField(field_uri="Location")
|
|
1415
|
+
start_time = TimeField(field_uri="StartTime")
|
|
1416
|
+
end_time = TimeField(field_uri="EndTime")
|
|
1417
|
+
associated_calendar_item_id = AssociatedCalendarItemIdField(
|
|
1418
|
+
field_uri="AssociatedCalendarItemId", supported_from=Build(15, 0, 913, 9)
|
|
1419
|
+
)
|
|
1420
|
+
|
|
1421
|
+
|
|
1422
|
+
class AcceptSharingInvitation(EWSElement):
|
|
1423
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/acceptsharinginvitation"""
|
|
1424
|
+
|
|
1425
|
+
ELEMENT_NAME = "AcceptSharingInvitation"
|
|
1426
|
+
|
|
1427
|
+
reference_item_id = ReferenceItemIdField(field_uri="item:ReferenceItemId")
|
|
1428
|
+
|
|
1429
|
+
|
|
1430
|
+
class SuppressReadReceipt(EWSElement):
|
|
1431
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/suppressreadreceipt"""
|
|
1432
|
+
|
|
1433
|
+
ELEMENT_NAME = "SuppressReadReceipt"
|
|
1434
|
+
|
|
1435
|
+
reference_item_id = ReferenceItemIdField(field_uri="item:ReferenceItemId")
|
|
1436
|
+
|
|
1437
|
+
|
|
1438
|
+
class RemoveItem(EWSElement):
|
|
1439
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/removeitem"""
|
|
1440
|
+
|
|
1441
|
+
ELEMENT_NAME = "RemoveItem"
|
|
1442
|
+
|
|
1443
|
+
reference_item_id = ReferenceItemIdField(field_uri="item:ReferenceItemId")
|
|
1444
|
+
|
|
1445
|
+
|
|
1446
|
+
class ResponseObjects(EWSElement):
|
|
1447
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/responseobjects"""
|
|
1448
|
+
|
|
1449
|
+
ELEMENT_NAME = "ResponseObjects"
|
|
1450
|
+
|
|
1451
|
+
accept_item = EWSElementField(field_uri="AcceptItem", value_cls="AcceptItem", namespace=TNS)
|
|
1452
|
+
tentatively_accept_item = EWSElementField(
|
|
1453
|
+
field_uri="TentativelyAcceptItem", value_cls="TentativelyAcceptItem", namespace=TNS
|
|
1454
|
+
)
|
|
1455
|
+
decline_item = EWSElementField(field_uri="DeclineItem", value_cls="DeclineItem", namespace=TNS)
|
|
1456
|
+
reply_to_item = EWSElementField(field_uri="ReplyToItem", value_cls="ReplyToItem", namespace=TNS)
|
|
1457
|
+
forward_item = EWSElementField(field_uri="ForwardItem", value_cls="ForwardItem", namespace=TNS)
|
|
1458
|
+
reply_all_to_item = EWSElementField(field_uri="ReplyAllToItem", value_cls="ReplyAllToItem", namespace=TNS)
|
|
1459
|
+
cancel_calendar_item = EWSElementField(
|
|
1460
|
+
field_uri="CancelCalendarItem", value_cls="CancelCalendarItem", namespace=TNS
|
|
1461
|
+
)
|
|
1462
|
+
remove_item = EWSElementField(field_uri="RemoveItem", value_cls=RemoveItem)
|
|
1463
|
+
post_reply_item = EWSElementField(field_uri="PostReplyItem", value_cls="PostReplyItem", namespace=TNS)
|
|
1464
|
+
success_read_receipt = EWSElementField(field_uri="SuppressReadReceipt", value_cls=SuppressReadReceipt)
|
|
1465
|
+
accept_sharing_invitation = EWSElementField(field_uri="AcceptSharingInvitation", value_cls=AcceptSharingInvitation)
|
|
1466
|
+
|
|
1467
|
+
|
|
1468
|
+
class PhoneNumber(EWSElement):
|
|
1469
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/phonenumber"""
|
|
1470
|
+
|
|
1471
|
+
ELEMENT_NAME = "PhoneNumber"
|
|
1472
|
+
|
|
1473
|
+
number = CharField(field_uri="Number")
|
|
1474
|
+
type = CharField(field_uri="Type")
|
|
1475
|
+
|
|
1476
|
+
|
|
1477
|
+
class IdChangeKeyMixIn(EWSElement, metaclass=EWSMeta):
|
|
1478
|
+
"""Base class for classes that have a concept of 'id' and 'changekey' values. The values are actually stored on
|
|
1479
|
+
a separate element, but we add convenience methods to hide that fact.
|
|
1480
|
+
"""
|
|
1481
|
+
|
|
1482
|
+
ID_ELEMENT_CLS = None
|
|
1483
|
+
|
|
1484
|
+
def __init__(self, **kwargs):
|
|
1485
|
+
_id, _changekey = kwargs.pop("id", None), kwargs.pop("changekey", None)
|
|
1486
|
+
if _id or _changekey:
|
|
1487
|
+
kwargs["_id"] = self.ID_ELEMENT_CLS(_id, _changekey)
|
|
1488
|
+
super().__init__(**kwargs)
|
|
1489
|
+
|
|
1490
|
+
@classmethod
|
|
1491
|
+
def get_field_by_fieldname(cls, fieldname):
|
|
1492
|
+
if fieldname in ("id", "changekey"):
|
|
1493
|
+
return cls.ID_ELEMENT_CLS.get_field_by_fieldname(fieldname=fieldname)
|
|
1494
|
+
return super().get_field_by_fieldname(fieldname=fieldname)
|
|
1495
|
+
|
|
1496
|
+
@property
|
|
1497
|
+
def id(self):
|
|
1498
|
+
if self._id is None:
|
|
1499
|
+
return None
|
|
1500
|
+
return self._id.id
|
|
1501
|
+
|
|
1502
|
+
@id.setter
|
|
1503
|
+
def id(self, value):
|
|
1504
|
+
if self._id is None:
|
|
1505
|
+
self._id = self.ID_ELEMENT_CLS()
|
|
1506
|
+
self._id.id = value
|
|
1507
|
+
|
|
1508
|
+
@property
|
|
1509
|
+
def changekey(self):
|
|
1510
|
+
if self._id is None:
|
|
1511
|
+
return None
|
|
1512
|
+
return self._id.changekey
|
|
1513
|
+
|
|
1514
|
+
@changekey.setter
|
|
1515
|
+
def changekey(self, value):
|
|
1516
|
+
if self._id is None:
|
|
1517
|
+
self._id = self.ID_ELEMENT_CLS()
|
|
1518
|
+
self._id.changekey = value
|
|
1519
|
+
|
|
1520
|
+
@classmethod
|
|
1521
|
+
def id_from_xml(cls, elem):
|
|
1522
|
+
# This method must be reasonably fast
|
|
1523
|
+
id_elem = elem.find(cls.ID_ELEMENT_CLS.response_tag())
|
|
1524
|
+
if id_elem is None:
|
|
1525
|
+
return None, None
|
|
1526
|
+
return id_elem.get(cls.ID_ELEMENT_CLS.ID_ATTR), id_elem.get(cls.ID_ELEMENT_CLS.CHANGEKEY_ATTR)
|
|
1527
|
+
|
|
1528
|
+
def to_id(self):
|
|
1529
|
+
if self._id is None:
|
|
1530
|
+
raise ValueError("Must have an ID")
|
|
1531
|
+
return self._id
|
|
1532
|
+
|
|
1533
|
+
def __eq__(self, other):
|
|
1534
|
+
if isinstance(other, tuple):
|
|
1535
|
+
return hash((self.id, self.changekey)) == hash(other)
|
|
1536
|
+
return super().__eq__(other)
|
|
1537
|
+
|
|
1538
|
+
def __hash__(self):
|
|
1539
|
+
# If we have an ID and changekey, use that as key. Else return a hash of all attributes
|
|
1540
|
+
if self.id:
|
|
1541
|
+
return hash((self.id, self.changekey))
|
|
1542
|
+
return super().__hash__()
|
|
1543
|
+
|
|
1544
|
+
|
|
1545
|
+
class DictionaryEntry(EWSElement):
|
|
1546
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/dictionaryentry"""
|
|
1547
|
+
|
|
1548
|
+
ELEMENT_NAME = "DictionaryEntry"
|
|
1549
|
+
|
|
1550
|
+
key = TypeValueField(field_uri="DictionaryKey")
|
|
1551
|
+
value = TypeValueField(field_uri="DictionaryValue")
|
|
1552
|
+
|
|
1553
|
+
|
|
1554
|
+
class UserConfigurationName(EWSElement):
|
|
1555
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/userconfigurationname"""
|
|
1556
|
+
|
|
1557
|
+
ELEMENT_NAME = "UserConfigurationName"
|
|
1558
|
+
NAMESPACE = TNS
|
|
1559
|
+
|
|
1560
|
+
name = CharField(field_uri="Name", is_attribute=True)
|
|
1561
|
+
folder = EWSElementField(value_cls=FolderId)
|
|
1562
|
+
|
|
1563
|
+
def clean(self, version=None):
|
|
1564
|
+
from .folders import BaseFolder
|
|
1565
|
+
|
|
1566
|
+
if isinstance(self.folder, BaseFolder):
|
|
1567
|
+
self.folder = self.folder.to_id()
|
|
1568
|
+
super().clean(version=version)
|
|
1569
|
+
|
|
1570
|
+
@classmethod
|
|
1571
|
+
def from_xml(cls, elem, account):
|
|
1572
|
+
# We also accept distinguished folders
|
|
1573
|
+
f = EWSElementField(value_cls=DistinguishedFolderId)
|
|
1574
|
+
distinguished_folder_id = f.from_xml(elem=elem, account=account)
|
|
1575
|
+
res = super().from_xml(elem=elem, account=account)
|
|
1576
|
+
if distinguished_folder_id:
|
|
1577
|
+
res.folder = distinguished_folder_id
|
|
1578
|
+
return res
|
|
1579
|
+
|
|
1580
|
+
|
|
1581
|
+
class UserConfigurationNameMNS(UserConfigurationName):
|
|
1582
|
+
"""Like UserConfigurationName, but in the MNS namespace.
|
|
1583
|
+
|
|
1584
|
+
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/userconfigurationname
|
|
1585
|
+
"""
|
|
1586
|
+
|
|
1587
|
+
NAMESPACE = MNS
|
|
1588
|
+
|
|
1589
|
+
|
|
1590
|
+
class UserConfiguration(IdChangeKeyMixIn):
|
|
1591
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/userconfiguration"""
|
|
1592
|
+
|
|
1593
|
+
ELEMENT_NAME = "UserConfiguration"
|
|
1594
|
+
NAMESPACE = MNS
|
|
1595
|
+
ID_ELEMENT_CLS = ItemId
|
|
1596
|
+
|
|
1597
|
+
_id = IdElementField(field_uri="ItemId", value_cls=ID_ELEMENT_CLS)
|
|
1598
|
+
user_configuration_name = EWSElementField(value_cls=UserConfigurationName)
|
|
1599
|
+
dictionary = DictionaryField(field_uri="Dictionary")
|
|
1600
|
+
xml_data = Base64Field(field_uri="XmlData")
|
|
1601
|
+
binary_data = Base64Field(field_uri="BinaryData")
|
|
1602
|
+
|
|
1603
|
+
|
|
1604
|
+
class Attribution(IdChangeKeyMixIn):
|
|
1605
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/phonenumber"""
|
|
1606
|
+
|
|
1607
|
+
ELEMENT_NAME = "Attribution"
|
|
1608
|
+
ID_ELEMENT_CLS = SourceId
|
|
1609
|
+
|
|
1610
|
+
ID = CharField(field_uri="Id")
|
|
1611
|
+
_id = IdElementField(field_uri="SourceId", value_cls=ID_ELEMENT_CLS)
|
|
1612
|
+
display_name = CharField(field_uri="DisplayName")
|
|
1613
|
+
is_writable = BooleanField(field_uri="IsWritable")
|
|
1614
|
+
is_quick_contact = BooleanField(field_uri="IsQuickContact")
|
|
1615
|
+
is_hidden = BooleanField(field_uri="IsHidden")
|
|
1616
|
+
folder_id = EWSElementField(value_cls=FolderId)
|
|
1617
|
+
|
|
1618
|
+
|
|
1619
|
+
class BodyContentValue(EWSElement):
|
|
1620
|
+
"""MSDN:
|
|
1621
|
+
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/value-bodycontenttype
|
|
1622
|
+
"""
|
|
1623
|
+
|
|
1624
|
+
ELEMENT_NAME = "Value"
|
|
1625
|
+
|
|
1626
|
+
value = CharField(field_uri="Value")
|
|
1627
|
+
body_type = CharField(field_uri="BodyType")
|
|
1628
|
+
|
|
1629
|
+
|
|
1630
|
+
class BodyContentAttributedValue(EWSElement):
|
|
1631
|
+
"""MSDN:
|
|
1632
|
+
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/bodycontentattributedvalue
|
|
1633
|
+
"""
|
|
1634
|
+
|
|
1635
|
+
ELEMENT_NAME = "BodyContentAttributedValue"
|
|
1636
|
+
|
|
1637
|
+
value = EWSElementField(value_cls=BodyContentValue)
|
|
1638
|
+
attributions = EWSElementListField(field_uri="Attributions", value_cls=Attribution)
|
|
1639
|
+
|
|
1640
|
+
|
|
1641
|
+
class StringAttributedValue(EWSElement):
|
|
1642
|
+
"""MSDN:
|
|
1643
|
+
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/stringattributedvalue
|
|
1644
|
+
"""
|
|
1645
|
+
|
|
1646
|
+
ELEMENT_NAME = "StringAttributedValue"
|
|
1647
|
+
|
|
1648
|
+
value = CharField(field_uri="Value")
|
|
1649
|
+
attributions = CharListField(field_uri="Attributions", list_elem_name="Attribution")
|
|
1650
|
+
|
|
1651
|
+
|
|
1652
|
+
class PersonaPhoneNumberTypeValue(EWSElement):
|
|
1653
|
+
"""MSDN:
|
|
1654
|
+
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/value-personaphonenumbertype
|
|
1655
|
+
"""
|
|
1656
|
+
|
|
1657
|
+
ELEMENT_NAME = "Value"
|
|
1658
|
+
|
|
1659
|
+
number = CharField(field_uri="Number")
|
|
1660
|
+
type = CharField(field_uri="Type")
|
|
1661
|
+
|
|
1662
|
+
|
|
1663
|
+
class PhoneNumberAttributedValue(EWSElement):
|
|
1664
|
+
"""MSDN:
|
|
1665
|
+
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/phonenumberattributedvalue
|
|
1666
|
+
"""
|
|
1667
|
+
|
|
1668
|
+
ELEMENT_NAME = "PhoneNumberAttributedValue"
|
|
1669
|
+
|
|
1670
|
+
value = EWSElementField(value_cls=PersonaPhoneNumberTypeValue)
|
|
1671
|
+
attributions = CharListField(field_uri="Attributions", list_elem_name="Attribution")
|
|
1672
|
+
|
|
1673
|
+
|
|
1674
|
+
class EmailAddressTypeValue(Mailbox):
|
|
1675
|
+
"""MSDN:
|
|
1676
|
+
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/value-emailaddresstype
|
|
1677
|
+
"""
|
|
1678
|
+
|
|
1679
|
+
ELEMENT_NAME = "Value"
|
|
1680
|
+
|
|
1681
|
+
original_display_name = TextField(field_uri="OriginalDisplayName")
|
|
1682
|
+
|
|
1683
|
+
|
|
1684
|
+
class EmailAddressAttributedValue(EWSElement):
|
|
1685
|
+
"""MSDN:
|
|
1686
|
+
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/emailaddressattributedvalue
|
|
1687
|
+
"""
|
|
1688
|
+
|
|
1689
|
+
ELEMENT_NAME = "EmailAddressAttributedValue"
|
|
1690
|
+
|
|
1691
|
+
value = EWSElementField(value_cls=EmailAddressTypeValue)
|
|
1692
|
+
attributions = EWSElementListField(field_uri="Attributions", value_cls=Attribution)
|
|
1693
|
+
|
|
1694
|
+
|
|
1695
|
+
class PersonaPostalAddressTypeValue(Mailbox):
|
|
1696
|
+
"""MSDN:
|
|
1697
|
+
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/value-personapostaladdresstype
|
|
1698
|
+
"""
|
|
1699
|
+
|
|
1700
|
+
ELEMENT_NAME = "Value"
|
|
1701
|
+
|
|
1702
|
+
street = TextField(field_uri="Street")
|
|
1703
|
+
city = TextField(field_uri="City")
|
|
1704
|
+
state = TextField(field_uri="State")
|
|
1705
|
+
country = TextField(field_uri="Country")
|
|
1706
|
+
postal_code = TextField(field_uri="PostalCode")
|
|
1707
|
+
post_office_box = TextField(field_uri="PostOfficeBox")
|
|
1708
|
+
type = TextField(field_uri="Type")
|
|
1709
|
+
latitude = TextField(field_uri="Latitude")
|
|
1710
|
+
longitude = TextField(field_uri="Longitude")
|
|
1711
|
+
accuracy = TextField(field_uri="Accuracy")
|
|
1712
|
+
altitude = TextField(field_uri="Altitude")
|
|
1713
|
+
altitude_accuracy = TextField(field_uri="AltitudeAccuracy")
|
|
1714
|
+
formatted_address = TextField(field_uri="FormattedAddress")
|
|
1715
|
+
location_uri = TextField(field_uri="LocationUri")
|
|
1716
|
+
location_source = TextField(field_uri="LocationSource")
|
|
1717
|
+
|
|
1718
|
+
|
|
1719
|
+
class PostalAddressAttributedValue(EWSElement):
|
|
1720
|
+
"""MSDN:
|
|
1721
|
+
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/postaladdressattributedvalue
|
|
1722
|
+
"""
|
|
1723
|
+
|
|
1724
|
+
ELEMENT_NAME = "PostalAddressAttributedValue"
|
|
1725
|
+
|
|
1726
|
+
value = EWSElementField(value_cls=PersonaPostalAddressTypeValue)
|
|
1727
|
+
attributions = EWSElementListField(field_uri="Attributions", value_cls=Attribution)
|
|
1728
|
+
|
|
1729
|
+
|
|
1730
|
+
class Event(EWSElement, metaclass=EWSMeta):
|
|
1731
|
+
"""Base class for all event types."""
|
|
1732
|
+
|
|
1733
|
+
watermark = CharField(field_uri="Watermark")
|
|
1734
|
+
|
|
1735
|
+
|
|
1736
|
+
class TimestampEvent(Event, metaclass=EWSMeta):
|
|
1737
|
+
"""Base class for both item and folder events with a timestamp."""
|
|
1738
|
+
|
|
1739
|
+
FOLDER = "folder"
|
|
1740
|
+
ITEM = "item"
|
|
1741
|
+
|
|
1742
|
+
timestamp = DateTimeField(field_uri="TimeStamp")
|
|
1743
|
+
item_id = EWSElementField(value_cls=ItemId)
|
|
1744
|
+
folder_id = EWSElementField(value_cls=FolderId)
|
|
1745
|
+
parent_folder_id = EWSElementField(value_cls=ParentFolderId)
|
|
1746
|
+
|
|
1747
|
+
@property
|
|
1748
|
+
def event_type(self):
|
|
1749
|
+
if self.item_id is not None:
|
|
1750
|
+
return self.ITEM
|
|
1751
|
+
if self.folder_id is not None:
|
|
1752
|
+
return self.FOLDER
|
|
1753
|
+
return None # Empty object
|
|
1754
|
+
|
|
1755
|
+
|
|
1756
|
+
class OldTimestampEvent(TimestampEvent, metaclass=EWSMeta):
|
|
1757
|
+
"""Base class for both item and folder copy/move events."""
|
|
1758
|
+
|
|
1759
|
+
old_item_id = EWSElementField(value_cls=OldItemId)
|
|
1760
|
+
old_folder_id = EWSElementField(value_cls=OldFolderId)
|
|
1761
|
+
old_parent_folder_id = EWSElementField(value_cls=OldParentFolderId)
|
|
1762
|
+
|
|
1763
|
+
|
|
1764
|
+
class CopiedEvent(OldTimestampEvent):
|
|
1765
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/copiedevent"""
|
|
1766
|
+
|
|
1767
|
+
ELEMENT_NAME = "CopiedEvent"
|
|
1768
|
+
|
|
1769
|
+
|
|
1770
|
+
class CreatedEvent(TimestampEvent):
|
|
1771
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/createdevent"""
|
|
1772
|
+
|
|
1773
|
+
ELEMENT_NAME = "CreatedEvent"
|
|
1774
|
+
|
|
1775
|
+
|
|
1776
|
+
class DeletedEvent(TimestampEvent):
|
|
1777
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/deletedevent"""
|
|
1778
|
+
|
|
1779
|
+
ELEMENT_NAME = "DeletedEvent"
|
|
1780
|
+
|
|
1781
|
+
|
|
1782
|
+
class ModifiedEvent(TimestampEvent):
|
|
1783
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/modifiedevent"""
|
|
1784
|
+
|
|
1785
|
+
ELEMENT_NAME = "ModifiedEvent"
|
|
1786
|
+
|
|
1787
|
+
unread_count = IntegerField(field_uri="UnreadCount")
|
|
1788
|
+
|
|
1789
|
+
|
|
1790
|
+
class MovedEvent(OldTimestampEvent):
|
|
1791
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/movedevent"""
|
|
1792
|
+
|
|
1793
|
+
ELEMENT_NAME = "MovedEvent"
|
|
1794
|
+
|
|
1795
|
+
|
|
1796
|
+
class NewMailEvent(TimestampEvent):
|
|
1797
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/newmailevent"""
|
|
1798
|
+
|
|
1799
|
+
ELEMENT_NAME = "NewMailEvent"
|
|
1800
|
+
|
|
1801
|
+
|
|
1802
|
+
class StatusEvent(Event):
|
|
1803
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/statusevent"""
|
|
1804
|
+
|
|
1805
|
+
ELEMENT_NAME = "StatusEvent"
|
|
1806
|
+
|
|
1807
|
+
|
|
1808
|
+
class FreeBusyChangedEvent(TimestampEvent):
|
|
1809
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/freebusychangedevent"""
|
|
1810
|
+
|
|
1811
|
+
ELEMENT_NAME = "FreeBusyChangedEvent"
|
|
1812
|
+
|
|
1813
|
+
|
|
1814
|
+
class Notification(EWSElement):
|
|
1815
|
+
"""MSDN:
|
|
1816
|
+
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/notification-ex15websvcsotherref
|
|
1817
|
+
"""
|
|
1818
|
+
|
|
1819
|
+
ELEMENT_NAME = "Notification"
|
|
1820
|
+
NAMESPACE = MNS
|
|
1821
|
+
|
|
1822
|
+
subscription_id = CharField(field_uri="SubscriptionId")
|
|
1823
|
+
previous_watermark = CharField(field_uri="PreviousWatermark")
|
|
1824
|
+
more_events = BooleanField(field_uri="MoreEvents")
|
|
1825
|
+
events = GenericEventListField("")
|
|
1826
|
+
|
|
1827
|
+
|
|
1828
|
+
class BaseTransition(EWSElement, metaclass=EWSMeta):
|
|
1829
|
+
"""Base class for all other transition classes"""
|
|
1830
|
+
|
|
1831
|
+
to = CharField(field_uri="To")
|
|
1832
|
+
kind = CharField(field_uri="Kind", is_attribute=True) # An attribute on the 'To' element
|
|
1833
|
+
|
|
1834
|
+
@staticmethod
|
|
1835
|
+
def transition_model_from_tag(tag):
|
|
1836
|
+
return {
|
|
1837
|
+
cls.response_tag(): cls
|
|
1838
|
+
for cls in (Transition, AbsoluteDateTransition, RecurringDateTransition, RecurringDayTransition)
|
|
1839
|
+
}[tag]
|
|
1840
|
+
|
|
1841
|
+
@classmethod
|
|
1842
|
+
def from_xml(cls, elem, account):
|
|
1843
|
+
kind = elem.find(cls.get_field_by_fieldname("to").response_tag()).get("Kind")
|
|
1844
|
+
res = super().from_xml(elem=elem, account=account)
|
|
1845
|
+
res.kind = kind
|
|
1846
|
+
return res
|
|
1847
|
+
|
|
1848
|
+
|
|
1849
|
+
class Transition(BaseTransition):
|
|
1850
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/transition"""
|
|
1851
|
+
|
|
1852
|
+
ELEMENT_NAME = "Transition"
|
|
1853
|
+
|
|
1854
|
+
|
|
1855
|
+
class AbsoluteDateTransition(BaseTransition):
|
|
1856
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/absolutedatetransition"""
|
|
1857
|
+
|
|
1858
|
+
ELEMENT_NAME = "AbsoluteDateTransition"
|
|
1859
|
+
|
|
1860
|
+
# Values are returned as naive, and we have no timezone to hook up the values to yet
|
|
1861
|
+
date = DateTimeBackedDateField(field_uri="DateTime", allow_naive=True)
|
|
1862
|
+
|
|
1863
|
+
|
|
1864
|
+
class RecurringDayTransition(BaseTransition):
|
|
1865
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/recurringdaytransition"""
|
|
1866
|
+
|
|
1867
|
+
ELEMENT_NAME = "RecurringDayTransition"
|
|
1868
|
+
|
|
1869
|
+
offset = TimeDeltaField(field_uri="TimeOffset")
|
|
1870
|
+
month = IntegerField(field_uri="Month")
|
|
1871
|
+
# Valid ISO 8601 weekday, as a number in range 1 -> 7 (1 being Monday)
|
|
1872
|
+
day_of_week = EnumField(field_uri="DayOfWeek", enum=WEEKDAY_NAMES)
|
|
1873
|
+
occurrence = IntegerField(field_uri="Occurrence")
|
|
1874
|
+
|
|
1875
|
+
@classmethod
|
|
1876
|
+
def from_xml(cls, elem, account):
|
|
1877
|
+
res = super().from_xml(elem=elem, account=account)
|
|
1878
|
+
# See TimeZoneTransition.from_xml()
|
|
1879
|
+
if res.occurrence == -1:
|
|
1880
|
+
res.occurrence = 5
|
|
1881
|
+
return res
|
|
1882
|
+
|
|
1883
|
+
|
|
1884
|
+
class RecurringDateTransition(BaseTransition):
|
|
1885
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/recurringdatetransition"""
|
|
1886
|
+
|
|
1887
|
+
ELEMENT_NAME = "RecurringDateTransition"
|
|
1888
|
+
|
|
1889
|
+
offset = TimeDeltaField(field_uri="TimeOffset")
|
|
1890
|
+
month = IntegerField(field_uri="Month")
|
|
1891
|
+
day = IntegerField(field_uri="Day") # Day of month
|
|
1892
|
+
|
|
1893
|
+
|
|
1894
|
+
class Period(EWSElement):
|
|
1895
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/period"""
|
|
1896
|
+
|
|
1897
|
+
ELEMENT_NAME = "Period"
|
|
1898
|
+
|
|
1899
|
+
id = CharField(field_uri="Id", is_attribute=True)
|
|
1900
|
+
name = CharField(field_uri="Name", is_attribute=True)
|
|
1901
|
+
bias = TimeDeltaField(field_uri="Bias", is_attribute=True)
|
|
1902
|
+
|
|
1903
|
+
@property
|
|
1904
|
+
def bias_in_minutes(self):
|
|
1905
|
+
return int(self.bias.total_seconds()) // 60 # Convert to minutes
|
|
1906
|
+
|
|
1907
|
+
|
|
1908
|
+
class TransitionsGroup(EWSElement):
|
|
1909
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/transitionsgroup"""
|
|
1910
|
+
|
|
1911
|
+
ELEMENT_NAME = "TransitionsGroup"
|
|
1912
|
+
|
|
1913
|
+
id = CharField(field_uri="Id", is_attribute=True)
|
|
1914
|
+
transitions = TransitionListField(value_cls=BaseTransition)
|
|
1915
|
+
|
|
1916
|
+
|
|
1917
|
+
class TimeZoneDefinition(EWSElement):
|
|
1918
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/timezonedefinition"""
|
|
1919
|
+
|
|
1920
|
+
ELEMENT_NAME = "TimeZoneDefinition"
|
|
1921
|
+
|
|
1922
|
+
id = CharField(field_uri="Id", is_attribute=True)
|
|
1923
|
+
name = CharField(field_uri="Name", is_attribute=True)
|
|
1924
|
+
|
|
1925
|
+
periods = EWSElementListField(field_uri="Periods", value_cls=Period)
|
|
1926
|
+
transitions_groups = EWSElementListField(field_uri="TransitionsGroups", value_cls=TransitionsGroup)
|
|
1927
|
+
transitions = TransitionListField(field_uri="Transitions", value_cls=BaseTransition)
|
|
1928
|
+
|
|
1929
|
+
def _get_standard_period(self, transitions_group):
|
|
1930
|
+
# Find the first standard period referenced from transitions_group
|
|
1931
|
+
standard_periods_map = {p.id: p for p in self.periods if p.name == "Standard"}
|
|
1932
|
+
for transition in transitions_group.transitions:
|
|
1933
|
+
try:
|
|
1934
|
+
return standard_periods_map[transition.to]
|
|
1935
|
+
except KeyError:
|
|
1936
|
+
continue
|
|
1937
|
+
raise ValueError(f"No standard period matching any transition in {transitions_group}")
|
|
1938
|
+
|
|
1939
|
+
def _get_transitions_group(self, for_year):
|
|
1940
|
+
# Look through the transitions, and pick the relevant transition group according to the 'for_year' value
|
|
1941
|
+
transitions_group = None
|
|
1942
|
+
transitions_groups_map = {tg.id: tg for tg in self.transitions_groups}
|
|
1943
|
+
for transition in sorted(self.transitions, key=lambda t: t.to):
|
|
1944
|
+
if transition.kind != "Group":
|
|
1945
|
+
continue
|
|
1946
|
+
if isinstance(transition, AbsoluteDateTransition) and transition.date.year > for_year:
|
|
1947
|
+
break
|
|
1948
|
+
transitions_group = transitions_groups_map[transition.to]
|
|
1949
|
+
if transitions_group is None:
|
|
1950
|
+
raise ValueError(f"No valid transition group for year {for_year}: {self.transitions}")
|
|
1951
|
+
return transitions_group
|
|
1952
|
+
|
|
1953
|
+
def get_std_and_dst(self, for_year):
|
|
1954
|
+
# Return 'standard_time' and 'daylight_time' objects. We do unnecessary work here, but it keeps code simple.
|
|
1955
|
+
transitions_group = self._get_transitions_group(for_year)
|
|
1956
|
+
if not 0 <= len(transitions_group.transitions) <= 2:
|
|
1957
|
+
raise ValueError(f"Expected 0-2 transitions in transitions group {transitions_group}")
|
|
1958
|
+
|
|
1959
|
+
standard_period = self._get_standard_period(transitions_group)
|
|
1960
|
+
periods_map = {p.id: p for p in self.periods}
|
|
1961
|
+
standard_time, daylight_time = None, None
|
|
1962
|
+
if len(transitions_group.transitions) == 1:
|
|
1963
|
+
# This is a simple transition group representing a timezone with no DST. Some servers don't accept
|
|
1964
|
+
# TimeZone elements without an STD and DST element (see issue #488). Return StandardTime and DaylightTime
|
|
1965
|
+
# objects with dummy values and 0 bias - this satisfies the broken servers and hopefully doesn't break
|
|
1966
|
+
# the well-behaving servers.
|
|
1967
|
+
standard_time = StandardTime(bias=0, time=datetime.time(0), occurrence=1, iso_month=1, weekday=1)
|
|
1968
|
+
daylight_time = DaylightTime(bias=0, time=datetime.time(0), occurrence=5, iso_month=12, weekday=7)
|
|
1969
|
+
return standard_time, daylight_time, standard_period
|
|
1970
|
+
for transition in transitions_group.transitions:
|
|
1971
|
+
# 'offset' is the time of day to transition, as timedelta since midnight. Check that it's a reasonable value
|
|
1972
|
+
transition.clean(version=None)
|
|
1973
|
+
transition_kwargs = dict(
|
|
1974
|
+
time=(datetime.datetime(2000, 1, 1) + transition.offset).time(),
|
|
1975
|
+
occurrence=transition.occurrence,
|
|
1976
|
+
iso_month=transition.month,
|
|
1977
|
+
weekday=transition.day_of_week,
|
|
1978
|
+
)
|
|
1979
|
+
period = periods_map[transition.to]
|
|
1980
|
+
if period.name == "Standard":
|
|
1981
|
+
transition_kwargs["bias"] = 0
|
|
1982
|
+
standard_time = StandardTime(**transition_kwargs)
|
|
1983
|
+
continue
|
|
1984
|
+
if period.name == "Daylight":
|
|
1985
|
+
transition_kwargs["bias"] = period.bias_in_minutes - standard_period.bias_in_minutes
|
|
1986
|
+
daylight_time = DaylightTime(**transition_kwargs)
|
|
1987
|
+
continue
|
|
1988
|
+
raise ValueError(f"Unknown transition: {transition}")
|
|
1989
|
+
return standard_time, daylight_time, standard_period
|
|
1990
|
+
|
|
1991
|
+
|
|
1992
|
+
class UserResponse(EWSElement):
|
|
1993
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/userresponse-soap"""
|
|
1994
|
+
|
|
1995
|
+
ELEMENT_NAME = "UserResponse"
|
|
1996
|
+
|
|
1997
|
+
# See https://learn.microsoft.com/en-us/exchange/client-developer/web-service-reference/setting-soap
|
|
1998
|
+
SETTINGS_MAP = {
|
|
1999
|
+
"user_display_name": "UserDisplayName",
|
|
2000
|
+
"user_dn": "UserDN",
|
|
2001
|
+
"user_deployment_id": "UserDeploymentId",
|
|
2002
|
+
"internal_mailbox_server": "InternalMailboxServer",
|
|
2003
|
+
"internal_rpc_client_server": "InternalRpcClientServer",
|
|
2004
|
+
"internal_mailbox_server_dn": "InternalMailboxServerDN",
|
|
2005
|
+
"internal_ecp_url": "InternalEcpUrl",
|
|
2006
|
+
"internal_ecp_voicemail_url": "InternalEcpVoicemailUrl",
|
|
2007
|
+
"internal_ecp_email_subscriptions_url": "InternalEcpEmailSubscriptionsUrl",
|
|
2008
|
+
"internal_ecp_text_messaging_url": "InternalEcpTextMessagingUrl",
|
|
2009
|
+
"internal_ecp_delivery_report_url": "InternalEcpDeliveryReportUrl",
|
|
2010
|
+
"internal_ecp_retention_policy_tags_url": "InternalEcpRetentionPolicyTagsUrl",
|
|
2011
|
+
"internal_ecp_publishing_url": "InternalEcpPublishingUrl",
|
|
2012
|
+
"internal_ews_url": "InternalEwsUrl",
|
|
2013
|
+
"internal_oab_url": "InternalOABUrl",
|
|
2014
|
+
"internal_um_url": "InternalUMUrl",
|
|
2015
|
+
"internal_web_client_urls": "InternalWebClientUrls",
|
|
2016
|
+
"mailbox_dn": "MailboxDN",
|
|
2017
|
+
"public_folder_server": "PublicFolderServer",
|
|
2018
|
+
"active_directory_server": "ActiveDirectoryServer",
|
|
2019
|
+
"external_mailbox_server": "ExternalMailboxServer",
|
|
2020
|
+
"external_mailbox_server_requires_ssl": "ExternalMailboxServerRequiresSSL",
|
|
2021
|
+
"external_mailbox_server_authentication_methods": "ExternalMailboxServerAuthenticationMethods",
|
|
2022
|
+
"ecp_voicemail_url_fragment,": "EcpVoicemailUrlFragment",
|
|
2023
|
+
"ecp_email_subscriptions_url_fragment": "EcpEmailSubscriptionsUrlFragment",
|
|
2024
|
+
"ecp_text_messaging_url_fragment": "EcpTextMessagingUrlFragment",
|
|
2025
|
+
"ecp_delivery_report_url_fragment": "EcpDeliveryReportUrlFragment",
|
|
2026
|
+
"ecp_retention_policy_tags_url_fragment": "EcpRetentionPolicyTagsUrlFragment",
|
|
2027
|
+
"ecp_publishing_url_fragment": "EcpPublishingUrlFragment",
|
|
2028
|
+
"external_ecp_url": "ExternalEcpUrl",
|
|
2029
|
+
"external_ecp_voicemail_url": "ExternalEcpVoicemailUrl",
|
|
2030
|
+
"external_ecp_email_subscriptions_url": "ExternalEcpEmailSubscriptionsUrl",
|
|
2031
|
+
"external_ecp_text_messaging_url": "ExternalEcpTextMessagingUrl",
|
|
2032
|
+
"external_ecp_delivery_report_url": "ExternalEcpDeliveryReportUrl",
|
|
2033
|
+
"external_ecp_retention_policy_tags_url": "ExternalEcpRetentionPolicyTagsUrl",
|
|
2034
|
+
"external_ecp_publishing_url": "ExternalEcpPublishingUrl",
|
|
2035
|
+
"external_ews_url": "ExternalEwsUrl",
|
|
2036
|
+
"external_oab_url": "ExternalOABUrl",
|
|
2037
|
+
"external_um_url": "ExternalUMUrl",
|
|
2038
|
+
"external_web_client_urls": "ExternalWebClientUrls",
|
|
2039
|
+
"cross_organization_sharing_enabled": "CrossOrganizationSharingEnabled",
|
|
2040
|
+
"alternate_mailboxes": "AlternateMailboxes",
|
|
2041
|
+
"cas_version": "CasVersion",
|
|
2042
|
+
"ews_supported_schemas": "EwsSupportedSchemas",
|
|
2043
|
+
"internal_pop3_connections": "InternalPop3Connections",
|
|
2044
|
+
"external_pop3_connections": "ExternalPop3Connections",
|
|
2045
|
+
"internal_imap4_connections": "InternalImap4Connections",
|
|
2046
|
+
"external_imap4_connections": "ExternalImap4Connections",
|
|
2047
|
+
"internal_smtp_connections": "InternalSmtpConnections",
|
|
2048
|
+
"external_smtp_connections": "ExternalSmtpConnections",
|
|
2049
|
+
"internal_server_exclusive_connect": "InternalServerExclusiveConnect",
|
|
2050
|
+
"external_server_exclusive_connect": "ExternalServerExclusiveConnect",
|
|
2051
|
+
"exchange_rpc_url": "ExchangeRpcUrl",
|
|
2052
|
+
"show_gal_as_default_view": "ShowGalAsDefaultView",
|
|
2053
|
+
"auto_discover_smtp_address": "AutoDiscoverSMTPAddress",
|
|
2054
|
+
"interop_external_ews_url": "InteropExternalEwsUrl",
|
|
2055
|
+
"external_ews_version": "ExternalEwsVersion",
|
|
2056
|
+
"interop_external_ews_version": "InteropExternalEwsVersion",
|
|
2057
|
+
"mobile_mailbox_policy_interop": "MobileMailboxPolicyInterop",
|
|
2058
|
+
"grouping_information": "GroupingInformation",
|
|
2059
|
+
"user_ms_online": "UserMSOnline",
|
|
2060
|
+
"mapi_http_enabled": "MapiHttpEnabled",
|
|
2061
|
+
}
|
|
2062
|
+
REVERSE_SETTINGS_MAP = {v: k for k, v in SETTINGS_MAP.items()}
|
|
2063
|
+
|
|
2064
|
+
error_code = CharField()
|
|
2065
|
+
error_message = CharField()
|
|
2066
|
+
redirect_address = CharField()
|
|
2067
|
+
redirect_url = CharField()
|
|
2068
|
+
user_settings_errors = DictionaryField()
|
|
2069
|
+
user_settings = DictionaryField()
|
|
2070
|
+
|
|
2071
|
+
@property
|
|
2072
|
+
def autodiscover_smtp_address(self):
|
|
2073
|
+
return self.user_settings.get("auto_discover_smtp_address")
|
|
2074
|
+
|
|
2075
|
+
@property
|
|
2076
|
+
def ews_url(self):
|
|
2077
|
+
return self.user_settings.get("external_ews_url")
|
|
2078
|
+
|
|
2079
|
+
@property
|
|
2080
|
+
def version(self):
|
|
2081
|
+
if not self.user_settings.get("ews_supported_schemas"):
|
|
2082
|
+
return None
|
|
2083
|
+
supported_schemas = [s.strip() for s in self.user_settings.get("ews_supported_schemas").split(",")]
|
|
2084
|
+
newest_supported_schema = sorted(supported_schemas, reverse=True)[0]
|
|
2085
|
+
|
|
2086
|
+
for version in Version.all_versions():
|
|
2087
|
+
if newest_supported_schema == version.api_version:
|
|
2088
|
+
return version
|
|
2089
|
+
raise ValueError(f"Unknown supported schemas: {supported_schemas}")
|
|
2090
|
+
|
|
2091
|
+
def raise_errors(self):
|
|
2092
|
+
if self.error_code == "InvalidUser":
|
|
2093
|
+
raise ErrorNonExistentMailbox(self.error_message)
|
|
2094
|
+
if self.error_code in (
|
|
2095
|
+
"InvalidDomain",
|
|
2096
|
+
"InvalidRequest",
|
|
2097
|
+
"InvalidSetting",
|
|
2098
|
+
"NotFederated",
|
|
2099
|
+
"SettingIsNotAvailable",
|
|
2100
|
+
):
|
|
2101
|
+
raise AutoDiscoverFailed(f"{self.error_code}: {self.error_message}")
|
|
2102
|
+
errors_to_report = {}
|
|
2103
|
+
for field_name, (error, message) in (self.user_settings_errors or {}).items():
|
|
2104
|
+
if error in ("InvalidSetting", "SettingIsNotAvailable") and field_name in self.SETTINGS_MAP:
|
|
2105
|
+
# Setting is not available for this user or is unknown to this server. Harmless.
|
|
2106
|
+
continue
|
|
2107
|
+
errors_to_report[field_name] = (error, message)
|
|
2108
|
+
if errors_to_report:
|
|
2109
|
+
raise AutoDiscoverFailed(f"User settings errors: {errors_to_report}")
|
|
2110
|
+
|
|
2111
|
+
@classmethod
|
|
2112
|
+
def parse_elem(cls, elem):
|
|
2113
|
+
# Possible ErrorCode values:
|
|
2114
|
+
# https://learn.microsoft.com/en-us/exchange/client-developer/web-service-reference/errorcode-soap
|
|
2115
|
+
error_code = get_xml_attr(elem, f"{{{ANS}}}ErrorCode")
|
|
2116
|
+
error_message = get_xml_attr(elem, f"{{{ANS}}}ErrorMessage")
|
|
2117
|
+
if error_code == "InternalServerError":
|
|
2118
|
+
return ErrorInternalServerError(error_message)
|
|
2119
|
+
if error_code == "ServerBusy":
|
|
2120
|
+
return ErrorServerBusy(error_message)
|
|
2121
|
+
if error_code == "NotFederated":
|
|
2122
|
+
return ErrorOrganizationNotFederated(error_message)
|
|
2123
|
+
return cls(error_code=error_code, error_message=error_message)
|
|
2124
|
+
|
|
2125
|
+
@classmethod
|
|
2126
|
+
def from_xml(cls, elem, account):
|
|
2127
|
+
res = cls.parse_elem(elem)
|
|
2128
|
+
if isinstance(res, Exception):
|
|
2129
|
+
raise res
|
|
2130
|
+
if res.error_code not in ("NoError", "RedirectAddress", "RedirectUrl"):
|
|
2131
|
+
return cls(error_code=res.error_code, error_message=res.error_message)
|
|
2132
|
+
|
|
2133
|
+
redirect_target = get_xml_attr(elem, f"{{{ANS}}}RedirectTarget")
|
|
2134
|
+
redirect_address = redirect_target if res.error_code == "RedirectAddress" else None
|
|
2135
|
+
redirect_url = redirect_target if res.error_code == "RedirectUrl" else None
|
|
2136
|
+
user_settings_errors = {}
|
|
2137
|
+
settings_errors_elem = elem.find(f"{{{ANS}}}UserSettingErrors")
|
|
2138
|
+
if settings_errors_elem is not None:
|
|
2139
|
+
for setting_error in settings_errors_elem:
|
|
2140
|
+
error_code = get_xml_attr(setting_error, f"{{{ANS}}}ErrorCode")
|
|
2141
|
+
error_message = get_xml_attr(setting_error, f"{{{ANS}}}ErrorMessage")
|
|
2142
|
+
name = get_xml_attr(setting_error, f"{{{ANS}}}SettingName")
|
|
2143
|
+
user_settings_errors[cls.REVERSE_SETTINGS_MAP[name]] = (error_code, error_message)
|
|
2144
|
+
user_settings = {}
|
|
2145
|
+
settings_elem = elem.find(f"{{{ANS}}}UserSettings")
|
|
2146
|
+
if settings_elem is not None:
|
|
2147
|
+
for setting in settings_elem:
|
|
2148
|
+
name = get_xml_attr(setting, f"{{{ANS}}}Name")
|
|
2149
|
+
value = get_xml_attr(setting, f"{{{ANS}}}Value")
|
|
2150
|
+
user_settings[cls.REVERSE_SETTINGS_MAP[name]] = value
|
|
2151
|
+
return cls(
|
|
2152
|
+
redirect_address=redirect_address,
|
|
2153
|
+
redirect_url=redirect_url,
|
|
2154
|
+
user_settings_errors=user_settings_errors,
|
|
2155
|
+
user_settings=user_settings,
|
|
2156
|
+
)
|
|
2157
|
+
|
|
2158
|
+
|
|
2159
|
+
class WithinDateRange(EWSElement):
|
|
2160
|
+
"""MSDN:
|
|
2161
|
+
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/withindaterange
|
|
2162
|
+
"""
|
|
2163
|
+
|
|
2164
|
+
ELEMENT_NAME = "DateRange"
|
|
2165
|
+
NAMESPACE = TNS
|
|
2166
|
+
|
|
2167
|
+
start_date_time = DateTimeField(field_uri="StartDateTime", is_required=True)
|
|
2168
|
+
end_date_time = DateTimeField(field_uri="EndDateTime", is_required=True)
|
|
2169
|
+
|
|
2170
|
+
|
|
2171
|
+
class WithinSizeRange(EWSElement):
|
|
2172
|
+
"""MSDN:
|
|
2173
|
+
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/withinsizerange
|
|
2174
|
+
"""
|
|
2175
|
+
|
|
2176
|
+
ELEMENT_NAME = "SizeRange"
|
|
2177
|
+
NAMESPACE = TNS
|
|
2178
|
+
|
|
2179
|
+
minimum_size = IntegerField(field_uri="MinimumSize", is_required=True)
|
|
2180
|
+
maximum_size = IntegerField(field_uri="MaximumSize", is_required=True)
|
|
2181
|
+
|
|
2182
|
+
|
|
2183
|
+
class Conditions(EWSElement):
|
|
2184
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/conditions"""
|
|
2185
|
+
|
|
2186
|
+
ELEMENT_NAME = "Conditions"
|
|
2187
|
+
NAMESPACE = TNS
|
|
2188
|
+
|
|
2189
|
+
categories = CharListField(field_uri="Categories")
|
|
2190
|
+
contains_body_strings = CharListField(field_uri="ContainsBodyStrings")
|
|
2191
|
+
contains_header_strings = CharListField(field_uri="ContainsHeaderStrings")
|
|
2192
|
+
contains_recipient_strings = CharListField(field_uri="ContainsRecipientStrings")
|
|
2193
|
+
contains_sender_strings = CharListField(field_uri="ContainsSenderStrings")
|
|
2194
|
+
contains_subject_or_body_strings = CharListField(field_uri="ContainsSubjectOrBodyStrings")
|
|
2195
|
+
contains_subject_strings = CharListField(field_uri="ContainsSubjectStrings")
|
|
2196
|
+
flagged_for_action = FlaggedForActionField(field_uri="FlaggedForAction")
|
|
2197
|
+
from_addresses = AddressListField(field_uri="FromAddresses")
|
|
2198
|
+
from_connected_accounts = CharListField(field_uri="FromConnectedAccounts")
|
|
2199
|
+
has_attachments = BooleanField(field_uri="HasAttachments")
|
|
2200
|
+
importance = ImportanceField(field_uri="Importance")
|
|
2201
|
+
is_approval_request = BooleanField(field_uri="IsApprovalRequest")
|
|
2202
|
+
is_automatic_forward = BooleanField(field_uri="IsAutomaticForward")
|
|
2203
|
+
is_automatic_reply = BooleanField(field_uri="IsAutomaticReply")
|
|
2204
|
+
is_encrypted = BooleanField(field_uri="IsEncrypted")
|
|
2205
|
+
is_meeting_request = BooleanField(field_uri="IsMeetingRequest")
|
|
2206
|
+
is_meeting_response = BooleanField(field_uri="IsMeetingResponse")
|
|
2207
|
+
is_ndr = BooleanField(field_uri="IsNDR")
|
|
2208
|
+
is_permission_controlled = BooleanField(field_uri="IsPermissionControlled")
|
|
2209
|
+
is_read_receipt = BooleanField(field_uri="IsReadReceipt")
|
|
2210
|
+
is_signed = BooleanField(field_uri="IsSigned")
|
|
2211
|
+
is_voicemail = BooleanField(field_uri="IsVoicemail")
|
|
2212
|
+
item_classes = CharListField(field_uri="ItemClasses")
|
|
2213
|
+
message_classifications = CharListField(field_uri="MessageClassifications")
|
|
2214
|
+
not_sent_to_me = BooleanField(field_uri="NotSentToMe")
|
|
2215
|
+
sent_cc_me = BooleanField(field_uri="SentCcMe")
|
|
2216
|
+
sent_only_to_me = BooleanField(field_uri="SentOnlyToMe")
|
|
2217
|
+
sent_to_addresses = AddressListField(field_uri="SentToAddresses")
|
|
2218
|
+
sent_to_me = BooleanField(field_uri="SentToMe")
|
|
2219
|
+
sent_to_or_cc_me = BooleanField(field_uri="SentToOrCcMe")
|
|
2220
|
+
sensitivity = SensitivityField(field_uri="Sensitivity")
|
|
2221
|
+
within_date_range = EWSElementField(value_cls=WithinDateRange, field_uri="WithinDateRange")
|
|
2222
|
+
within_size_range = EWSElementField(value_cls=WithinSizeRange, field_uri="WithinSizeRange")
|
|
2223
|
+
|
|
2224
|
+
|
|
2225
|
+
class Exceptions(Conditions):
|
|
2226
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/exceptions"""
|
|
2227
|
+
|
|
2228
|
+
ELEMENT_NAME = "Exceptions"
|
|
2229
|
+
NAMESPACE = TNS
|
|
2230
|
+
|
|
2231
|
+
|
|
2232
|
+
class CopyToFolder(EWSElement):
|
|
2233
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/copytofolder"""
|
|
2234
|
+
|
|
2235
|
+
ELEMENT_NAME = "CopyToFolder"
|
|
2236
|
+
|
|
2237
|
+
folder_id = EWSElementField(value_cls=FolderId)
|
|
2238
|
+
distinguished_folder_id = EWSElementField(value_cls=DistinguishedFolderId)
|
|
2239
|
+
|
|
2240
|
+
|
|
2241
|
+
class MoveToFolder(CopyToFolder):
|
|
2242
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/movetofolder"""
|
|
2243
|
+
|
|
2244
|
+
ELEMENT_NAME = "MoveToFolder"
|
|
2245
|
+
|
|
2246
|
+
|
|
2247
|
+
class Actions(EWSElement):
|
|
2248
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/actions"""
|
|
2249
|
+
|
|
2250
|
+
ELEMENT_NAME = "Actions"
|
|
2251
|
+
|
|
2252
|
+
assign_categories = CharListField(field_uri="AssignCategories")
|
|
2253
|
+
copy_to_folder = FolderActionField(value_cls=CopyToFolder)
|
|
2254
|
+
delete = BooleanField(field_uri="Delete")
|
|
2255
|
+
forward_as_attachment_to_recipients = AddressListField(field_uri="ForwardAsAttachmentToRecipients")
|
|
2256
|
+
forward_to_recipients = AddressListField(field_uri="ForwardToRecipients")
|
|
2257
|
+
mark_importance = ImportanceField(field_uri="MarkImportance")
|
|
2258
|
+
mark_as_read = BooleanField(field_uri="MarkAsRead")
|
|
2259
|
+
move_to_folder = FolderActionField(value_cls=MoveToFolder)
|
|
2260
|
+
permanent_delete = BooleanField(field_uri="PermanentDelete")
|
|
2261
|
+
redirect_to_recipients = AddressListField(field_uri="RedirectToRecipients")
|
|
2262
|
+
send_sms_alert_to_recipients = AddressListField(field_uri="SendSMSAlertToRecipients")
|
|
2263
|
+
server_reply_with_message = EWSElementField(value_cls=ItemId, field_uri="ServerReplyWithMessage")
|
|
2264
|
+
stop_processing_rules = BooleanField(field_uri="StopProcessingRules")
|
|
2265
|
+
|
|
2266
|
+
|
|
2267
|
+
class Rule(EWSElement):
|
|
2268
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/rule-ruletype"""
|
|
2269
|
+
|
|
2270
|
+
def __init__(self, **kwargs):
|
|
2271
|
+
"""Pick out optional 'account' kwarg, and pass the rest to the parent class.
|
|
2272
|
+
|
|
2273
|
+
:param kwargs:
|
|
2274
|
+
'account' is optional but allows calling 'send()' and 'delete()'
|
|
2275
|
+
"""
|
|
2276
|
+
from .account import Account
|
|
2277
|
+
|
|
2278
|
+
self.account = kwargs.pop("account", None)
|
|
2279
|
+
if self.account is not None and not isinstance(self.account, Account):
|
|
2280
|
+
raise InvalidTypeError("account", self.account, Account)
|
|
2281
|
+
super().__init__(**kwargs)
|
|
2282
|
+
|
|
2283
|
+
__slots__ = ("account",)
|
|
2284
|
+
|
|
2285
|
+
ELEMENT_NAME = "Rule"
|
|
2286
|
+
|
|
2287
|
+
id = CharField(field_uri="RuleId")
|
|
2288
|
+
display_name = CharField(field_uri="DisplayName", is_required=True)
|
|
2289
|
+
priority = IntegerField(field_uri="Priority", is_required=True)
|
|
2290
|
+
is_enabled = BooleanField(field_uri="IsEnabled")
|
|
2291
|
+
is_not_supported = BooleanField(field_uri="IsNotSupported")
|
|
2292
|
+
is_in_error = BooleanField(field_uri="IsInError")
|
|
2293
|
+
conditions = EWSElementField(value_cls=Conditions)
|
|
2294
|
+
exceptions = EWSElementField(value_cls=Exceptions)
|
|
2295
|
+
actions = EWSElementField(value_cls=Actions, is_required=True)
|
|
2296
|
+
|
|
2297
|
+
@classmethod
|
|
2298
|
+
def from_xml(cls, elem, account):
|
|
2299
|
+
res = super().from_xml(elem=elem, account=account)
|
|
2300
|
+
res.account = account
|
|
2301
|
+
return res
|
|
2302
|
+
|
|
2303
|
+
def save(self):
|
|
2304
|
+
if self.id is None:
|
|
2305
|
+
self.account.create_rule(self)
|
|
2306
|
+
else:
|
|
2307
|
+
self.account.set_rule(self)
|
|
2308
|
+
return self
|
|
2309
|
+
|
|
2310
|
+
def delete(self):
|
|
2311
|
+
if self.is_enabled is False:
|
|
2312
|
+
# Cannot delete a disabled rule - the server throws 'ErrorItemNotFound'. We need to enable it first.
|
|
2313
|
+
self.is_enabled = True
|
|
2314
|
+
# Make sure we can save the rule by wiping all possibly-misconfigured fields
|
|
2315
|
+
self.priority = 10**6
|
|
2316
|
+
self.conditions = None
|
|
2317
|
+
self.exceptions = None
|
|
2318
|
+
self.actions = Actions(stop_processing_rules=True)
|
|
2319
|
+
self.save()
|
|
2320
|
+
self.account.delete_rule(self)
|
|
2321
|
+
|
|
2322
|
+
|
|
2323
|
+
class InboxRules(EWSElement):
|
|
2324
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/inboxrules"""
|
|
2325
|
+
|
|
2326
|
+
ELEMENT_NAME = "InboxRules"
|
|
2327
|
+
NAMESPACE = MNS
|
|
2328
|
+
|
|
2329
|
+
rule = EWSElementListField(value_cls=Rule)
|
|
2330
|
+
|
|
2331
|
+
|
|
2332
|
+
class CreateRuleOperation(EWSElement):
|
|
2333
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/createruleoperation"""
|
|
2334
|
+
|
|
2335
|
+
ELEMENT_NAME = "CreateRuleOperation"
|
|
2336
|
+
|
|
2337
|
+
rule = EWSElementField(value_cls=Rule)
|
|
2338
|
+
|
|
2339
|
+
|
|
2340
|
+
class SetRuleOperation(EWSElement):
|
|
2341
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/setruleoperation"""
|
|
2342
|
+
|
|
2343
|
+
ELEMENT_NAME = "SetRuleOperation"
|
|
2344
|
+
|
|
2345
|
+
rule = EWSElementField(value_cls=Rule)
|
|
2346
|
+
|
|
2347
|
+
|
|
2348
|
+
class DeleteRuleOperation(EWSElement):
|
|
2349
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/deleteruleoperation"""
|
|
2350
|
+
|
|
2351
|
+
ELEMENT_NAME = "DeleteRuleOperation"
|
|
2352
|
+
|
|
2353
|
+
id = CharField(field_uri="RuleId")
|
|
2354
|
+
|
|
2355
|
+
|
|
2356
|
+
class Operations(EWSElement):
|
|
2357
|
+
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/operations"""
|
|
2358
|
+
|
|
2359
|
+
ELEMENT_NAME = "Operations"
|
|
2360
|
+
NAMESPACE = MNS
|
|
2361
|
+
|
|
2362
|
+
create_rule_operation = EWSElementField(value_cls=CreateRuleOperation)
|
|
2363
|
+
set_rule_operation = EWSElementField(value_cls=SetRuleOperation)
|
|
2364
|
+
delete_rule_operation = EWSElementField(value_cls=DeleteRuleOperation)
|