@backtomyfuture/exchange-cli-win32-x64 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/VCRUNTIME140_1.dll +0 -0
- package/bin/_internal/_asyncio.pyd +0 -0
- package/bin/_internal/_bz2.pyd +0 -0
- package/bin/_internal/_cffi_backend.cp312-win_amd64.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-win_amd64.pyd +0 -0
- package/bin/_internal/api-ms-win-core-console-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-core-datetime-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-core-debug-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-core-errorhandling-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-core-fibers-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-core-fibers-l1-1-1.dll +0 -0
- package/bin/_internal/api-ms-win-core-file-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-core-file-l1-2-0.dll +0 -0
- package/bin/_internal/api-ms-win-core-file-l2-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-core-handle-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-core-heap-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-core-interlocked-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-core-kernel32-legacy-l1-1-1.dll +0 -0
- package/bin/_internal/api-ms-win-core-libraryloader-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-core-localization-l1-2-0.dll +0 -0
- package/bin/_internal/api-ms-win-core-memory-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-core-namedpipe-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-core-processenvironment-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-core-processthreads-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-core-processthreads-l1-1-1.dll +0 -0
- package/bin/_internal/api-ms-win-core-profile-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-core-rtlsupport-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-core-string-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-core-synch-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-core-synch-l1-2-0.dll +0 -0
- package/bin/_internal/api-ms-win-core-sysinfo-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-core-sysinfo-l1-2-0.dll +0 -0
- package/bin/_internal/api-ms-win-core-timezone-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-core-util-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-crt-conio-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-crt-convert-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-crt-environment-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-crt-filesystem-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-crt-heap-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-crt-locale-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-crt-math-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-crt-process-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-crt-runtime-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-crt-stdio-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-crt-string-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-crt-time-l1-1-0.dll +0 -0
- package/bin/_internal/api-ms-win-crt-utility-l1-1-0.dll +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-win_amd64.pyd +0 -0
- package/bin/_internal/charset_normalizer/md.cp312-win_amd64.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 +1362 -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-win_amd64.pyd +0 -0
- package/bin/_internal/lxml/builder.cp312-win_amd64.pyd +0 -0
- package/bin/_internal/lxml/etree.cp312-win_amd64.pyd +0 -0
- package/bin/_internal/lxml/html/_difflib.cp312-win_amd64.pyd +0 -0
- package/bin/_internal/lxml/html/diff.cp312-win_amd64.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-win_amd64.pyd +0 -0
- package/bin/_internal/lxml/sax.cp312-win_amd64.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/ucrtbase.dll +0 -0
- package/bin/_internal/unicodedata.pyd +0 -0
- package/bin/exchange-cli.exe +0 -0
- package/package.json +20 -0
|
@@ -0,0 +1,983 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
import logging
|
|
3
|
+
from contextlib import suppress
|
|
4
|
+
from itertools import chain
|
|
5
|
+
|
|
6
|
+
from oauthlib.oauth2 import TokenExpiredError
|
|
7
|
+
|
|
8
|
+
from .. import errors
|
|
9
|
+
from ..attachments import AttachmentId
|
|
10
|
+
from ..credentials import IMPERSONATION, BaseOAuth2Credentials
|
|
11
|
+
from ..errors import (
|
|
12
|
+
ErrorBatchProcessingStopped,
|
|
13
|
+
ErrorCannotDeleteObject,
|
|
14
|
+
ErrorCannotDeleteTaskOccurrence,
|
|
15
|
+
ErrorCorruptData,
|
|
16
|
+
ErrorExceededConnectionCount,
|
|
17
|
+
ErrorIncorrectSchemaVersion,
|
|
18
|
+
ErrorInternalServerTransientError,
|
|
19
|
+
ErrorInvalidChangeKey,
|
|
20
|
+
ErrorInvalidIdMalformed,
|
|
21
|
+
ErrorInvalidRequest,
|
|
22
|
+
ErrorInvalidSchemaVersionForMailboxVersion,
|
|
23
|
+
ErrorInvalidServerVersion,
|
|
24
|
+
ErrorItemCorrupt,
|
|
25
|
+
ErrorItemNotFound,
|
|
26
|
+
ErrorItemSave,
|
|
27
|
+
ErrorMailRecipientNotFound,
|
|
28
|
+
ErrorMessageSizeExceeded,
|
|
29
|
+
ErrorMimeContentConversionFailed,
|
|
30
|
+
ErrorRecurrenceHasNoOccurrence,
|
|
31
|
+
ErrorServerBusy,
|
|
32
|
+
ErrorTimeoutExpired,
|
|
33
|
+
ErrorTooManyObjectsOpened,
|
|
34
|
+
EWSWarning,
|
|
35
|
+
InvalidTypeError,
|
|
36
|
+
MalformedResponseError,
|
|
37
|
+
SessionPoolMinSizeReached,
|
|
38
|
+
SOAPError,
|
|
39
|
+
TransportError,
|
|
40
|
+
)
|
|
41
|
+
from ..folders import BaseFolder, Folder, RootOfHierarchy
|
|
42
|
+
from ..items import BaseItem
|
|
43
|
+
from ..properties import BaseItemId, ExceptionFieldURI, ExtendedFieldURI, FieldURI, FolderId, IndexedFieldURI, ItemId
|
|
44
|
+
from ..transport import DEFAULT_ENCODING
|
|
45
|
+
from ..util import (
|
|
46
|
+
ENS,
|
|
47
|
+
MNS,
|
|
48
|
+
SOAPNS,
|
|
49
|
+
TNS,
|
|
50
|
+
DummyResponse,
|
|
51
|
+
ParseError,
|
|
52
|
+
add_xml_child,
|
|
53
|
+
chunkify,
|
|
54
|
+
create_element,
|
|
55
|
+
get_xml_attr,
|
|
56
|
+
ns_translation,
|
|
57
|
+
post_ratelimited,
|
|
58
|
+
set_xml_value,
|
|
59
|
+
to_xml,
|
|
60
|
+
xml_to_str,
|
|
61
|
+
)
|
|
62
|
+
from ..version import SupportedVersionClassMixIn, Version
|
|
63
|
+
|
|
64
|
+
log = logging.getLogger(__name__)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class EWSService(SupportedVersionClassMixIn, metaclass=abc.ABCMeta):
|
|
68
|
+
"""Base class for all EWS services."""
|
|
69
|
+
|
|
70
|
+
CHUNK_SIZE = 100 # A default chunk size for all services. This is the number of items we send in a single request
|
|
71
|
+
|
|
72
|
+
SERVICE_NAME = None # The name of the SOAP service
|
|
73
|
+
element_container_name = None # The name of the XML element wrapping the collection of returned items
|
|
74
|
+
returns_elements = True # If False, the service does not return response elements, just the ResponseCode status
|
|
75
|
+
# Return exception instance instead of raising exceptions for the following errors when contained in an element
|
|
76
|
+
ERRORS_TO_CATCH_IN_RESPONSE = (
|
|
77
|
+
EWSWarning,
|
|
78
|
+
ErrorCannotDeleteObject,
|
|
79
|
+
ErrorInvalidChangeKey,
|
|
80
|
+
ErrorItemNotFound,
|
|
81
|
+
ErrorItemSave,
|
|
82
|
+
ErrorInvalidIdMalformed,
|
|
83
|
+
ErrorMessageSizeExceeded,
|
|
84
|
+
ErrorCannotDeleteTaskOccurrence,
|
|
85
|
+
ErrorMimeContentConversionFailed,
|
|
86
|
+
ErrorRecurrenceHasNoOccurrence,
|
|
87
|
+
ErrorCorruptData,
|
|
88
|
+
ErrorItemCorrupt,
|
|
89
|
+
ErrorMailRecipientNotFound,
|
|
90
|
+
)
|
|
91
|
+
# Similarly, define the warnings we want to return un-raised
|
|
92
|
+
WARNINGS_TO_CATCH_IN_RESPONSE = ErrorBatchProcessingStopped
|
|
93
|
+
# Define the warnings we want to ignore, to let response processing proceed
|
|
94
|
+
WARNINGS_TO_IGNORE_IN_RESPONSE = ()
|
|
95
|
+
# The exception type to raise when all attempted API versions failed
|
|
96
|
+
NO_VALID_SERVER_VERSIONS = ErrorInvalidServerVersion
|
|
97
|
+
|
|
98
|
+
NS_MAP = {k: v for k, v in ns_translation.items() if k in ("s", "m", "t")}
|
|
99
|
+
|
|
100
|
+
def __init__(self, protocol, chunk_size=None, timeout=None):
|
|
101
|
+
self.chunk_size = chunk_size or self.CHUNK_SIZE
|
|
102
|
+
if not isinstance(self.chunk_size, int):
|
|
103
|
+
raise InvalidTypeError("chunk_size", chunk_size, int)
|
|
104
|
+
if self.chunk_size < 1:
|
|
105
|
+
raise ValueError(f"'chunk_size' {self.chunk_size} must be a positive number")
|
|
106
|
+
if self.supported_from and protocol.version.build < self.supported_from:
|
|
107
|
+
raise NotImplementedError(
|
|
108
|
+
f"Service {self.SERVICE_NAME!r} only supports server versions from {self.supported_from or '*'} to "
|
|
109
|
+
f"{self.deprecated_from or '*'} (server has {protocol.version})"
|
|
110
|
+
)
|
|
111
|
+
self.protocol = protocol
|
|
112
|
+
# Allow a service to override the default protocol timeout. Useful for streaming services
|
|
113
|
+
self.timeout = timeout
|
|
114
|
+
# Controls whether the HTTP request should be streaming or fetch everything at once
|
|
115
|
+
self.streaming = False
|
|
116
|
+
# Streaming connection variables
|
|
117
|
+
self._streaming_session = None
|
|
118
|
+
self._streaming_response = None
|
|
119
|
+
|
|
120
|
+
def __del__(self):
|
|
121
|
+
# pylint: disable=bare-except
|
|
122
|
+
try:
|
|
123
|
+
if self.streaming:
|
|
124
|
+
# Make sure to clean up lingering resources
|
|
125
|
+
self.stop_streaming()
|
|
126
|
+
except Exception: # nosec
|
|
127
|
+
# __del__ should never fail
|
|
128
|
+
pass
|
|
129
|
+
|
|
130
|
+
# The following two methods are the minimum required to be implemented by subclasses, but the name and number of
|
|
131
|
+
# kwargs differs between services. Therefore, we cannot make these methods abstract.
|
|
132
|
+
|
|
133
|
+
# @abc.abstractmethod
|
|
134
|
+
# def call(self, **kwargs):
|
|
135
|
+
# """Defines the arguments required by the service. Arguments are basic Python types or EWSElement objects.
|
|
136
|
+
# Returns either XML objects or EWSElement objects.
|
|
137
|
+
# """"
|
|
138
|
+
# pass
|
|
139
|
+
|
|
140
|
+
# @abc.abstractmethod
|
|
141
|
+
# def get_payload(self, **kwargs):
|
|
142
|
+
# """Using the arguments from .call(), return the payload expected by the service, as an XML object. The XML
|
|
143
|
+
# object should consist of a SERVICE_NAME element and everything within that.
|
|
144
|
+
# """
|
|
145
|
+
# pass
|
|
146
|
+
|
|
147
|
+
def get(self, expect_result=True, **kwargs):
|
|
148
|
+
"""Like .call(), but expects exactly one result from the server, or zero when expect_result=False, or either
|
|
149
|
+
zero or one when expect_result=None. Returns either one object or None.
|
|
150
|
+
|
|
151
|
+
:param expect_result: None, True, or False
|
|
152
|
+
:param kwargs: Same as arguments for .call()
|
|
153
|
+
:return: Same as .call(), but returns either None or exactly one item
|
|
154
|
+
"""
|
|
155
|
+
res = list(self.call(**kwargs))
|
|
156
|
+
# Raise any errors
|
|
157
|
+
for r in res:
|
|
158
|
+
if isinstance(r, Exception):
|
|
159
|
+
raise r
|
|
160
|
+
if expect_result is None and not res:
|
|
161
|
+
# Allow empty result
|
|
162
|
+
return None
|
|
163
|
+
if expect_result is False:
|
|
164
|
+
if res:
|
|
165
|
+
raise ValueError(f"Expected result length 0, but got {res}")
|
|
166
|
+
return None
|
|
167
|
+
if len(res) != 1:
|
|
168
|
+
raise ValueError(f"Expected result length 1, but got {res}")
|
|
169
|
+
return res[0]
|
|
170
|
+
|
|
171
|
+
def parse(self, xml):
|
|
172
|
+
"""Used mostly for testing, when we want to parse static XML data."""
|
|
173
|
+
resp = DummyResponse(content=xml, streaming=self.streaming)
|
|
174
|
+
_, body = self._get_soap_parts(response=resp)
|
|
175
|
+
return self._elems_to_objs(self._get_elements_in_response(response=self._get_soap_messages(body=body)))
|
|
176
|
+
|
|
177
|
+
def wrap(self, content, api_version=None):
|
|
178
|
+
"""Generate the necessary boilerplate XML for a raw SOAP request. The XML is specific to the server version.
|
|
179
|
+
ExchangeImpersonation allows to act as the user we want to impersonate.
|
|
180
|
+
|
|
181
|
+
RequestServerVersion element on MSDN:
|
|
182
|
+
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/requestserverversion
|
|
183
|
+
|
|
184
|
+
ExchangeImpersonation element on MSDN:
|
|
185
|
+
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/exchangeimpersonation
|
|
186
|
+
|
|
187
|
+
TimeZoneContent element on MSDN:
|
|
188
|
+
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/timezonecontext
|
|
189
|
+
|
|
190
|
+
:param content:
|
|
191
|
+
:param api_version:
|
|
192
|
+
"""
|
|
193
|
+
envelope = create_element("s:Envelope", nsmap=self.NS_MAP)
|
|
194
|
+
header = create_element("s:Header")
|
|
195
|
+
if api_version:
|
|
196
|
+
request_server_version = create_element("t:RequestServerVersion", attrs=dict(Version=api_version))
|
|
197
|
+
header.append(request_server_version)
|
|
198
|
+
identity = self._account_to_impersonate
|
|
199
|
+
if identity:
|
|
200
|
+
add_xml_child(header, "t:ExchangeImpersonation", identity)
|
|
201
|
+
timezone = self._timezone
|
|
202
|
+
if timezone:
|
|
203
|
+
timezone_context = create_element("t:TimeZoneContext")
|
|
204
|
+
timezone_definition = create_element("t:TimeZoneDefinition", attrs=dict(Id=timezone.ms_id))
|
|
205
|
+
timezone_context.append(timezone_definition)
|
|
206
|
+
header.append(timezone_context)
|
|
207
|
+
if len(header):
|
|
208
|
+
envelope.append(header)
|
|
209
|
+
body = create_element("s:Body")
|
|
210
|
+
body.append(content)
|
|
211
|
+
envelope.append(body)
|
|
212
|
+
return xml_to_str(envelope, encoding=DEFAULT_ENCODING, xml_declaration=True)
|
|
213
|
+
|
|
214
|
+
def _elems_to_objs(self, elems):
|
|
215
|
+
"""Takes a generator of XML elements and exceptions. Returns the equivalent Python objects (or exceptions)."""
|
|
216
|
+
for elem in elems:
|
|
217
|
+
# Allow None here. Some services don't return an ID if the target folder is outside the mailbox.
|
|
218
|
+
if isinstance(elem, (Exception, type(None))):
|
|
219
|
+
yield elem
|
|
220
|
+
continue
|
|
221
|
+
yield self._elem_to_obj(elem)
|
|
222
|
+
|
|
223
|
+
def _elem_to_obj(self, elem):
|
|
224
|
+
"""Convert a single XML element to a single Python object"""
|
|
225
|
+
if not self.returns_elements:
|
|
226
|
+
raise RuntimeError("Incorrect call to method when 'returns_elements' is False")
|
|
227
|
+
raise NotImplementedError()
|
|
228
|
+
|
|
229
|
+
@property
|
|
230
|
+
def _version_hint(self):
|
|
231
|
+
# We may be here due to version guessing in Protocol.version, so we can't use the self.protocol.version property
|
|
232
|
+
return self.protocol.config.version
|
|
233
|
+
|
|
234
|
+
@_version_hint.setter
|
|
235
|
+
def _version_hint(self, value):
|
|
236
|
+
self.protocol.config.version = value
|
|
237
|
+
|
|
238
|
+
def _extra_headers(self):
|
|
239
|
+
headers = {}
|
|
240
|
+
identity = self._account_to_impersonate
|
|
241
|
+
if identity and identity.primary_smtp_address:
|
|
242
|
+
# See
|
|
243
|
+
# https://blogs.msdn.microsoft.com/webdav_101/2015/05/11/best-practices-ews-authentication-and-access-issues/
|
|
244
|
+
headers["X-AnchorMailbox"] = identity.primary_smtp_address
|
|
245
|
+
return headers
|
|
246
|
+
|
|
247
|
+
@property
|
|
248
|
+
def _account_to_impersonate(self):
|
|
249
|
+
if self.protocol and isinstance(self.protocol.credentials, BaseOAuth2Credentials):
|
|
250
|
+
return self.protocol.credentials.identity
|
|
251
|
+
return None
|
|
252
|
+
|
|
253
|
+
@property
|
|
254
|
+
def _timezone(self):
|
|
255
|
+
return None
|
|
256
|
+
|
|
257
|
+
def _response_generator(self, payload):
|
|
258
|
+
"""Send the payload to the server, and return the response.
|
|
259
|
+
|
|
260
|
+
:param payload: payload as an XML object
|
|
261
|
+
:return: the response, as XML objects
|
|
262
|
+
"""
|
|
263
|
+
response = self._get_response_xml(payload=payload)
|
|
264
|
+
return self._get_elements_in_response(response=response)
|
|
265
|
+
|
|
266
|
+
def _chunked_get_elements(self, payload_func, items, **kwargs):
|
|
267
|
+
"""Yield elements in a response. Like ._get_elements(), but chop items into suitable chunks and send multiple
|
|
268
|
+
requests.
|
|
269
|
+
|
|
270
|
+
:param payload_func: A reference to .payload()
|
|
271
|
+
:param items: An iterable of items (messages, folders, etc.) to process
|
|
272
|
+
:param kwargs: Same as arguments for .call(), except for the 'items' argument
|
|
273
|
+
:return: Same as ._get_elements()
|
|
274
|
+
"""
|
|
275
|
+
# If the input for a service is a QuerySet, it can be difficult to remove exceptions before now
|
|
276
|
+
filtered_items = filter(lambda item: not isinstance(item, Exception), items)
|
|
277
|
+
for i, chunk in enumerate(chunkify(filtered_items, self.chunk_size), start=1):
|
|
278
|
+
log.debug("Processing chunk %s containing %s items", i, len(chunk))
|
|
279
|
+
yield from self._get_elements(payload=payload_func(chunk, **kwargs))
|
|
280
|
+
|
|
281
|
+
def stop_streaming(self):
|
|
282
|
+
if not self.streaming:
|
|
283
|
+
raise RuntimeError("Attempt to stop a non-streaming service")
|
|
284
|
+
if self._streaming_response:
|
|
285
|
+
self._streaming_response.close() # Release memory
|
|
286
|
+
self._streaming_response = None
|
|
287
|
+
if self._streaming_session:
|
|
288
|
+
self.protocol.release_session(self._streaming_session)
|
|
289
|
+
self._streaming_session = None
|
|
290
|
+
|
|
291
|
+
def _get_elements(self, payload):
|
|
292
|
+
"""Send the payload to be sent and parsed. Handles and re-raise exceptions that are not meant to be returned
|
|
293
|
+
to the caller as exception objects. Retry the request according to the retry policy.
|
|
294
|
+
"""
|
|
295
|
+
wait = self.protocol.RETRY_WAIT
|
|
296
|
+
while True:
|
|
297
|
+
try:
|
|
298
|
+
# Create a generator over the response elements so exceptions in response elements are also raised
|
|
299
|
+
# here and can be handled.
|
|
300
|
+
yield from self._response_generator(payload=payload)
|
|
301
|
+
# TODO: Restore session pool size on succeeding request?
|
|
302
|
+
return
|
|
303
|
+
except TokenExpiredError:
|
|
304
|
+
# Retry immediately
|
|
305
|
+
continue
|
|
306
|
+
except ErrorServerBusy as e:
|
|
307
|
+
if not e.back_off:
|
|
308
|
+
e.back_off = wait
|
|
309
|
+
self._handle_backoff(e)
|
|
310
|
+
except ErrorExceededConnectionCount as e:
|
|
311
|
+
# ErrorExceededConnectionCount indicates that the connecting user has too many open TCP connections to
|
|
312
|
+
# the server. Decrease our session pool size and retry immediately.
|
|
313
|
+
try:
|
|
314
|
+
self.protocol.decrease_poolsize()
|
|
315
|
+
continue
|
|
316
|
+
except SessionPoolMinSizeReached:
|
|
317
|
+
# We're already as low as we can go. Let the user handle this.
|
|
318
|
+
raise e
|
|
319
|
+
except ErrorTimeoutExpired as e:
|
|
320
|
+
# ErrorTimeoutExpired can be caused by a busy server, or by an overly large request. If it's the latter,
|
|
321
|
+
# we don't want to continue hammering the server with this request indefinitely. Instead, lower the
|
|
322
|
+
# connection count, if possible, and retry the request.
|
|
323
|
+
if self.protocol.session_pool_size <= 1:
|
|
324
|
+
# We're already as low as we can go. We can no longer use the session count to put less load
|
|
325
|
+
# on the server. If this is a chunked request we could lower the chunk size, but we don't have a
|
|
326
|
+
# way of doing that from this part of the code yet. Let the user handle this.
|
|
327
|
+
raise e
|
|
328
|
+
self._handle_backoff(ErrorServerBusy(f"Reraised from {e.__class__.__name__}({e})", back_off=wait))
|
|
329
|
+
except (ErrorTooManyObjectsOpened, ErrorInternalServerTransientError) as e:
|
|
330
|
+
# ErrorTooManyObjectsOpened means there are too many connections to the Exchange database. This is very
|
|
331
|
+
# often a symptom of sending too many requests.
|
|
332
|
+
self._handle_backoff(ErrorServerBusy(f"Reraised from {e.__class__.__name__}({e})", back_off=wait))
|
|
333
|
+
finally:
|
|
334
|
+
wait *= 2 # Increase delay for every retry
|
|
335
|
+
if self.streaming:
|
|
336
|
+
self.stop_streaming()
|
|
337
|
+
|
|
338
|
+
def _handle_response_cookies(self, session):
|
|
339
|
+
"""Code to react on response cookies"""
|
|
340
|
+
|
|
341
|
+
def _get_response(self, payload, api_version):
|
|
342
|
+
"""Send the actual HTTP request and get the response."""
|
|
343
|
+
if self.streaming:
|
|
344
|
+
# Make sure to clean up lingering resources
|
|
345
|
+
self.stop_streaming()
|
|
346
|
+
session = self.protocol.get_session()
|
|
347
|
+
r, session = post_ratelimited(
|
|
348
|
+
protocol=self.protocol,
|
|
349
|
+
session=session,
|
|
350
|
+
url=self.protocol.service_endpoint,
|
|
351
|
+
headers=self._extra_headers(),
|
|
352
|
+
data=self.wrap(
|
|
353
|
+
content=payload,
|
|
354
|
+
api_version=api_version,
|
|
355
|
+
),
|
|
356
|
+
stream=self.streaming,
|
|
357
|
+
timeout=self.timeout or self.protocol.TIMEOUT,
|
|
358
|
+
)
|
|
359
|
+
self._handle_response_cookies(session)
|
|
360
|
+
if self.streaming:
|
|
361
|
+
# We con only release the session when we have fully consumed the response. Save session and response
|
|
362
|
+
# objects for later.
|
|
363
|
+
self._streaming_session, self._streaming_response = session, r
|
|
364
|
+
else:
|
|
365
|
+
self.protocol.release_session(session)
|
|
366
|
+
return r
|
|
367
|
+
|
|
368
|
+
@classmethod
|
|
369
|
+
def supported_api_versions(cls):
|
|
370
|
+
"""Return API versions supported by the service, sorted from newest to oldest"""
|
|
371
|
+
return sorted({v.api_version for v in Version.all_versions() if cls.supports_version(v)}, reverse=True)
|
|
372
|
+
|
|
373
|
+
def _api_versions_to_try(self):
|
|
374
|
+
# Put the hint first in the list, and then all other versions except the hint, from newest to oldest
|
|
375
|
+
return (self._version_hint.api_version,) + tuple(
|
|
376
|
+
v for v in self.supported_api_versions() if v != self._version_hint.api_version
|
|
377
|
+
)
|
|
378
|
+
|
|
379
|
+
def _get_response_xml(self, payload):
|
|
380
|
+
"""Send the payload to the server and return relevant elements from the result. Several things happen here:
|
|
381
|
+
* Wraps the payload is wrapped in SOAP headers and sends to the server
|
|
382
|
+
* Negotiates the Exchange API version and stores it in the protocol object
|
|
383
|
+
* Handles connection errors and possibly re-raises them as ErrorServerBusy
|
|
384
|
+
* Raises SOAP errors
|
|
385
|
+
* Raises EWS errors or passes them on to the caller
|
|
386
|
+
|
|
387
|
+
:param payload: The request payload, as an XML object
|
|
388
|
+
:return: A generator of XML objects or None if the service does not return a result
|
|
389
|
+
"""
|
|
390
|
+
# Microsoft really doesn't want to make our lives easy. The server may report one version in our initial version
|
|
391
|
+
# guessing tango, but then the server may decide that any arbitrary legacy backend server may actually process
|
|
392
|
+
# the request for an account. Prepare to handle version-related errors and set the server version per-account.
|
|
393
|
+
log.debug("Calling service %s", self.SERVICE_NAME)
|
|
394
|
+
for api_version in self._api_versions_to_try():
|
|
395
|
+
log.debug("Trying API version %s", api_version)
|
|
396
|
+
r = self._get_response(payload=payload, api_version=api_version)
|
|
397
|
+
if self.streaming:
|
|
398
|
+
# Let 'requests' decode raw data automatically
|
|
399
|
+
r.raw.decode_content = True
|
|
400
|
+
try:
|
|
401
|
+
header, body = self._get_soap_parts(response=r)
|
|
402
|
+
except Exception:
|
|
403
|
+
r.close() # Release memory
|
|
404
|
+
raise
|
|
405
|
+
# The body may contain error messages from Exchange, but we still want to collect version info
|
|
406
|
+
if header is not None:
|
|
407
|
+
self._update_api_version(api_version=api_version, header=header)
|
|
408
|
+
try:
|
|
409
|
+
return self._get_soap_messages(body=body)
|
|
410
|
+
except (
|
|
411
|
+
ErrorInvalidServerVersion,
|
|
412
|
+
ErrorIncorrectSchemaVersion,
|
|
413
|
+
ErrorInvalidRequest,
|
|
414
|
+
ErrorInvalidSchemaVersionForMailboxVersion,
|
|
415
|
+
):
|
|
416
|
+
# The guessed server version is wrong. Try the next version
|
|
417
|
+
log.debug("API version %s was invalid", api_version)
|
|
418
|
+
continue
|
|
419
|
+
finally:
|
|
420
|
+
if not self.streaming:
|
|
421
|
+
# In streaming mode, we may not have accessed the raw stream yet. Caller must handle this.
|
|
422
|
+
r.close() # Release memory
|
|
423
|
+
|
|
424
|
+
raise self.NO_VALID_SERVER_VERSIONS(f"Tried versions {self._api_versions_to_try()} but all were invalid")
|
|
425
|
+
|
|
426
|
+
def _handle_backoff(self, e):
|
|
427
|
+
"""Take a request from the server to back off and checks the retry policy for what to do. Re-raise the
|
|
428
|
+
exception if conditions are not met.
|
|
429
|
+
|
|
430
|
+
:param e: An ErrorServerBusy instance
|
|
431
|
+
:return:
|
|
432
|
+
"""
|
|
433
|
+
log.debug("Got ErrorServerBusy (back off %s seconds)", e.back_off)
|
|
434
|
+
# ErrorServerBusy is very often a symptom of sending too many requests. Scale back connections if possible.
|
|
435
|
+
with suppress(SessionPoolMinSizeReached):
|
|
436
|
+
self.protocol.decrease_poolsize()
|
|
437
|
+
if self.protocol.retry_policy.fail_fast:
|
|
438
|
+
raise e
|
|
439
|
+
self.protocol.retry_policy.back_off(e.back_off)
|
|
440
|
+
# We'll warn about this later if we actually need to sleep
|
|
441
|
+
|
|
442
|
+
def _update_api_version(self, api_version, header):
|
|
443
|
+
"""Parse the server version contained in SOAP headers and update the version hint stored by the caller, if
|
|
444
|
+
necessary.
|
|
445
|
+
"""
|
|
446
|
+
try:
|
|
447
|
+
head_version = Version.from_soap_header(requested_api_version=api_version, header=header)
|
|
448
|
+
except TransportError as te:
|
|
449
|
+
log.debug("Failed to update version info (%s)", te)
|
|
450
|
+
return
|
|
451
|
+
if self._version_hint == head_version:
|
|
452
|
+
# Nothing to do
|
|
453
|
+
return
|
|
454
|
+
log.debug("Found new version (%s -> %s)", self._version_hint, head_version)
|
|
455
|
+
# The api_version that worked was different from our hint, or we never got a build version. Store the working
|
|
456
|
+
# version.
|
|
457
|
+
self._version_hint = head_version
|
|
458
|
+
|
|
459
|
+
@classmethod
|
|
460
|
+
def _response_tag(cls):
|
|
461
|
+
"""Return the name of the element containing the service response."""
|
|
462
|
+
return f"{{{MNS}}}{cls.SERVICE_NAME}Response"
|
|
463
|
+
|
|
464
|
+
@staticmethod
|
|
465
|
+
def _response_messages_tag():
|
|
466
|
+
"""Return the name of the element containing service response messages."""
|
|
467
|
+
return f"{{{MNS}}}ResponseMessages"
|
|
468
|
+
|
|
469
|
+
@classmethod
|
|
470
|
+
def _response_message_tag(cls):
|
|
471
|
+
"""Return the name of the element of a single response message."""
|
|
472
|
+
return f"{{{MNS}}}{cls.SERVICE_NAME}ResponseMessage"
|
|
473
|
+
|
|
474
|
+
@classmethod
|
|
475
|
+
def _get_soap_parts(cls, response):
|
|
476
|
+
"""Split the SOAP response into its headers and body elements."""
|
|
477
|
+
try:
|
|
478
|
+
root = to_xml(response.iter_content())
|
|
479
|
+
except ParseError as e:
|
|
480
|
+
raise SOAPError(f"Bad SOAP response: {e}")
|
|
481
|
+
header = root.find(f"{{{SOAPNS}}}Header")
|
|
482
|
+
if header is None:
|
|
483
|
+
# This is normal when the response contains SOAP-level errors
|
|
484
|
+
log.debug("No header in XML response")
|
|
485
|
+
body = root.find(f"{{{SOAPNS}}}Body")
|
|
486
|
+
if body is None:
|
|
487
|
+
raise MalformedResponseError("No Body element in SOAP response")
|
|
488
|
+
return header, body
|
|
489
|
+
|
|
490
|
+
def _get_soap_messages(self, body):
|
|
491
|
+
"""Return the elements in the response containing the response messages. Raises any SOAP exceptions."""
|
|
492
|
+
response = body.find(self._response_tag())
|
|
493
|
+
if response is None:
|
|
494
|
+
fault = body.find(f"{{{SOAPNS}}}Fault")
|
|
495
|
+
if fault is None:
|
|
496
|
+
raise SOAPError(f"Unknown SOAP response (expected {self._response_tag()} or Fault): {xml_to_str(body)}")
|
|
497
|
+
self._raise_soap_errors(fault=fault) # Will throw SOAPError or custom EWS error
|
|
498
|
+
response_messages = response.find(self._response_messages_tag())
|
|
499
|
+
if response_messages is None:
|
|
500
|
+
# Result isn't delivered in a list of FooResponseMessages, but directly in the FooResponse. Consumers expect
|
|
501
|
+
# a list, so return a list
|
|
502
|
+
return [response]
|
|
503
|
+
return response_messages.findall(self._response_message_tag())
|
|
504
|
+
|
|
505
|
+
@classmethod
|
|
506
|
+
def _raise_soap_errors(cls, fault):
|
|
507
|
+
"""Parse error messages contained in SOAP headers and raise as exceptions defined in this package."""
|
|
508
|
+
# Fault: See http://www.w3.org/TR/2000/NOTE-SOAP-20000508/#_Toc478383507
|
|
509
|
+
fault_code = get_xml_attr(fault, "faultcode")
|
|
510
|
+
fault_string = get_xml_attr(fault, "faultstring")
|
|
511
|
+
fault_actor = get_xml_attr(fault, "faultactor")
|
|
512
|
+
detail = fault.find("detail")
|
|
513
|
+
if detail is not None:
|
|
514
|
+
code = get_xml_attr(detail, f"{{{ENS}}}ResponseCode")
|
|
515
|
+
if code:
|
|
516
|
+
code = code.strip()
|
|
517
|
+
msg = get_xml_attr(detail, f"{{{ENS}}}Message")
|
|
518
|
+
if msg:
|
|
519
|
+
msg = msg.strip()
|
|
520
|
+
msg_xml = detail.find(f"{{{TNS}}}MessageXml") # Crazy. Here, it's in the TNS namespace
|
|
521
|
+
if code == "ErrorServerBusy":
|
|
522
|
+
back_off = None
|
|
523
|
+
with suppress(TypeError, AttributeError):
|
|
524
|
+
value = msg_xml.find(f"{{{TNS}}}Value")
|
|
525
|
+
if value.get("Name") == "BackOffMilliseconds":
|
|
526
|
+
back_off = int(value.text) / 1000.0 # Convert to seconds
|
|
527
|
+
raise ErrorServerBusy(msg, back_off=back_off)
|
|
528
|
+
if code == "ErrorSchemaValidation" and msg_xml is not None:
|
|
529
|
+
line_number = get_xml_attr(msg_xml, f"{{{TNS}}}LineNumber")
|
|
530
|
+
line_position = get_xml_attr(msg_xml, f"{{{TNS}}}LinePosition")
|
|
531
|
+
violation = get_xml_attr(msg_xml, f"{{{TNS}}}Violation")
|
|
532
|
+
if violation:
|
|
533
|
+
msg = f"{msg} {violation}"
|
|
534
|
+
if line_number or line_position:
|
|
535
|
+
msg = f"{msg} (line: {line_number} position: {line_position})"
|
|
536
|
+
try:
|
|
537
|
+
raise vars(errors)[code](msg)
|
|
538
|
+
except KeyError:
|
|
539
|
+
detail = f"{cls.SERVICE_NAME}: code: {code} msg: {msg} ({xml_to_str(detail)})"
|
|
540
|
+
with suppress(KeyError):
|
|
541
|
+
raise vars(errors)[fault_code](fault_string)
|
|
542
|
+
raise SOAPError(f"SOAP error code: {fault_code} string: {fault_string} actor: {fault_actor} detail: {detail}")
|
|
543
|
+
|
|
544
|
+
def _get_element_container(self, message, name=None):
|
|
545
|
+
"""Return the XML element in a response element that contains the elements we want the service to return. For
|
|
546
|
+
example, in a GetFolder response, 'message' is the GetFolderResponseMessage element, and we return the 'Folders'
|
|
547
|
+
element:
|
|
548
|
+
|
|
549
|
+
<m:GetFolderResponseMessage ResponseClass="Success">
|
|
550
|
+
<m:ResponseCode>NoError</m:ResponseCode>
|
|
551
|
+
<m:Folders>
|
|
552
|
+
<t:Folder>
|
|
553
|
+
<t:FolderId Id="AQApA=" ChangeKey="AQAAAB" />
|
|
554
|
+
[...]
|
|
555
|
+
</t:Folder>
|
|
556
|
+
</m:Folders>
|
|
557
|
+
</m:GetFolderResponseMessage>
|
|
558
|
+
|
|
559
|
+
Some service responses don't have a containing element for the returned elements ('name' is None). In
|
|
560
|
+
that case, we return the 'SomeServiceResponseMessage' element.
|
|
561
|
+
|
|
562
|
+
If the response contains a warning or an error message, we raise the relevant exception, unless the error class
|
|
563
|
+
is contained in WARNINGS_TO_CATCH_IN_RESPONSE or ERRORS_TO_CATCH_IN_RESPONSE, in which case we return the
|
|
564
|
+
exception instance.
|
|
565
|
+
"""
|
|
566
|
+
# ResponseClass is an XML attribute of various SomeServiceResponseMessage elements: Possible values are:
|
|
567
|
+
# Success, Warning, Error. See e.g.
|
|
568
|
+
# https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/finditemresponsemessage
|
|
569
|
+
response_class = message.get("ResponseClass")
|
|
570
|
+
# ResponseCode, MessageText: See
|
|
571
|
+
# https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/responsecode
|
|
572
|
+
response_code = get_xml_attr(message, f"{{{MNS}}}ResponseCode")
|
|
573
|
+
if response_class == "Success" and response_code == "NoError":
|
|
574
|
+
if not name:
|
|
575
|
+
return message
|
|
576
|
+
container = message.find(name)
|
|
577
|
+
if container is None:
|
|
578
|
+
raise MalformedResponseError(f"No {name} elements in ResponseMessage ({xml_to_str(message)})")
|
|
579
|
+
return container
|
|
580
|
+
if response_code == "NoError":
|
|
581
|
+
return True
|
|
582
|
+
# Raise any non-acceptable errors in the container, or return the container or the acceptable exception instance
|
|
583
|
+
msg_text = get_xml_attr(message, f"{{{MNS}}}MessageText")
|
|
584
|
+
msg_xml = message.find(f"{{{MNS}}}MessageXml")
|
|
585
|
+
rule_errors = message.find(f"{{{MNS}}}RuleOperationErrors")
|
|
586
|
+
if response_class == "Warning":
|
|
587
|
+
try:
|
|
588
|
+
raise self._get_exception(code=response_code, text=msg_text, msg_xml=msg_xml)
|
|
589
|
+
except self.WARNINGS_TO_CATCH_IN_RESPONSE as e:
|
|
590
|
+
return e
|
|
591
|
+
except self.WARNINGS_TO_IGNORE_IN_RESPONSE as e:
|
|
592
|
+
log.warning(str(e))
|
|
593
|
+
container = message.find(name)
|
|
594
|
+
if container is None:
|
|
595
|
+
raise MalformedResponseError(f"No {name} elements in ResponseMessage ({xml_to_str(message)})")
|
|
596
|
+
return container
|
|
597
|
+
# response_class == 'Error', or 'Success' and not 'NoError'
|
|
598
|
+
try:
|
|
599
|
+
raise self._get_exception(code=response_code, text=msg_text, msg_xml=msg_xml, rule_errors=rule_errors)
|
|
600
|
+
except self.ERRORS_TO_CATCH_IN_RESPONSE as e:
|
|
601
|
+
return e
|
|
602
|
+
|
|
603
|
+
@staticmethod
|
|
604
|
+
def _get_exception(code, text, msg_xml=None, rule_errors=None):
|
|
605
|
+
"""Parse error messages contained in EWS responses and raise as exceptions defined in this package."""
|
|
606
|
+
if not code:
|
|
607
|
+
return TransportError(f"Empty ResponseCode in ResponseMessage (MessageText: {text}, MessageXml: {msg_xml})")
|
|
608
|
+
if msg_xml is not None:
|
|
609
|
+
# If this is an ErrorInvalidPropertyRequest error, the xml may contain a specific FieldURI
|
|
610
|
+
for elem_cls in (FieldURI, IndexedFieldURI, ExtendedFieldURI, ExceptionFieldURI):
|
|
611
|
+
elem = msg_xml.find(elem_cls.response_tag())
|
|
612
|
+
if elem is not None:
|
|
613
|
+
field_uri = elem_cls.from_xml(elem, account=None)
|
|
614
|
+
text += f" (field: {field_uri})"
|
|
615
|
+
break
|
|
616
|
+
|
|
617
|
+
# If this is an ErrorInvalidValueForProperty error, the xml may contain the name and value of the property
|
|
618
|
+
if code == "ErrorInvalidValueForProperty":
|
|
619
|
+
msg_parts = {}
|
|
620
|
+
for elem in msg_xml.findall(f"{{{TNS}}}Value"):
|
|
621
|
+
key, val = elem.get("Name"), elem.text
|
|
622
|
+
if key:
|
|
623
|
+
msg_parts[key] = val
|
|
624
|
+
if msg_parts:
|
|
625
|
+
text += f" ({', '.join(f'{k}: {v}' for k, v in msg_parts.items())})"
|
|
626
|
+
|
|
627
|
+
# If this is an ErrorInternalServerError error, the xml may contain a more specific error code
|
|
628
|
+
inner_code, inner_text = None, None
|
|
629
|
+
for value_elem in msg_xml.findall(f"{{{TNS}}}Value"):
|
|
630
|
+
name = value_elem.get("Name")
|
|
631
|
+
if name == "InnerErrorResponseCode":
|
|
632
|
+
inner_code = value_elem.text
|
|
633
|
+
elif name == "InnerErrorMessageText":
|
|
634
|
+
inner_text = value_elem.text
|
|
635
|
+
if inner_code:
|
|
636
|
+
try:
|
|
637
|
+
# Raise the error as the inner error code
|
|
638
|
+
return vars(errors)[inner_code](f"{inner_text} (raised from: {code}({text!r}))")
|
|
639
|
+
except KeyError:
|
|
640
|
+
# Inner code is unknown to us. Just append to the original text
|
|
641
|
+
text += f" (inner error: {inner_code}({inner_text!r}))"
|
|
642
|
+
if rule_errors is not None:
|
|
643
|
+
for rule_error in rule_errors.findall(f"{{{TNS}}}RuleOperationError"):
|
|
644
|
+
for error in rule_error.find(f"{{{TNS}}}ValidationErrors").findall(f"{{{TNS}}}Error"):
|
|
645
|
+
field_uri = get_xml_attr(error, f"{{{TNS}}}FieldURI")
|
|
646
|
+
error_code = get_xml_attr(error, f"{{{TNS}}}ErrorCode")
|
|
647
|
+
error_message = get_xml_attr(error, f"{{{TNS}}}ErrorMessage")
|
|
648
|
+
text += f" ({error_code} on field {field_uri}: {error_message})"
|
|
649
|
+
try:
|
|
650
|
+
# Raise the error corresponding to the ResponseCode
|
|
651
|
+
return vars(errors)[code](text)
|
|
652
|
+
except KeyError:
|
|
653
|
+
# Should not happen
|
|
654
|
+
return TransportError(
|
|
655
|
+
f"Unknown ResponseCode in ResponseMessage: {code} (MessageText: {text}, MessageXml: {msg_xml})"
|
|
656
|
+
)
|
|
657
|
+
|
|
658
|
+
def _get_elements_in_response(self, response):
|
|
659
|
+
"""Take a list of 'SomeServiceResponseMessage' elements and return the elements in each response message that
|
|
660
|
+
we want the service to return. With e.g. 'CreateItem', we get a list of 'CreateItemResponseMessage' elements
|
|
661
|
+
and return the 'Message' elements.
|
|
662
|
+
|
|
663
|
+
<m:CreateItemResponseMessage ResponseClass="Success">
|
|
664
|
+
<m:ResponseCode>NoError</m:ResponseCode>
|
|
665
|
+
<m:Items>
|
|
666
|
+
<t:Message>
|
|
667
|
+
<t:ItemId Id="AQApA=" ChangeKey="AQAAAB"/>
|
|
668
|
+
</t:Message>
|
|
669
|
+
</m:Items>
|
|
670
|
+
</m:CreateItemResponseMessage>
|
|
671
|
+
<m:CreateItemResponseMessage ResponseClass="Success">
|
|
672
|
+
<m:ResponseCode>NoError</m:ResponseCode>
|
|
673
|
+
<m:Items>
|
|
674
|
+
<t:Message>
|
|
675
|
+
<t:ItemId Id="AQApB=" ChangeKey="AQAAAC"/>
|
|
676
|
+
</t:Message>
|
|
677
|
+
</m:Items>
|
|
678
|
+
</m:CreateItemResponseMessage>
|
|
679
|
+
|
|
680
|
+
:param response: a list of 'SomeServiceResponseMessage' XML objects
|
|
681
|
+
:return: a generator of items as returned by '_get_elements_in_container()
|
|
682
|
+
"""
|
|
683
|
+
for msg in response:
|
|
684
|
+
container_or_exc = self._get_element_container(message=msg, name=self.element_container_name)
|
|
685
|
+
if isinstance(container_or_exc, (bool, Exception)):
|
|
686
|
+
yield container_or_exc
|
|
687
|
+
else:
|
|
688
|
+
for c in self._get_elements_in_container(container=container_or_exc):
|
|
689
|
+
yield c
|
|
690
|
+
|
|
691
|
+
@classmethod
|
|
692
|
+
def _get_elements_in_container(cls, container):
|
|
693
|
+
"""Return a list of response elements from an XML response element container. With e.g.
|
|
694
|
+
'CreateItem', 'Items' is the container element, and we return the 'Message' child elements:
|
|
695
|
+
|
|
696
|
+
<m:Items>
|
|
697
|
+
<t:Message>
|
|
698
|
+
<t:ItemId Id="AQApA=" ChangeKey="AQAAAB"/>
|
|
699
|
+
</t:Message>
|
|
700
|
+
</m:Items>
|
|
701
|
+
|
|
702
|
+
If the service does not return response elements, return True to indicate the status. Errors have already been
|
|
703
|
+
raised.
|
|
704
|
+
"""
|
|
705
|
+
if cls.returns_elements:
|
|
706
|
+
return list(container)
|
|
707
|
+
return [True]
|
|
708
|
+
|
|
709
|
+
|
|
710
|
+
class EWSAccountService(EWSService, metaclass=abc.ABCMeta):
|
|
711
|
+
"""Base class for services that act on items concerning a single Mailbox on the server."""
|
|
712
|
+
|
|
713
|
+
NO_VALID_SERVER_VERSIONS = ErrorInvalidSchemaVersionForMailboxVersion
|
|
714
|
+
# Marks services that need affinity to the backend server
|
|
715
|
+
prefer_affinity = False
|
|
716
|
+
|
|
717
|
+
def __init__(self, *args, **kwargs):
|
|
718
|
+
self.account = kwargs.pop("account")
|
|
719
|
+
kwargs["protocol"] = self.account.protocol
|
|
720
|
+
super().__init__(*args, **kwargs)
|
|
721
|
+
|
|
722
|
+
@property
|
|
723
|
+
def _version_hint(self):
|
|
724
|
+
return self.account.version
|
|
725
|
+
|
|
726
|
+
@_version_hint.setter
|
|
727
|
+
def _version_hint(self, value):
|
|
728
|
+
self.account.version = value
|
|
729
|
+
|
|
730
|
+
def _handle_response_cookies(self, session):
|
|
731
|
+
super()._handle_response_cookies(session=session)
|
|
732
|
+
|
|
733
|
+
# See self._extra_headers() for documentation on affinity
|
|
734
|
+
if self.prefer_affinity:
|
|
735
|
+
for cookie in session.cookies:
|
|
736
|
+
if cookie.name == "X-BackEndOverrideCookie":
|
|
737
|
+
self.account.affinity_cookie = cookie.value
|
|
738
|
+
break
|
|
739
|
+
|
|
740
|
+
def _extra_headers(self):
|
|
741
|
+
headers = super()._extra_headers()
|
|
742
|
+
# See
|
|
743
|
+
# https://blogs.msdn.microsoft.com/webdav_101/2015/05/11/best-practices-ews-authentication-and-access-issues/
|
|
744
|
+
headers["X-AnchorMailbox"] = self.account.primary_smtp_address
|
|
745
|
+
|
|
746
|
+
# See
|
|
747
|
+
# https://docs.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-maintain-affinity-between-group-of-subscriptions-and-mailbox-server
|
|
748
|
+
if self.prefer_affinity:
|
|
749
|
+
headers["X-PreferServerAffinity"] = "True"
|
|
750
|
+
if self.account.affinity_cookie:
|
|
751
|
+
headers["X-BackEndOverrideCookie"] = self.account.affinity_cookie
|
|
752
|
+
return headers
|
|
753
|
+
|
|
754
|
+
@property
|
|
755
|
+
def _account_to_impersonate(self):
|
|
756
|
+
if self.account.access_type == IMPERSONATION:
|
|
757
|
+
return self.account.identity
|
|
758
|
+
return super()._account_to_impersonate
|
|
759
|
+
|
|
760
|
+
@property
|
|
761
|
+
def _timezone(self):
|
|
762
|
+
return self.account.default_timezone
|
|
763
|
+
|
|
764
|
+
|
|
765
|
+
class EWSPagingService(EWSAccountService):
|
|
766
|
+
PAGE_SIZE = 100 # A default page size for all paging services. This is the number of items we request per page
|
|
767
|
+
|
|
768
|
+
paging_container_name = None # The name of the element that contains paging information and the paged results
|
|
769
|
+
|
|
770
|
+
def __init__(self, *args, **kwargs):
|
|
771
|
+
self.page_size = kwargs.pop("page_size", None) or self.PAGE_SIZE
|
|
772
|
+
if not isinstance(self.page_size, int):
|
|
773
|
+
raise InvalidTypeError("page_size", self.page_size, int)
|
|
774
|
+
if self.page_size < 1:
|
|
775
|
+
raise ValueError(f"'page_size' {self.page_size} must be a positive number")
|
|
776
|
+
super().__init__(*args, **kwargs)
|
|
777
|
+
|
|
778
|
+
def _response_generator(self, payload):
|
|
779
|
+
"""Send the payload to the server, and return the response.
|
|
780
|
+
|
|
781
|
+
:param payload: payload as an XML object
|
|
782
|
+
:return: the response, as XML objects
|
|
783
|
+
"""
|
|
784
|
+
response = self._get_response_xml(payload=payload)
|
|
785
|
+
return (self._get_page(message) for message in response)
|
|
786
|
+
|
|
787
|
+
def _paged_call(self, payload_func, max_items, folders, **kwargs):
|
|
788
|
+
"""Call a service that supports paging requests. Return a generator over all response items. Keeps track of
|
|
789
|
+
all paging-related counters.
|
|
790
|
+
"""
|
|
791
|
+
paging_infos = {f: dict(item_count=0, next_offset=None) for f in folders}
|
|
792
|
+
common_next_offset = kwargs["offset"]
|
|
793
|
+
total_item_count = 0
|
|
794
|
+
while True:
|
|
795
|
+
if not paging_infos:
|
|
796
|
+
# Paging is done for all folders
|
|
797
|
+
break
|
|
798
|
+
log.debug("Getting page at offset %s (max_items %s)", common_next_offset, max_items)
|
|
799
|
+
kwargs["offset"] = common_next_offset
|
|
800
|
+
kwargs["folders"] = paging_infos.keys() # Only request the paging of the remaining folders.
|
|
801
|
+
pages = self._get_pages(payload_func, kwargs, len(paging_infos))
|
|
802
|
+
for (page, next_offset), (f, paging_info) in zip(pages, list(paging_infos.items())):
|
|
803
|
+
paging_info["next_offset"] = next_offset
|
|
804
|
+
if isinstance(page, Exception):
|
|
805
|
+
# Assume this folder no longer works. Don't attempt to page it again.
|
|
806
|
+
log.debug("Exception occurred for folder %s. Removing.", f)
|
|
807
|
+
del paging_infos[f]
|
|
808
|
+
yield page
|
|
809
|
+
continue
|
|
810
|
+
if page is not None:
|
|
811
|
+
for elem in self._get_elems_from_page(page, max_items, total_item_count):
|
|
812
|
+
paging_info["item_count"] += 1
|
|
813
|
+
total_item_count += 1
|
|
814
|
+
yield elem
|
|
815
|
+
if max_items and total_item_count >= max_items:
|
|
816
|
+
# No need to continue. Break out of inner loop
|
|
817
|
+
log.debug("'max_items' count reached (inner)")
|
|
818
|
+
break
|
|
819
|
+
if not paging_info["next_offset"]:
|
|
820
|
+
# Paging is done for this folder. Don't attempt to page it again.
|
|
821
|
+
log.debug("Paging has completed for folder %s. Removing.", f)
|
|
822
|
+
del paging_infos[f]
|
|
823
|
+
continue
|
|
824
|
+
log.debug("Folder %s still has items", f)
|
|
825
|
+
# Check sanity of paging offsets, but don't fail. When we are iterating huge collections that take a
|
|
826
|
+
# long time to complete, the collection may change while we are iterating. This can affect the
|
|
827
|
+
# 'next_offset' value and make it inconsistent with the number of already collected items.
|
|
828
|
+
# We may have a mismatch if we stopped early due to reaching 'max_items'.
|
|
829
|
+
if paging_info["next_offset"] != paging_info["item_count"] and (
|
|
830
|
+
not max_items or total_item_count < max_items
|
|
831
|
+
):
|
|
832
|
+
log.warning(
|
|
833
|
+
"Unexpected next offset: %s -> %s. Maybe the server-side collection has changed?",
|
|
834
|
+
paging_info["item_count"],
|
|
835
|
+
paging_info["next_offset"],
|
|
836
|
+
)
|
|
837
|
+
# Also break out of outer loop
|
|
838
|
+
if max_items and total_item_count >= max_items:
|
|
839
|
+
log.debug("'max_items' count reached (outer)")
|
|
840
|
+
break
|
|
841
|
+
common_next_offset = self._get_next_offset(paging_infos.values())
|
|
842
|
+
if common_next_offset is None:
|
|
843
|
+
# Paging is done for all folders
|
|
844
|
+
break
|
|
845
|
+
|
|
846
|
+
@staticmethod
|
|
847
|
+
def _get_paging_values(elem):
|
|
848
|
+
"""Read paging information from the paging container element."""
|
|
849
|
+
offset_attr = elem.get("IndexedPagingOffset")
|
|
850
|
+
next_offset = None if offset_attr is None else int(offset_attr)
|
|
851
|
+
item_count = int(elem.get("TotalItemsInView"))
|
|
852
|
+
is_last_page = elem.get("IncludesLastItemInRange").lower() in ("true", "0")
|
|
853
|
+
log.debug("Got page with offset %s, item_count %s, last_page %s", next_offset, item_count, is_last_page)
|
|
854
|
+
# Clean up contradictory paging values
|
|
855
|
+
if next_offset is None and not is_last_page:
|
|
856
|
+
log.debug("Not last page in range, but server didn't send a page offset. Assuming first page")
|
|
857
|
+
next_offset = 1
|
|
858
|
+
if next_offset is not None and is_last_page:
|
|
859
|
+
if next_offset != item_count:
|
|
860
|
+
log.debug("Last page in range, but we still got an offset. Assuming paging has completed")
|
|
861
|
+
next_offset = None
|
|
862
|
+
if not item_count and not is_last_page:
|
|
863
|
+
log.debug("Not last page in range, but also no items left. Assuming paging has completed")
|
|
864
|
+
next_offset = None
|
|
865
|
+
if item_count and next_offset == 0:
|
|
866
|
+
log.debug("Non-zero offset, but also no items left. Assuming paging has completed")
|
|
867
|
+
next_offset = None
|
|
868
|
+
return item_count, next_offset
|
|
869
|
+
|
|
870
|
+
def _get_page(self, message):
|
|
871
|
+
"""Get a single page from a request message, and return the container and next offset."""
|
|
872
|
+
paging_elem = self._get_element_container(message=message, name=self.paging_container_name)
|
|
873
|
+
if isinstance(paging_elem, Exception):
|
|
874
|
+
return paging_elem, None
|
|
875
|
+
item_count, next_offset = self._get_paging_values(paging_elem)
|
|
876
|
+
if not item_count:
|
|
877
|
+
paging_elem = None
|
|
878
|
+
return paging_elem, next_offset
|
|
879
|
+
|
|
880
|
+
def _get_elems_from_page(self, elem, max_items, total_item_count):
|
|
881
|
+
container = elem.find(self.element_container_name)
|
|
882
|
+
if container is None:
|
|
883
|
+
raise MalformedResponseError(
|
|
884
|
+
f"No {self.element_container_name} elements in ResponseMessage ({xml_to_str(elem)})"
|
|
885
|
+
)
|
|
886
|
+
for e in self._get_elements_in_container(container=container):
|
|
887
|
+
if max_items and total_item_count >= max_items:
|
|
888
|
+
# No need to continue. Break out of elements loop
|
|
889
|
+
log.debug("'max_items' count reached (elements)")
|
|
890
|
+
break
|
|
891
|
+
yield e
|
|
892
|
+
|
|
893
|
+
def _get_pages(self, payload_func, kwargs, expected_message_count):
|
|
894
|
+
"""Request a page, or a list of pages if multiple collections are pages in a single request. Return each
|
|
895
|
+
page.
|
|
896
|
+
"""
|
|
897
|
+
payload = payload_func(**kwargs)
|
|
898
|
+
page_elems = list(self._get_elements(payload=payload))
|
|
899
|
+
if len(page_elems) != expected_message_count:
|
|
900
|
+
raise MalformedResponseError(
|
|
901
|
+
f"Expected {expected_message_count} items in 'response', got {len(page_elems)}"
|
|
902
|
+
)
|
|
903
|
+
return page_elems
|
|
904
|
+
|
|
905
|
+
@staticmethod
|
|
906
|
+
def _get_next_offset(paging_infos):
|
|
907
|
+
next_offsets = {p["next_offset"] for p in paging_infos if p["next_offset"] is not None}
|
|
908
|
+
if not next_offsets:
|
|
909
|
+
# Paging is done for all messages
|
|
910
|
+
return None
|
|
911
|
+
# We cannot guarantee that all messages that have a next_offset also have the *same* next_offset. This is
|
|
912
|
+
# because the collections that we are iterating may change while iterating. We'll do our best, but we cannot
|
|
913
|
+
# guarantee 100% consistency when large collections are simultaneously being changed on the server.
|
|
914
|
+
#
|
|
915
|
+
# It's not possible to supply a per-folder offset when iterating multiple folders, so we'll just have to
|
|
916
|
+
# choose something that is most likely to work. Select the lowest of all the values to at least make sure
|
|
917
|
+
# we don't miss any items, although we may then get duplicates ¯\_(ツ)_/¯
|
|
918
|
+
if len(next_offsets) > 1:
|
|
919
|
+
log.warning("Inconsistent next_offset values: %r. Using lowest value", next_offsets)
|
|
920
|
+
return min(next_offsets)
|
|
921
|
+
|
|
922
|
+
|
|
923
|
+
def to_item_id(item, item_cls):
|
|
924
|
+
# Coerce a tuple, dict or object to an 'item_cls' instance. Used to create [Parent][Item|Folder]Id instances from a
|
|
925
|
+
# variety of input.
|
|
926
|
+
if isinstance(item, (BaseItemId, AttachmentId)):
|
|
927
|
+
# Allow any BaseItemId subclass to pass unaltered
|
|
928
|
+
return item
|
|
929
|
+
if isinstance(item, (BaseFolder, BaseItem)):
|
|
930
|
+
return item.to_id()
|
|
931
|
+
if isinstance(item, (str, tuple, list)):
|
|
932
|
+
return item_cls(*item)
|
|
933
|
+
return item_cls(item.id, item.changekey)
|
|
934
|
+
|
|
935
|
+
|
|
936
|
+
def shape_element(tag, shape, additional_fields, version):
|
|
937
|
+
shape_elem = create_element(tag)
|
|
938
|
+
add_xml_child(shape_elem, "t:BaseShape", shape)
|
|
939
|
+
if additional_fields:
|
|
940
|
+
additional_properties = create_element("t:AdditionalProperties")
|
|
941
|
+
expanded_fields = chain(*(f.expand(version=version) for f in additional_fields))
|
|
942
|
+
# 'path' is insufficient to consistently sort additional properties. For example, we have both
|
|
943
|
+
# 'contacts:Companies' and 'task:Companies' with path 'companies'. Sort by both 'field_uri' and 'path'.
|
|
944
|
+
# Extended properties do not have a 'field_uri' value.
|
|
945
|
+
set_xml_value(
|
|
946
|
+
additional_properties,
|
|
947
|
+
sorted(expanded_fields, key=lambda f: (getattr(f.field, "field_uri", ""), f.path)),
|
|
948
|
+
version=version,
|
|
949
|
+
)
|
|
950
|
+
shape_elem.append(additional_properties)
|
|
951
|
+
return shape_elem
|
|
952
|
+
|
|
953
|
+
|
|
954
|
+
def _ids_element(items, item_cls, version, tag):
|
|
955
|
+
item_ids = create_element(tag)
|
|
956
|
+
for item in items:
|
|
957
|
+
set_xml_value(item_ids, to_item_id(item, item_cls), version=version)
|
|
958
|
+
return item_ids
|
|
959
|
+
|
|
960
|
+
|
|
961
|
+
def folder_ids_element(folders, version, tag="m:FolderIds"):
|
|
962
|
+
return _ids_element(folders, FolderId, version, tag)
|
|
963
|
+
|
|
964
|
+
|
|
965
|
+
def item_ids_element(items, version, tag="m:ItemIds"):
|
|
966
|
+
return _ids_element(items, ItemId, version, tag)
|
|
967
|
+
|
|
968
|
+
|
|
969
|
+
def attachment_ids_element(items, version, tag="m:AttachmentIds"):
|
|
970
|
+
return _ids_element(items, AttachmentId, version, tag)
|
|
971
|
+
|
|
972
|
+
|
|
973
|
+
def parse_folder_elem(elem, folder):
|
|
974
|
+
if isinstance(folder, RootOfHierarchy):
|
|
975
|
+
res = folder.from_xml(elem=elem, account=folder.account)
|
|
976
|
+
elif isinstance(folder, Folder):
|
|
977
|
+
res = folder.from_xml_with_root(elem=elem, root=folder.root)
|
|
978
|
+
else:
|
|
979
|
+
raise ValueError(f"Unsupported folder class: {folder}")
|
|
980
|
+
# Not all servers support fetching the DistinguishedFolderId field. Add it back here.
|
|
981
|
+
if folder._distinguished_id and not res._distinguished_id:
|
|
982
|
+
res._distinguished_id = folder._distinguished_id
|
|
983
|
+
return res
|