Version in base suite: 4.11-1 Base version: eas4tbsync_4.11-1 Target version: eas4tbsync_4.17-1~deb13u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/e/eas4tbsync/eas4tbsync_4.11-1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/e/eas4tbsync/eas4tbsync_4.17-1~deb13u1.dsc /srv/release.debian.org/tmp/3hr8AaymMg/eas4tbsync-4.17/screenshots/AddEASAccount.png |binary /srv/release.debian.org/tmp/3hr8AaymMg/eas4tbsync-4.17/screenshots/autodiscover.png |binary /srv/release.debian.org/tmp/3hr8AaymMg/eas4tbsync-4.17/screenshots/install.png |binary /srv/release.debian.org/tmp/3hr8AaymMg/eas4tbsync-4.17/screenshots/options.png |binary /srv/release.debian.org/tmp/3hr8AaymMg/eas4tbsync-4.17/unused/icons/cape.png |binary /srv/release.debian.org/tmp/3hr8AaymMg/eas4tbsync-4.17/unused/icons/catman.png |binary /srv/release.debian.org/tmp/3hr8AaymMg/eas4tbsync-4.17/unused/icons/discon.png |binary /srv/release.debian.org/tmp/3hr8AaymMg/eas4tbsync-4.17/unused/icons/help.png |binary /srv/release.debian.org/tmp/3hr8AaymMg/eas4tbsync-4.17/unused/icons/old2_sync16.png |binary /srv/release.debian.org/tmp/3hr8AaymMg/eas4tbsync-4.17/unused/icons/old2_sync16_r.png |binary /srv/release.debian.org/tmp/3hr8AaymMg/eas4tbsync-4.17/unused/icons/old_sync16.png |binary /srv/release.debian.org/tmp/3hr8AaymMg/eas4tbsync-4.17/unused/icons/settings.png |binary /srv/release.debian.org/tmp/3hr8AaymMg/eas4tbsync-4.17/unused/icons/slider-off.png |binary /srv/release.debian.org/tmp/3hr8AaymMg/eas4tbsync-4.17/unused/icons/slider-on.png |binary /srv/release.debian.org/tmp/3hr8AaymMg/eas4tbsync-4.17/unused/icons/sync.png |binary /srv/release.debian.org/tmp/3hr8AaymMg/eas4tbsync-4.17/unused/icons/syncsmall.png |binary /srv/release.debian.org/tmp/3hr8AaymMg/eas4tbsync-4.17/unused/icons/t3_sync16.png |binary /srv/release.debian.org/tmp/3hr8AaymMg/eas4tbsync-4.17/unused/icons/t3_sync16_r.png |binary eas4tbsync-4.17/.github/issue_template.md | 16 eas4tbsync-4.17/CONTRIBUTORS.md | 39 eas4tbsync-4.17/LICENSE | 746 +- eas4tbsync-4.17/Makebeta | 34 eas4tbsync-4.17/Makefile | 25 eas4tbsync-4.17/Makefile.bat | 9 eas4tbsync-4.17/README.md | 46 eas4tbsync-4.17/_locales/Readme.txt | 16 eas4tbsync-4.17/_locales/bg/messages.json | 1132 +-- eas4tbsync-4.17/_locales/cs/messages.json | 1132 +-- eas4tbsync-4.17/_locales/de/messages.json | 1132 +-- eas4tbsync-4.17/_locales/en-US/messages.json | 1132 +-- eas4tbsync-4.17/_locales/es/messages.json | 1132 +-- eas4tbsync-4.17/_locales/fr/messages.json | 1132 +-- eas4tbsync-4.17/_locales/gl/messages.json | 1132 +-- eas4tbsync-4.17/_locales/hu/messages.json | 1132 +-- eas4tbsync-4.17/_locales/it/messages.json | 1132 +-- eas4tbsync-4.17/_locales/ja/messages.json | 1132 +-- eas4tbsync-4.17/_locales/pl/messages.json | 1132 +-- eas4tbsync-4.17/_locales/pt_BR/messages.json | 1132 +-- eas4tbsync-4.17/_locales/ro/messages.json | 1132 +-- eas4tbsync-4.17/_locales/ru/messages.json | 1132 +-- eas4tbsync-4.17/api/EAS4TbSync/implementation.js | 74 eas4tbsync-4.17/api/EAS4TbSync/schema.json | 13 eas4tbsync-4.17/api/LegacyHelper/README.md | 50 eas4tbsync-4.17/api/LegacyHelper/implementation.js | 118 eas4tbsync-4.17/api/LegacyHelper/schema.json | 42 eas4tbsync-4.17/background.js | 11 eas4tbsync-4.17/beta-release-channel-update.json | 13 eas4tbsync-4.17/content/api/BootstrapLoader/CHANGELOG.md | 75 eas4tbsync-4.17/content/api/BootstrapLoader/README.md | 1 eas4tbsync-4.17/content/api/BootstrapLoader/implementation.js | 187 eas4tbsync-4.17/content/api/BootstrapLoader/schema.json | 61 eas4tbsync-4.17/content/bootstrap.js | 53 eas4tbsync-4.17/content/includes/calendarsync.js | 852 +- eas4tbsync-4.17/content/includes/contactsync.js | 1109 +-- eas4tbsync-4.17/content/includes/network.js | 3150 +++++----- eas4tbsync-4.17/content/includes/sync.js | 3015 ++++----- eas4tbsync-4.17/content/includes/tasksync.js | 429 - eas4tbsync-4.17/content/includes/tools.js | 1083 +-- eas4tbsync-4.17/content/includes/wbxmltools.js | 1766 ++--- eas4tbsync-4.17/content/includes/xmltools.js | 322 - eas4tbsync-4.17/content/locales.js | 15 eas4tbsync-4.17/content/manager/createAccount.js | 517 - eas4tbsync-4.17/content/manager/createAccount.xhtml | 194 eas4tbsync-4.17/content/manager/editAccountOverlay.js | 112 eas4tbsync-4.17/content/manager/editAccountOverlay.xhtml | 308 eas4tbsync-4.17/content/provider.js | 1477 ++-- eas4tbsync-4.17/content/skin/365.svg | 22 eas4tbsync-4.17/content/skin/fieldset.css | 12 eas4tbsync-4.17/content/timezonedata/Aliases.csv | 230 eas4tbsync-4.17/content/timezonedata/README | 8 eas4tbsync-4.17/content/timezonedata/WindowsTimezone.csv | 1028 +-- eas4tbsync-4.17/crowdin.yml | 5 eas4tbsync-4.17/debian/changelog | 28 eas4tbsync-4.17/debian/control | 8 eas4tbsync-4.17/debian/copyright | 4 eas4tbsync-4.17/debian/dpb.conf | 18 eas4tbsync-4.17/debian/gbp.conf | 7 eas4tbsync-4.17/debian/watch | 6 eas4tbsync-4.17/manifest.json | 79 79 files changed, 16654 insertions(+), 16627 deletions(-) diff -Nru eas4tbsync-4.11/.github/issue_template.md eas4tbsync-4.17/.github/issue_template.md --- eas4tbsync-4.11/.github/issue_template.md 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/.github/issue_template.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -## Your environment - -TbSync version: -EAS-4-TbSync version: -Thunderbird version: - -## Expected behavior -... - -## Actual behavior -... - -## Steps to reproduce -... - -To help resolving your issue, enable debug logging (TbSync Account Manager -> Help) and send me the debug.log via e-mail (use the title of your issue as subject of the email). diff -Nru eas4tbsync-4.11/CONTRIBUTORS.md eas4tbsync-4.17/CONTRIBUTORS.md --- eas4tbsync-4.11/CONTRIBUTORS.md 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/CONTRIBUTORS.md 2025-07-28 17:36:48.000000000 +0000 @@ -1,19 +1,20 @@ -## Creator -* John Bieling - -## Contributors -* Chris Allan (recurring events) -* John Bieling -* Emil Ljungdahl -* Mark Nethersole (initial implementation of contact sync) -* Dzamo Norton -* Puran2 -* Tijuca - -## Translators -* John Bieling (de, en-US) -* Wanderlei Hüttel (pt-BR) -* Alessandro Menti (it) -* Óvári (hu) -* Alexey Sinitsyn (ru) -* Daniel Wróblewski (pl) +## Creator +* John Bieling + +## Contributors +* Chris Allan (recurring events) +* John Bieling +* Emil Ljungdahl +* Mark Nethersole (initial implementation of contact sync) +* Dzamo Norton +* Puran2 +* Tijuca +* Kabe2007 + +## Translators +* John Bieling (de, en-US) +* Wanderlei Hüttel (pt-BR) +* Alessandro Menti (it) +* Óvári (hu) +* Alexey Sinitsyn (ru) +* Daniel Wróblewski (pl) diff -Nru eas4tbsync-4.11/LICENSE eas4tbsync-4.17/LICENSE --- eas4tbsync-4.11/LICENSE 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/LICENSE 2019-05-17 21:11:12.000000000 +0000 @@ -1,373 +1,373 @@ -Mozilla Public License Version 2.0 -================================== - -1. Definitions --------------- - -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. - -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff -Nru eas4tbsync-4.11/Makebeta eas4tbsync-4.17/Makebeta --- eas4tbsync-4.11/Makebeta 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/Makebeta 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -#!/bin/bash -# This file is part of EAS-4-TbSync. -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -# $1 link to base web server : https://tbsync.jobisoft.de/beta -# $2 local path of base web server : /var/www/jobisoft.de/tbsync/beta -# $3 name of XPI : EAS-4-TbSync.xpi - -git clean -df -git checkout -- . -git pull - -version=$(cat manifest.json | jq -r .version) -updatefile=update-eas.json - -sed -i "s/%VERSION%/$version/g" "beta-release-channel-update.json" -sed -i "s|%LINK%|$1/$3|g" "beta-release-channel-update.json" -sed -i "s/static getApiVersion() { return \"/static getApiVersion() { return \"Beta /g" "content/provider.js" - -echo "Releasing version $version via beta release channel (will include updateURL)" -sed -i "s|\"name\": \"__MSG_extensionName__\",|\"name\": \"EAS for TbSync [Beta Release Channel]\",|g" "manifest.json" -sed -i "s|\"gecko\": {|\"gecko\": {\n \"update_url\": \"$1/$updatefile\",|g" "manifest.json" - -cp beta-release-channel-update.json $2/$updatefile - -rm -f $3 -rm -f $3.tar.gz -zip -r $3 content _locales manifest.json background.js LICENSE CONTRIBUTORS.md -tar cfvz $3.tar.gz content _locales manifest.json background.js LICENSE CONTRIBUTORS.md -cp $3 $2/$3 -cp $3.tar.gz $2/$3.tar.gz diff -Nru eas4tbsync-4.11/Makefile eas4tbsync-4.17/Makefile --- eas4tbsync-4.11/Makefile 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -# This file is part of EAS-4-TbSync. -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -PACKAGE_NAME=EAS-4-TbSync - -ARCHIVE_NAME=$(PACKAGE_NAME).xpi - -PACKAGE_FILES= \ - content \ - _locales \ - manifest.json \ - CONTRIBUTORS.md \ - LICENSE README.md \ - background.js - -all: clean $(PACKAGE_FILES) - zip -r $(ARCHIVE_NAME) $(PACKAGE_FILES) - -clean: - rm -f $(ARCHIVE_NAME) - -.PHONY: clean diff -Nru eas4tbsync-4.11/Makefile.bat eas4tbsync-4.17/Makefile.bat --- eas4tbsync-4.11/Makefile.bat 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/Makefile.bat 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ -@echo off -REM This file is part of EAS-4-TbSync. -REM -REM This Source Code Form is subject to the terms of the Mozilla Public -REM License, v. 2.0. If a copy of the MPL was not distributed with this -REM file, You can obtain one at http://mozilla.org/MPL/2.0/. - -del EAS-4-TbSync.xpi -"C:\Program Files\7-Zip\7zG.exe" a -tzip EAS-4-TbSync.xpi content _locales manifest.json CONTRIBUTORS.md LICENSE README.md background.js diff -Nru eas4tbsync-4.11/README.md eas4tbsync-4.17/README.md --- eas4tbsync-4.11/README.md 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/README.md 2019-11-30 12:30:50.000000000 +0000 @@ -1,23 +1,23 @@ -# EAS-4-TbSync - -This provider add-on adds Exchange ActiveSync (EAS v2.5 & v14.0) synchronization capabilities to [TbSync](https://github.com/jobisoft/TbSync/). - -More information can be found in the [wiki](https://github.com/jobisoft/EAS-4-TbSync/wiki/About:-Provider-for-Exchange-ActiveSync) of this repository - -## Want to add or fix a localization? -To help translating this project, please visit [crowdin.com](https://crowdin.com/profile/jobisoft), where the localizations are managed. If you want to add a new language, just contact me and I will set it up. - - -## External data sources - -* TbSync uses a [timezone mapping](https://github.com/mj1856/TimeZoneConverter/blob/master/src/TimeZoneConverter/Data/Mapping.csv.gz) provided by [Matt Johnson](https://github.com/mj1856) - - -## Icon sources and attributions - -#### CC0 Public Domain -* [365_*.png] by [Microsoft / Wikimedia](https://commons.wikimedia.org/w/index.php?curid=21546299), converted from [SVG to PNG](https://ezgif.com/svg-to-png) - -#### CC-BY 3.0 -* [eas*.png] by [FatCow Web Hosting](https://www.iconfinder.com/icons/64484/exchange_ms_icon) -* [exchange_300.png] derived from [Microsoft Exchange Icon #270871](https://icon-library.net/icon/microsoft-exchange-icon-10.html), [resized](www.simpleimageresizer.com/) +# EAS-4-TbSync + +This provider add-on adds Exchange ActiveSync (EAS v2.5 & v14.0) synchronization capabilities to [TbSync](https://github.com/jobisoft/TbSync/). + +More information can be found in the [wiki](https://github.com/jobisoft/EAS-4-TbSync/wiki/About:-Provider-for-Exchange-ActiveSync) of this repository + +## Want to add or fix a localization? +To help translating this project, please visit [crowdin.com](https://crowdin.com/profile/jobisoft), where the localizations are managed. If you want to add a new language, just contact me and I will set it up. + + +## External data sources + +* TbSync uses a [timezone mapping](https://github.com/mj1856/TimeZoneConverter/blob/master/src/TimeZoneConverter/Data/Mapping.csv.gz) provided by [Matt Johnson](https://github.com/mj1856) + + +## Icon sources and attributions + +#### CC0 Public Domain +* [365_*.png] by [Microsoft / Wikimedia](https://commons.wikimedia.org/w/index.php?curid=21546299), converted from [SVG to PNG](https://ezgif.com/svg-to-png) + +#### CC-BY 3.0 +* [eas*.png] by [FatCow Web Hosting](https://www.iconfinder.com/icons/64484/exchange_ms_icon) +* [exchange_300.png] derived from [Microsoft Exchange Icon #270871](https://icon-library.net/icon/microsoft-exchange-icon-10.html), [resized](www.simpleimageresizer.com/) diff -Nru eas4tbsync-4.11/_locales/Readme.txt eas4tbsync-4.17/_locales/Readme.txt --- eas4tbsync-4.11/_locales/Readme.txt 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/_locales/Readme.txt 2019-09-30 15:35:10.000000000 +0000 @@ -1,8 +1,8 @@ -Want to add or fix a localization? - -To help translating this project, please visit - - https://crowdin.com/profile/jobisoft - -where the localizations are managed. If you want to add -a new language, just contact me and I will set it up. +Want to add or fix a localization? + +To help translating this project, please visit + + https://crowdin.com/profile/jobisoft + +where the localizations are managed. If you want to add +a new language, just contact me and I will set it up. diff -Nru eas4tbsync-4.11/_locales/bg/messages.json eas4tbsync-4.17/_locales/bg/messages.json --- eas4tbsync-4.11/_locales/bg/messages.json 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/_locales/bg/messages.json 2025-05-15 11:21:18.000000000 +0000 @@ -1,566 +1,566 @@ -{ - "abCard.Anniversary": { - "message": "Anniversary:" - }, - "abCard.AssistantName": { - "message": "Assistant:" - }, - "abCard.AssistantPhoneNumber": { - "message": "Assistant Phone:" - }, - "abCard.Business2PhoneNumber": { - "message": "Work Alternative Phone:" - }, - "abCard.BusinessFaxNumber": { - "message": "Work Fax:" - }, - "abCard.CarPhoneNumber": { - "message": "Car Phone:" - }, - "abCard.CompanyMainPhone": { - "message": "Work Main Phone:" - }, - "abCard.Email3Address": { - "message": "Alternative Email:" - }, - "abCard.Home2PhoneNumber": { - "message": "Home Alternative Phone:" - }, - "abCard.ManagerName": { - "message": "Manager:" - }, - "abCard.MiddleName": { - "message": "Middle name:" - }, - "abCard.OtherAddress": { - "message": "Address:" - }, - "abCard.OtherCity": { - "message": "City:" - }, - "abCard.OtherCountry": { - "message": "Country:" - }, - "abCard.OtherState": { - "message": "State:" - }, - "abCard.OtherZip": { - "message": "ZIP Code:" - }, - "abCard.RadioPhoneNumber": { - "message": "Radio Phone:" - }, - "abCard.Spouse": { - "message": "Spouse:" - }, - "abCard.header.eas": { - "message": "Other Fields (EAS)" - }, - "abCard.header.homenumbers": { - "message": "Additional home numbers:" - }, - "abCard.header.messaging": { - "message": "Messaging:" - }, - "abCard.header.otheraddress": { - "message": "Other Address (EAS)" - }, - "abCard.header.othernumbers": { - "message": "Additional numbers:" - }, - "abCard.header.people": { - "message": "People:" - }, - "abCard.header.worknumbers": { - "message": "Additional work numbers:" - }, - "acl.readonly": { - "message": "Read-only server access (revert local changes)" - }, - "acl.readwrite": { - "message": "Read from and write to server" - }, - "add.description": { - "message": "Please select one of the available server configuration options and enter the requested details. " - }, - "add.name": { - "message": "Account name:" - }, - "add.ok": { - "message": "Add account" - }, - "add.password": { - "message": "Password:" - }, - "add.server": { - "message": "Server configuration:" - }, - "add.shortdescription": { - "message": "Account information" - }, - "add.title": { - "message": "Adding an Exchange ActiveSync account to TbSync" - }, - "add.url": { - "message": "Server address:" - }, - "add.urldescription": { - "message": "It should be sufficient to provide just the basic server address (e.g.: mail.yourserver.com). However, it is also possible to provide the full URL (e.g.: https://mail.yourserver.com/Microsoft-Server-ActiveSync)." - }, - "add.user": { - "message": "User name (email address):" - }, - "autocomplete.serverdirectory": { - "message": "global server directory" - }, - "autodiscover.Failed": { - "message": "Autodiscover for user <##user##> failed. Either the provided credentials were wrong or your ActiveSync provider has a temporary issue, or does not support Autodiscover." - }, - "autodiscover.NeedEmail": { - "message": "Autodiscover needs a valid email address as user name." - }, - "autodiscover.Ok": { - "message": "Autodiscover completed successfully, you can now check the optional settings and establish the synchronization connection." - }, - "autodiscover.Querying": { - "message": "Searching for settings…" - }, - "config.auto": { - "message": "ActiveSync server configuration (Autodiscover)" - }, - "config.custom": { - "message": "ActiveSync server configuration" - }, - "deletefolder.confirm": { - "message": "Do you really want to PERMANENTLY PURGE folder “##replace.1##” from trash?" - }, - "deletefolder.menuentry": { - "message": "Permanently purge folder “##replace.1##” from trash" - }, - "deletefolder.notallowed": { - "message": "Please unsubscribe folder “##replace.1##” before trying to purge it from trash." - }, - "extensionDescription": { - "message": "Add sync support for Exchange ActiveSync accounts to TbSync (contacts, tasks and calendars)." - }, - "extensionName": { - "message": "Provider for Exchange ActiveSync" - }, - "helplink.BadItemSkipped": { - "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped" - }, - "helplink.global.clientdenied": { - "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F" - }, - "helplink.security": { - "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F" - }, - "manager.tabs.accountsettings": { - "message": "Account settings" - }, - "manager.tabs.outOfOffice": { - "message": "Auto responder" - }, - "manager.tabs.syncsettings": { - "message": "Options" - }, - "newaccount.add_auto": { - "message": "Autodiscover settings and add account" - }, - "newaccount.add_custom": { - "message": "Add account" - }, - "pref.AccountName": { - "message": "Description" - }, - "pref.ActiveSyncVersion": { - "message": "ActiveSync version" - }, - "pref.DeviceId": { - "message": "ActiveSync device ID" - }, - "pref.ServerName": { - "message": "Server address" - }, - "pref.ServerNameDescription": { - "message": "e.g. mail.yourserver.com" - }, - "pref.ShowTrashedFolders": { - "message": "Show folders found in trash" - }, - "pref.UserName": { - "message": "User name" - }, - "pref.UserNameDescription": { - "message": "User name is usually the email address of your account." - }, - "pref.autodetect": { - "message": "best available" - }, - "pref.birthday": { - "message": "Send birthday information" - }, - "pref.calendaroptions": { - "message": "Calendar options" - }, - "pref.contactoptions": { - "message": "Contact options" - }, - "pref.displayoverride": { - "message": "Override Display Name with “First Name” + “Second Name”" - }, - "pref.generaloptions": { - "message": "General options" - }, - "pref.provision": { - "message": "Enforce provisioning (required by Kerio)" - }, - "pref.seperator.comma": { - "message": "Comma" - }, - "pref.seperator.description": { - "message": "Separator for multiline address field." - }, - "pref.seperator.linebreak": { - "message": "Line break" - }, - "pref.synclimit.1month": { - "message": "from 4 weeks ago" - }, - "pref.synclimit.2weeks": { - "message": "from 2 weeks ago" - }, - "pref.synclimit.3month": { - "message": "from 3 months ago" - }, - "pref.synclimit.6month": { - "message": "from 6 months ago" - }, - "pref.synclimit.all": { - "message": "everything" - }, - "pref.synclimit.description": { - "message": "Synchronization period: " - }, - "pref.usehttps": { - "message": "Use secure connection (connect via https)" - }, - "recyclebin": { - "message": "Trash" - }, - "servertype.auto": { - "message": "Automatic configuration" - }, - "servertype.custom": { - "message": "Custom configuration" - }, - "servertype.description.auto": { - "message": "The configuration for many ActiveSync servers can be discovered by providing just your email address." - }, - "servertype.description.custom": { - "message": "Setup your account by manually providing the address of the server you want to connect." - }, - "servertype.description.office365": { - "message": "Accounts connected to Office 365 use a modern authentication process called OAuth 2.0 which also supports Multi-Factor-Authentication (MFA)." - }, - "servertype.office365": { - "message": "Microsoft Office 365" - }, - "servertype.unlock": { - "message": "Double click to unlock all predefined server settings." - }, - "status.401": { - "message": "Could not authenticate, check username and password (HTTP Error 401)." - }, - "status.403": { - "message": "Server rejected connection (forbidden) (HTTP Error 403)." - }, - "status.404": { - "message": "User not found (HTTP Error 404)." - }, - "status.449": { - "message": "Server requests provisioning (HTTP Error 449)." - }, - "status.500": { - "message": "Unknown Server Error (HTTP Error 500)." - }, - "status.503": { - "message": "Service unavailable (HTTP Error 503)." - }, - "status.BadItemSkipped": { - "message": "Bad Item Skipped: ##replace.1##" - }, - "status.FolderDelete.3": { - "message": "Cannot delete a system folder (status 3)" - }, - "status.FolderDelete.4": { - "message": "Folder does not exist (status 4), resyncing" - }, - "status.FolderDelete.6": { - "message": "Command could not be completed, an error occurred on the server (status 6)" - }, - "status.FolderDelete.9": { - "message": "Invalid synchronization key (status 9), resyncing" - }, - "status.FolderSync.9": { - "message": "Invalid synchronization key (status 9), resyncing" - }, - "status.InvalidServerOptions": { - "message": "The server does not provide information about the supported ActiveSync versions. Is EAS blocked for this user or this client (TbSync)? You could try to set the ActiveSync version manually." - }, - "status.OK": { - "message": "OK" - }, - "status.ServerRejectedRequest": { - "message": "The EAS Server rejected the last request." - }, - "status.ServerRejectedSomeItems": { - "message": "The EAS server did not accept ##replace.1## elements." - }, - "status.Sync.12": { - "message": "Folder hierarchy changed (status 12), resyncing" - }, - "status.Sync.3": { - "message": "Invalid synchronization key (status 3), resyncing" - }, - "status.Sync.4": { - "message": "Malformed request (status 4)" - }, - "status.Sync.5": { - "message": "Temporary server issues or invalid item (status 5)" - }, - "status.Sync.6": { - "message": "Invalid item (status 6)" - }, - "status.Sync.8": { - "message": "Object not found (status 8)" - }, - "status.aborted": { - "message": "Not synchronized" - }, - "status.disabled": { - "message": "Disabled" - }, - "status.empty-response": { - "message": "Server sends unexpected empty response." - }, - "status.forbiddenCalendarItemInTasksFolder": { - "message": "Forbidden calendar item in a task folder (please resort)" - }, - "status.forbiddenTasksItemInCalendarFolder": { - "message": "Forbidden task item in a calendar folder (please resort)" - }, - "status.global.101": { - "message": "The request contains WBXML but it could not be decoded into XML (EAS Error 101)." - }, - "status.global.102": { - "message": "The request contains WBXML but it could not be decoded into XML (EAS Error 102)." - }, - "status.global.103": { - "message": "The XML provided in the request does not follow the protocol requirements (EAS Error 103)." - }, - "status.global.110": { - "message": "The server reported an internal error and we should not retry immediately. Automatic periodic sync has been disabled for 30 minutes (EAS Error 110)." - }, - "status.global.clientdenied": { - "message": "The EAS server reports <##replace.2##> (status ##replace.1##) and does not allow TbSync to access your account." - }, - "status.httperror": { - "message": "Communication error (HTTP status ##replace.1##)." - }, - "status.invalid": { - "message": "Invalid server response (junk)." - }, - "status.malformed-xml": { - "message": "Could not parse XML. Check event log for details." - }, - "status.modified": { - "message": "Local modifications" - }, - "status.network": { - "message": "Could not connect to server (##replace.1##)." - }, - "status.networkerror": { - "message": "Could not connect to server." - }, - "status.nosupportedeasversion": { - "message": "Server does not support ActiveSync v2.5 or v14.0 (only ##replace.1##). TbSync will not work with this ActiveSync server." - }, - "status.notargets": { - "message": "Aborting Sync, because sync targets could not be created." - }, - "status.notsupportedeasversion": { - "message": "Server does not support selected ActiveSync v##replace.1## (only ##replace.2##)." - }, - "status.notsyncronized": { - "message": "Account needs to be synchronized, at least one item is out of sync." - }, - "status.nouserhost": { - "message": "Missing username and/or server. Please provide those values." - }, - "status.pending": { - "message": "Waiting to be synchronized" - }, - "status.policy.2": { - "message": "There is no policy for this client. Contact your server administrator or disable provisioning for this account." - }, - "status.policy.3": { - "message": "Unknown PolicyType value. Contact your server administrator or disable provisioning for this account." - }, - "status.policy.4": { - "message": "The policy data on the server is corrupted (possibly tampered with). Contact your server administrator or disable provisioning for this account." - }, - "status.policy.5": { - "message": "The client is acknowledging the wrong policy key. Contact your server administrator or disable provisioning for this account." - }, - "status.provision": { - "message": "Provisioning failed with status <##replace.1##>" - }, - "status.response-contains-no-data": { - "message": "Response from the server contains no data." - }, - "status.resync-loop": { - "message": "There was an error from which we could not recover by resyncing the account. Please disable the account and try again. (Error: resync loop)" - }, - "status.security": { - "message": "Could not establish a secure connection. Are you using a self-signed or otherwise untrusted certificate without importing it into Thunderbird? (##replace.1##)" - }, - "status.skipped": { - "message": "Not yet supported, skipped" - }, - "status.syncing": { - "message": "Synchronizing" - }, - "status.timeout": { - "message": "Communication timeout." - }, - "status.wbxml-parse-error": { - "message": "Server sends unreadable response." - }, - "status.wbxmlerror": { - "message": "Sync failed. Server responded with status <##replace.1##>." - }, - "status.wbxmlmissingfield": { - "message": "ActiveSync protocol violation: Mandatory field <##replace.1##> is missing from server response." - }, - "syncstate.accountdone": { - "message": "Finished account" - }, - "syncstate.done": { - "message": "Preparing next item for synchronization" - }, - "syncstate.eval.response.autodiscover": { - "message": "Processing updated server settings" - }, - "syncstate.eval.response.deletefolder": { - "message": "Folder deleted" - }, - "syncstate.eval.response.estimate": { - "message": "Processing change estimate" - }, - "syncstate.eval.response.folders": { - "message": "Processing folder list update" - }, - "syncstate.eval.response.localchanges": { - "message": "Processing acknowledgment of local changes" - }, - "syncstate.eval.response.localdeletes": { - "message": "Processing acknowledgment of local deletes" - }, - "syncstate.eval.response.options": { - "message": "Processing server options" - }, - "syncstate.eval.response.provision": { - "message": "Processing provision" - }, - "syncstate.eval.response.remotechanges": { - "message": "Processing remote changes" - }, - "syncstate.eval.response.revertlocalchanges": { - "message": "Reverting local changes" - }, - "syncstate.eval.response.setdeviceinfo": { - "message": "Sending device information" - }, - "syncstate.eval.response.synckey": { - "message": "Processing SyncKey" - }, - "syncstate.prepare.request.autodiscover": { - "message": "Requesting updated server settings" - }, - "syncstate.prepare.request.deletefolder": { - "message": "Preparing to delete folder" - }, - "syncstate.prepare.request.estimate": { - "message": "Requesting change estimate" - }, - "syncstate.prepare.request.folders": { - "message": "Sending folder list update" - }, - "syncstate.prepare.request.localchanges": { - "message": "Sending local changes" - }, - "syncstate.prepare.request.localdeletes": { - "message": "Sending local deletes" - }, - "syncstate.prepare.request.options": { - "message": "Requesting server options" - }, - "syncstate.prepare.request.provision": { - "message": "Requesting provision" - }, - "syncstate.prepare.request.remotechanges": { - "message": "Requesting remote changes" - }, - "syncstate.prepare.request.revertlocalchanges": { - "message": "Collecting local changes" - }, - "syncstate.prepare.request.setdeviceinfo": { - "message": "Sending device information" - }, - "syncstate.prepare.request.synckey": { - "message": "Requesting SyncKey" - }, - "syncstate.preparing": { - "message": "Preparing next item for synchronization" - }, - "syncstate.send.request.autodiscover": { - "message": "Waiting for updated server settings" - }, - "syncstate.send.request.deletefolder": { - "message": "Waiting for folder to be deleted" - }, - "syncstate.send.request.estimate": { - "message": "Waiting for change estimate" - }, - "syncstate.send.request.folders": { - "message": "Waiting for folder list update" - }, - "syncstate.send.request.localchanges": { - "message": "Waiting for acknowledgment of local changes" - }, - "syncstate.send.request.localdeletes": { - "message": "Waiting for acknowledgment of local deletes" - }, - "syncstate.send.request.options": { - "message": "Waiting for server options" - }, - "syncstate.send.request.provision": { - "message": "Waiting for provision" - }, - "syncstate.send.request.remotechanges": { - "message": "Waiting for remote changes" - }, - "syncstate.send.request.revertlocalchanges": { - "message": "Waiting for most recent versions" - }, - "syncstate.send.request.setdeviceinfo": { - "message": "Sending device information" - }, - "syncstate.send.request.synckey": { - "message": "Waiting for SyncKey" - }, - "syncstate.syncing": { - "message": "Initialize synchronization" - } -} +{ + "abCard.Anniversary": { + "message": "Anniversary:" + }, + "abCard.AssistantName": { + "message": "Assistant:" + }, + "abCard.AssistantPhoneNumber": { + "message": "Assistant Phone:" + }, + "abCard.Business2PhoneNumber": { + "message": "Work Alternative Phone:" + }, + "abCard.BusinessFaxNumber": { + "message": "Work Fax:" + }, + "abCard.CarPhoneNumber": { + "message": "Car Phone:" + }, + "abCard.CompanyMainPhone": { + "message": "Work Main Phone:" + }, + "abCard.Email3Address": { + "message": "Alternative Email:" + }, + "abCard.Home2PhoneNumber": { + "message": "Home Alternative Phone:" + }, + "abCard.ManagerName": { + "message": "Manager:" + }, + "abCard.MiddleName": { + "message": "Middle name:" + }, + "abCard.OtherAddress": { + "message": "Address:" + }, + "abCard.OtherCity": { + "message": "City:" + }, + "abCard.OtherCountry": { + "message": "Country:" + }, + "abCard.OtherState": { + "message": "State:" + }, + "abCard.OtherZip": { + "message": "ZIP Code:" + }, + "abCard.RadioPhoneNumber": { + "message": "Radio Phone:" + }, + "abCard.Spouse": { + "message": "Spouse:" + }, + "abCard.header.eas": { + "message": "Other Fields (EAS)" + }, + "abCard.header.homenumbers": { + "message": "Additional home numbers:" + }, + "abCard.header.messaging": { + "message": "Messaging:" + }, + "abCard.header.otheraddress": { + "message": "Other Address (EAS)" + }, + "abCard.header.othernumbers": { + "message": "Additional numbers:" + }, + "abCard.header.people": { + "message": "People:" + }, + "abCard.header.worknumbers": { + "message": "Additional work numbers:" + }, + "acl.readonly": { + "message": "Read-only server access (revert local changes)" + }, + "acl.readwrite": { + "message": "Read from and write to server" + }, + "add.description": { + "message": "Please select one of the available server configuration options and enter the requested details. " + }, + "add.name": { + "message": "Account name:" + }, + "add.ok": { + "message": "Add account" + }, + "add.password": { + "message": "Password:" + }, + "add.server": { + "message": "Server configuration:" + }, + "add.shortdescription": { + "message": "Account information" + }, + "add.title": { + "message": "Adding an Exchange ActiveSync account to TbSync" + }, + "add.url": { + "message": "Server address:" + }, + "add.urldescription": { + "message": "It should be sufficient to provide just the basic server address (e.g.: mail.yourserver.com). However, it is also possible to provide the full URL (e.g.: https://mail.yourserver.com/Microsoft-Server-ActiveSync)." + }, + "add.user": { + "message": "User name (email address):" + }, + "autocomplete.serverdirectory": { + "message": "global server directory" + }, + "autodiscover.Failed": { + "message": "Autodiscover for user <##user##> failed. Either the provided credentials were wrong or your ActiveSync provider has a temporary issue, or does not support Autodiscover." + }, + "autodiscover.NeedEmail": { + "message": "Autodiscover needs a valid email address as user name." + }, + "autodiscover.Ok": { + "message": "Autodiscover completed successfully, you can now check the optional settings and establish the synchronization connection." + }, + "autodiscover.Querying": { + "message": "Searching for settings…" + }, + "config.auto": { + "message": "ActiveSync server configuration (Autodiscover)" + }, + "config.custom": { + "message": "ActiveSync server configuration" + }, + "deletefolder.confirm": { + "message": "Do you really want to PERMANENTLY PURGE folder “##replace.1##” from trash?" + }, + "deletefolder.menuentry": { + "message": "Permanently purge folder “##replace.1##” from trash" + }, + "deletefolder.notallowed": { + "message": "Please unsubscribe folder “##replace.1##” before trying to purge it from trash." + }, + "extensionDescription": { + "message": "Add sync support for Exchange ActiveSync accounts to TbSync (contacts, tasks and calendars)." + }, + "extensionName": { + "message": "Provider for Exchange ActiveSync" + }, + "helplink.BadItemSkipped": { + "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped" + }, + "helplink.global.clientdenied": { + "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F" + }, + "helplink.security": { + "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F" + }, + "manager.tabs.accountsettings": { + "message": "Account settings" + }, + "manager.tabs.outOfOffice": { + "message": "Auto responder" + }, + "manager.tabs.syncsettings": { + "message": "Options" + }, + "newaccount.add_auto": { + "message": "Autodiscover settings and add account" + }, + "newaccount.add_custom": { + "message": "Add account" + }, + "pref.AccountName": { + "message": "Description" + }, + "pref.ActiveSyncVersion": { + "message": "ActiveSync version" + }, + "pref.DeviceId": { + "message": "ActiveSync device ID" + }, + "pref.ServerName": { + "message": "Server address" + }, + "pref.ServerNameDescription": { + "message": "e.g. mail.yourserver.com" + }, + "pref.ShowTrashedFolders": { + "message": "Show folders found in trash" + }, + "pref.UserName": { + "message": "User name" + }, + "pref.UserNameDescription": { + "message": "User name is usually the email address of your account." + }, + "pref.autodetect": { + "message": "best available" + }, + "pref.birthday": { + "message": "Send birthday information" + }, + "pref.calendaroptions": { + "message": "Calendar options" + }, + "pref.contactoptions": { + "message": "Contact options" + }, + "pref.displayoverride": { + "message": "Override Display Name with “First Name” + “Second Name”" + }, + "pref.generaloptions": { + "message": "General options" + }, + "pref.provision": { + "message": "Enforce provisioning (required by Kerio)" + }, + "pref.seperator.comma": { + "message": "Comma" + }, + "pref.seperator.description": { + "message": "Separator for multiline address field." + }, + "pref.seperator.linebreak": { + "message": "Line break" + }, + "pref.synclimit.1month": { + "message": "from 4 weeks ago" + }, + "pref.synclimit.2weeks": { + "message": "from 2 weeks ago" + }, + "pref.synclimit.3month": { + "message": "from 3 months ago" + }, + "pref.synclimit.6month": { + "message": "from 6 months ago" + }, + "pref.synclimit.all": { + "message": "everything" + }, + "pref.synclimit.description": { + "message": "Synchronization period: " + }, + "pref.usehttps": { + "message": "Use secure connection (connect via https)" + }, + "recyclebin": { + "message": "Trash" + }, + "servertype.auto": { + "message": "Automatic configuration" + }, + "servertype.custom": { + "message": "Custom configuration" + }, + "servertype.description.auto": { + "message": "The configuration for many ActiveSync servers can be discovered by providing just your email address." + }, + "servertype.description.custom": { + "message": "Setup your account by manually providing the address of the server you want to connect." + }, + "servertype.description.office365": { + "message": "Accounts connected to Office 365 use a modern authentication process called OAuth 2.0 which also supports Multi-Factor-Authentication (MFA)." + }, + "servertype.office365": { + "message": "Microsoft Office 365" + }, + "servertype.unlock": { + "message": "Double click to unlock all predefined server settings." + }, + "status.401": { + "message": "Could not authenticate, check username and password (HTTP Error 401)." + }, + "status.403": { + "message": "Server rejected connection (forbidden) (HTTP Error 403)." + }, + "status.404": { + "message": "User not found (HTTP Error 404)." + }, + "status.449": { + "message": "Server requests provisioning (HTTP Error 449)." + }, + "status.500": { + "message": "Unknown Server Error (HTTP Error 500)." + }, + "status.503": { + "message": "Service unavailable (HTTP Error 503)." + }, + "status.BadItemSkipped": { + "message": "Bad Item Skipped: ##replace.1##" + }, + "status.FolderDelete.3": { + "message": "Cannot delete a system folder (status 3)" + }, + "status.FolderDelete.4": { + "message": "Folder does not exist (status 4), resyncing" + }, + "status.FolderDelete.6": { + "message": "Command could not be completed, an error occurred on the server (status 6)" + }, + "status.FolderDelete.9": { + "message": "Invalid synchronization key (status 9), resyncing" + }, + "status.FolderSync.9": { + "message": "Invalid synchronization key (status 9), resyncing" + }, + "status.InvalidServerOptions": { + "message": "The server does not provide information about the supported ActiveSync versions. Is EAS blocked for this user or this client (TbSync)? You could try to set the ActiveSync version manually." + }, + "status.OK": { + "message": "OK" + }, + "status.ServerRejectedRequest": { + "message": "The EAS Server rejected the last request." + }, + "status.ServerRejectedSomeItems": { + "message": "The EAS server did not accept ##replace.1## elements." + }, + "status.Sync.12": { + "message": "Folder hierarchy changed (status 12), resyncing" + }, + "status.Sync.3": { + "message": "Invalid synchronization key (status 3), resyncing" + }, + "status.Sync.4": { + "message": "Malformed request (status 4)" + }, + "status.Sync.5": { + "message": "Temporary server issues or invalid item (status 5)" + }, + "status.Sync.6": { + "message": "Invalid item (status 6)" + }, + "status.Sync.8": { + "message": "Object not found (status 8)" + }, + "status.aborted": { + "message": "Not synchronized" + }, + "status.disabled": { + "message": "Disabled" + }, + "status.empty-response": { + "message": "Server sends unexpected empty response." + }, + "status.forbiddenCalendarItemInTasksFolder": { + "message": "Forbidden calendar item in a task folder (please resort)" + }, + "status.forbiddenTasksItemInCalendarFolder": { + "message": "Forbidden task item in a calendar folder (please resort)" + }, + "status.global.101": { + "message": "The request contains WBXML but it could not be decoded into XML (EAS Error 101)." + }, + "status.global.102": { + "message": "The request contains WBXML but it could not be decoded into XML (EAS Error 102)." + }, + "status.global.103": { + "message": "The XML provided in the request does not follow the protocol requirements (EAS Error 103)." + }, + "status.global.110": { + "message": "The server reported an internal error and we should not retry immediately. Automatic periodic sync has been disabled for 30 minutes (EAS Error 110)." + }, + "status.global.clientdenied": { + "message": "The EAS server reports <##replace.2##> (status ##replace.1##) and does not allow TbSync to access your account." + }, + "status.httperror": { + "message": "Communication error (HTTP status ##replace.1##)." + }, + "status.invalid": { + "message": "Invalid server response (junk)." + }, + "status.malformed-xml": { + "message": "Could not parse XML. Check event log for details." + }, + "status.modified": { + "message": "Local modifications" + }, + "status.network": { + "message": "Could not connect to server (##replace.1##)." + }, + "status.networkerror": { + "message": "Could not connect to server." + }, + "status.nosupportedeasversion": { + "message": "Server does not support ActiveSync v2.5 or v14.0 (only ##replace.1##). TbSync will not work with this ActiveSync server." + }, + "status.notargets": { + "message": "Aborting Sync, because sync targets could not be created." + }, + "status.notsupportedeasversion": { + "message": "Server does not support selected ActiveSync v##replace.1## (only ##replace.2##)." + }, + "status.notsyncronized": { + "message": "Account needs to be synchronized, at least one item is out of sync." + }, + "status.nouserhost": { + "message": "Missing username and/or server. Please provide those values." + }, + "status.pending": { + "message": "Waiting to be synchronized" + }, + "status.policy.2": { + "message": "There is no policy for this client. Contact your server administrator or disable provisioning for this account." + }, + "status.policy.3": { + "message": "Unknown PolicyType value. Contact your server administrator or disable provisioning for this account." + }, + "status.policy.4": { + "message": "The policy data on the server is corrupted (possibly tampered with). Contact your server administrator or disable provisioning for this account." + }, + "status.policy.5": { + "message": "The client is acknowledging the wrong policy key. Contact your server administrator or disable provisioning for this account." + }, + "status.provision": { + "message": "Provisioning failed with status <##replace.1##>" + }, + "status.response-contains-no-data": { + "message": "Response from the server contains no data." + }, + "status.resync-loop": { + "message": "There was an error from which we could not recover by resyncing the account. Please disable the account and try again. (Error: resync loop)" + }, + "status.security": { + "message": "Could not establish a secure connection. Are you using a self-signed or otherwise untrusted certificate without importing it into Thunderbird? (##replace.1##)" + }, + "status.skipped": { + "message": "Not yet supported, skipped" + }, + "status.syncing": { + "message": "Synchronizing" + }, + "status.timeout": { + "message": "Communication timeout." + }, + "status.wbxml-parse-error": { + "message": "Server sends unreadable response." + }, + "status.wbxmlerror": { + "message": "Sync failed. Server responded with status <##replace.1##>." + }, + "status.wbxmlmissingfield": { + "message": "ActiveSync protocol violation: Mandatory field <##replace.1##> is missing from server response." + }, + "syncstate.accountdone": { + "message": "Finished account" + }, + "syncstate.done": { + "message": "Preparing next item for synchronization" + }, + "syncstate.eval.response.autodiscover": { + "message": "Processing updated server settings" + }, + "syncstate.eval.response.deletefolder": { + "message": "Folder deleted" + }, + "syncstate.eval.response.estimate": { + "message": "Processing change estimate" + }, + "syncstate.eval.response.folders": { + "message": "Processing folder list update" + }, + "syncstate.eval.response.localchanges": { + "message": "Processing acknowledgment of local changes" + }, + "syncstate.eval.response.localdeletes": { + "message": "Processing acknowledgment of local deletes" + }, + "syncstate.eval.response.options": { + "message": "Processing server options" + }, + "syncstate.eval.response.provision": { + "message": "Processing provision" + }, + "syncstate.eval.response.remotechanges": { + "message": "Processing remote changes" + }, + "syncstate.eval.response.revertlocalchanges": { + "message": "Reverting local changes" + }, + "syncstate.eval.response.setdeviceinfo": { + "message": "Sending device information" + }, + "syncstate.eval.response.synckey": { + "message": "Processing SyncKey" + }, + "syncstate.prepare.request.autodiscover": { + "message": "Requesting updated server settings" + }, + "syncstate.prepare.request.deletefolder": { + "message": "Preparing to delete folder" + }, + "syncstate.prepare.request.estimate": { + "message": "Requesting change estimate" + }, + "syncstate.prepare.request.folders": { + "message": "Sending folder list update" + }, + "syncstate.prepare.request.localchanges": { + "message": "Sending local changes" + }, + "syncstate.prepare.request.localdeletes": { + "message": "Sending local deletes" + }, + "syncstate.prepare.request.options": { + "message": "Requesting server options" + }, + "syncstate.prepare.request.provision": { + "message": "Requesting provision" + }, + "syncstate.prepare.request.remotechanges": { + "message": "Requesting remote changes" + }, + "syncstate.prepare.request.revertlocalchanges": { + "message": "Collecting local changes" + }, + "syncstate.prepare.request.setdeviceinfo": { + "message": "Sending device information" + }, + "syncstate.prepare.request.synckey": { + "message": "Requesting SyncKey" + }, + "syncstate.preparing": { + "message": "Preparing next item for synchronization" + }, + "syncstate.send.request.autodiscover": { + "message": "Waiting for updated server settings" + }, + "syncstate.send.request.deletefolder": { + "message": "Waiting for folder to be deleted" + }, + "syncstate.send.request.estimate": { + "message": "Waiting for change estimate" + }, + "syncstate.send.request.folders": { + "message": "Waiting for folder list update" + }, + "syncstate.send.request.localchanges": { + "message": "Waiting for acknowledgment of local changes" + }, + "syncstate.send.request.localdeletes": { + "message": "Waiting for acknowledgment of local deletes" + }, + "syncstate.send.request.options": { + "message": "Waiting for server options" + }, + "syncstate.send.request.provision": { + "message": "Waiting for provision" + }, + "syncstate.send.request.remotechanges": { + "message": "Waiting for remote changes" + }, + "syncstate.send.request.revertlocalchanges": { + "message": "Waiting for most recent versions" + }, + "syncstate.send.request.setdeviceinfo": { + "message": "Sending device information" + }, + "syncstate.send.request.synckey": { + "message": "Waiting for SyncKey" + }, + "syncstate.syncing": { + "message": "Initialize synchronization" + } +} diff -Nru eas4tbsync-4.11/_locales/cs/messages.json eas4tbsync-4.17/_locales/cs/messages.json --- eas4tbsync-4.11/_locales/cs/messages.json 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/_locales/cs/messages.json 2025-05-15 11:21:18.000000000 +0000 @@ -1,566 +1,566 @@ -{ - "abCard.Anniversary": { - "message": "Výročí:" - }, - "abCard.AssistantName": { - "message": "Asistent:" - }, - "abCard.AssistantPhoneNumber": { - "message": "Telefon asistenta:" - }, - "abCard.Business2PhoneNumber": { - "message": "Alternativní telefon do práce:" - }, - "abCard.BusinessFaxNumber": { - "message": "Fax do práce:" - }, - "abCard.CarPhoneNumber": { - "message": "Telefon do auta:" - }, - "abCard.CompanyMainPhone": { - "message": "Hlavní pracovní telefon:" - }, - "abCard.Email3Address": { - "message": "Alternativní e-mail:" - }, - "abCard.Home2PhoneNumber": { - "message": "Alternativní telefon domů:" - }, - "abCard.ManagerName": { - "message": "Manažer:" - }, - "abCard.MiddleName": { - "message": "Prostřední jméno:" - }, - "abCard.OtherAddress": { - "message": "Adresa:" - }, - "abCard.OtherCity": { - "message": "Město:" - }, - "abCard.OtherCountry": { - "message": "Země:" - }, - "abCard.OtherState": { - "message": "Stát:" - }, - "abCard.OtherZip": { - "message": "PSČ:" - }, - "abCard.RadioPhoneNumber": { - "message": "Radiotelefon:" - }, - "abCard.Spouse": { - "message": "Manžel(ka):" - }, - "abCard.header.eas": { - "message": "Další údaje (EAS)" - }, - "abCard.header.homenumbers": { - "message": "Další čísla domů:" - }, - "abCard.header.messaging": { - "message": "Zprávy:" - }, - "abCard.header.otheraddress": { - "message": "Další adresa (EAS)" - }, - "abCard.header.othernumbers": { - "message": "Další čísla:" - }, - "abCard.header.people": { - "message": "Lidé:" - }, - "abCard.header.worknumbers": { - "message": "Další čísla do práce:" - }, - "acl.readonly": { - "message": "Přistup na server pouze pro čtení (odstranit místní změny)" - }, - "acl.readwrite": { - "message": "Přístup na server pro čtení i zápis" - }, - "add.description": { - "message": "Vyberte prosím jednu z dostupných možností konfigurace serveru a zadejte požadované podrobnosti. " - }, - "add.name": { - "message": "Název účtu:" - }, - "add.ok": { - "message": "Přidat účet" - }, - "add.password": { - "message": "Heslo:" - }, - "add.server": { - "message": "Nastavení serveru:" - }, - "add.shortdescription": { - "message": "Informace o účtu" - }, - "add.title": { - "message": "Přidání nového účtu Exchange ActiveSync do TbSync" - }, - "add.url": { - "message": "Adresa serveru:" - }, - "add.urldescription": { - "message": "Mělo by stačit zadat pouze adresu serveru (např. mail.mujmail.cz). Nicméně můžete zadat i celou URL (např. https://mail.mujmail.cz/Microsoft-Server-ActiveSync)." - }, - "add.user": { - "message": "Uživatelské jméno (e-mailová adresa):" - }, - "autocomplete.serverdirectory": { - "message": "globální adresář serveru" - }, - "autodiscover.Failed": { - "message": "Automatické nastavení pro uživatele <##user##> selhalo. Buď nejsou zadané přihlašovací údaje správné, nebo má váš poskytovatel ActiveSync dočasný problém, anebo nepodporuje automatické nastavení." - }, - "autodiscover.NeedEmail": { - "message": "Funkce automatického nastavení Autodiscover vyžaduje zadání platné e-mailové adresy jako uživatelského jména." - }, - "autodiscover.Ok": { - "message": "Automatické nastavení bylo úspěšně dokončeno. Nyní si můžete projít volitelné nastavení a vytvořit synchronizační připojení." - }, - "autodiscover.Querying": { - "message": "Hledám nastavení…" - }, - "config.auto": { - "message": "Konfigurace serveru ActiveSync (Autodiscover)" - }, - "config.custom": { - "message": "Konfigurace serveru ActiveSync" - }, - "deletefolder.confirm": { - "message": "Opravdu chcete z koše TRVALE vymazat složku “##replace.1##”?" - }, - "deletefolder.menuentry": { - "message": "Trvale z koše vymazat složku “##replace.1##”" - }, - "deletefolder.notallowed": { - "message": "Prosím, odhlašte odběr složky “##replace.1##“ předtím, než se ji pokusíte odstranit z koše." - }, - "extensionDescription": { - "message": "Přidává do TbSync podporu synchronizace pro účty Exchange ActiveSync (kontakty, úkoly a kalendáře)." - }, - "extensionName": { - "message": "Modul poskytovatele pro Exchange ActiveSync" - }, - "helplink.BadItemSkipped": { - "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped" - }, - "helplink.global.clientdenied": { - "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F" - }, - "helplink.security": { - "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F" - }, - "manager.tabs.accountsettings": { - "message": "Nastavení účtu" - }, - "manager.tabs.outOfOffice": { - "message": "Automatická odpověď" - }, - "manager.tabs.syncsettings": { - "message": "Volby" - }, - "newaccount.add_auto": { - "message": "Vyhledat nastavení a přidat účet" - }, - "newaccount.add_custom": { - "message": "Přidat účet" - }, - "pref.AccountName": { - "message": "Pojmenování" - }, - "pref.ActiveSyncVersion": { - "message": "Verze ActiveSync" - }, - "pref.DeviceId": { - "message": "ID zařízení ActiveSync" - }, - "pref.ServerName": { - "message": "Adresa serveru" - }, - "pref.ServerNameDescription": { - "message": "např. mail.mujmail.cz" - }, - "pref.ShowTrashedFolders": { - "message": "Zobrazit složky nalezené v koši" - }, - "pref.UserName": { - "message": "Uživatelské jméno" - }, - "pref.UserNameDescription": { - "message": "Uživatelské jméno je obvykle e-mailová adresa vašeho účtu." - }, - "pref.autodetect": { - "message": "nejlepší možná" - }, - "pref.birthday": { - "message": "Odeslat informace o narozeninách" - }, - "pref.calendaroptions": { - "message": "Nastavení kalendáře" - }, - "pref.contactoptions": { - "message": "Kontakty" - }, - "pref.displayoverride": { - "message": "Vynutit zobrazování jména jako “křestní” + “příjmení”" - }, - "pref.generaloptions": { - "message": "Obecné" - }, - "pref.provision": { - "message": "Vynutit provisioning (vyžaduje Kerio)" - }, - "pref.seperator.comma": { - "message": "Čárka" - }, - "pref.seperator.description": { - "message": "Oddělovač pro víceřádkové pole adres." - }, - "pref.seperator.linebreak": { - "message": "Nový řádek" - }, - "pref.synclimit.1month": { - "message": "poslední 4 týdny" - }, - "pref.synclimit.2weeks": { - "message": "poslední 2 týdny" - }, - "pref.synclimit.3month": { - "message": "poslední 3 měsíce" - }, - "pref.synclimit.6month": { - "message": "posledních 6 měsíců" - }, - "pref.synclimit.all": { - "message": "vše" - }, - "pref.synclimit.description": { - "message": "Období pro synchronizaci: " - }, - "pref.usehttps": { - "message": "Použít zabezpečené připojení (přes https)" - }, - "recyclebin": { - "message": "Koš" - }, - "servertype.auto": { - "message": "Automatické nastavení pomocí ActiveSync Autodiscover" - }, - "servertype.custom": { - "message": "Ruční nastavení" - }, - "servertype.description.auto": { - "message": "Pro nastavení většiny ActiveSync serverů stačí zadat pouze e-mailovou adresu." - }, - "servertype.description.custom": { - "message": "Nastavte si účet pomocí ručního zadání adresy serveru." - }, - "servertype.description.office365": { - "message": "Účty Office 365 používají moderní proces ověřování s názvem OAuth 2.0, který také podporuje vícefaktorové ověřování (MFA)." - }, - "servertype.office365": { - "message": "Microsoft Office 365" - }, - "servertype.unlock": { - "message": "Dvojklikem odemknete všechna předdefinovaná nastavení serveru." - }, - "status.401": { - "message": "Chyba ověření, zkontrolujte uživatelské jméno a heslo (HTTP chyba 401)." - }, - "status.403": { - "message": "Server odmítl spojení (HTTP chyba 403)." - }, - "status.404": { - "message": "Uživatel nebyl nalezen (HTTP chyba 404)." - }, - "status.449": { - "message": "Server si vyžádal provisioning (HTTP chyba 449)." - }, - "status.500": { - "message": "Neznámá chyba serveru (HTTP chyba 500)." - }, - "status.503": { - "message": "Služba není dostupná (HTTP chyba 503)." - }, - "status.BadItemSkipped": { - "message": "Vynechána chybná položka: ##replace.1##" - }, - "status.FolderDelete.3": { - "message": "Systémovou složku nelze odstranit (status 3)" - }, - "status.FolderDelete.4": { - "message": "Složka neexistuje (status 4), opětovně synchronizuji" - }, - "status.FolderDelete.6": { - "message": "Příkaz nemohl být dokončen, došlo k chybě na serveru (status 6)" - }, - "status.FolderDelete.9": { - "message": "Neplatný synchronizační klíč (status 9), opětovně synchronizuji" - }, - "status.FolderSync.9": { - "message": "Neplatný synchronizační klíč (status 9), opětovně synchronizuji" - }, - "status.InvalidServerOptions": { - "message": "Server neposkytuje informaci o podporovaných verzích ActiveSync. Je pro tohoto uživatele nebo tohoto klienta (TbSync) EAS blokován? Můžete zkusit nastavit verzi ActiveSync ručně." - }, - "status.OK": { - "message": "OK" - }, - "status.ServerRejectedRequest": { - "message": "EAS Server poslední požadavek odmítl." - }, - "status.ServerRejectedSomeItems": { - "message": "Server EAS nepřijal ##replace.1## položek." - }, - "status.Sync.12": { - "message": "Změnila se struktura složky (status 12), opětovně synchronizuji" - }, - "status.Sync.3": { - "message": "Neplatný synchronizační klíč (status 3), opětovně synchronizuji" - }, - "status.Sync.4": { - "message": "Chybný požadavek (status 4)" - }, - "status.Sync.5": { - "message": "Dočasné potíže na serveru nebo neplatná položka (status 5)" - }, - "status.Sync.6": { - "message": "Neplatná položka (status 6)" - }, - "status.Sync.8": { - "message": "Objekt nebyl nalezen (status 8)" - }, - "status.aborted": { - "message": "Není synchronizováno" - }, - "status.disabled": { - "message": "Zakázáno" - }, - "status.empty-response": { - "message": "Server zaslal odpověď bez obsahu." - }, - "status.forbiddenCalendarItemInTasksFolder": { - "message": "V seznamu úkolů máte uložený záznam, který má patřit do kalendáře (prosím, přesuňte jej)" - }, - "status.forbiddenTasksItemInCalendarFolder": { - "message": "V kalendáři máte uložený záznam, který má patřit mezi úkoly (prosím, přesuňte jej)" - }, - "status.global.101": { - "message": "Požadavek obsahuje WBXML, ale nemohl být dekódován do XML (EAS chyba 101)." - }, - "status.global.102": { - "message": "Požadavek obsahuje WBXML, ale nemohl být dekódován do XML (EAS chyba 102)." - }, - "status.global.103": { - "message": "Poskytnuté XML data neodpovídají požadavkům protokolu (EAS chyba 103)." - }, - "status.global.110": { - "message": "Server nahlásil interní chybu, automatická synchronizace byla pozastavena na 30 minut (EAS chyba 110)." - }, - "status.global.clientdenied": { - "message": "EAS server nahlásil <##replace.2##> (status ##replace.1##) a nepovolil pro TbSync přístup k účtu." - }, - "status.httperror": { - "message": "Chyba komunikace (HTTP status ##replace.1##)." - }, - "status.invalid": { - "message": "Neplatná odpověď serveru." - }, - "status.malformed-xml": { - "message": "Nelze zpracovat XML. Podrobnosti naleznete v protokolu událostí." - }, - "status.modified": { - "message": "Místní změny" - }, - "status.network": { - "message": "Nelze se připojit k serveru (##replace.1##)." - }, - "status.networkerror": { - "message": "Nelze se připojit k serveru." - }, - "status.nosupportedeasversion": { - "message": "Server nepodporuje ActiveSync v2.5 nebo v14.0 (pouze ##replace.1##). TbSync nepodporuje tento typ ActiveSync serveru." - }, - "status.notargets": { - "message": "Synchronizace byla přerušena, protože nebylo možné vytvořit cíle pro synchronizaci." - }, - "status.notsupportedeasversion": { - "message": "Server nepodporuje vybranou verzi ActiveSync v##replace.1## (pouze ##replace.2##)." - }, - "status.notsyncronized": { - "message": "Účet musí být synchronizován, alespoň jedna položka není synchronizována." - }, - "status.nouserhost": { - "message": "Uživatel a/nebo server nebyl zadán. Prosím, doplňte chybějící hodnoty." - }, - "status.pending": { - "message": "Čeká se na synchronizaci" - }, - "status.policy.2": { - "message": "Chybí zásady pro tohoto klienta. Kontaktujte administrátora nebo zakažte provisioning pro tento účet." - }, - "status.policy.3": { - "message": "Neznámá hodnota PolicyType. Kontaktujte administrátora nebo zakažte provisioning pro tento účet." - }, - "status.policy.4": { - "message": "Data zásad na serveru jsou porušená. Kontaktujte administrátora nebo zakažte provisioning pro tento účet." - }, - "status.policy.5": { - "message": "Klient přijal špatný klíč zásad. Kontaktujte administrátora nebo zakažte provisioning pro tento účet." - }, - "status.provision": { - "message": "Provisioning skončil chybou <##replace.1##>" - }, - "status.response-contains-no-data": { - "message": "Odpověď serveru neobsahovala data." - }, - "status.resync-loop": { - "message": "Nastala chyba, kterou není možné napravit pouze opětovnou synchronizací. Prosím, zakažte tento účet a zkuste to znovu. (Chyba: zacyklená synchronizace)" - }, - "status.security": { - "message": "Nelze navázat zabezpečené spojení. Používáte samopodepsaný nebo jinak nedůvěryhodný certifikát, aniž byste jej importovali do Thunderbirdu? (##replace.1##)" - }, - "status.skipped": { - "message": "Ještě není podporováno, přeskočeno" - }, - "status.syncing": { - "message": "Probíhá synchronizace" - }, - "status.timeout": { - "message": "Časový limit komunikace vypršel." - }, - "status.wbxml-parse-error": { - "message": "Odpověď serveru byla nečitelná." - }, - "status.wbxmlerror": { - "message": "Chyba synchronizace. Server hlásí status <##replace.1##>." - }, - "status.wbxmlmissingfield": { - "message": "Porušení protokolu ActiveSync: Vyžadované pole <##replace.1##> v odpovědi serveru chybí." - }, - "syncstate.accountdone": { - "message": "Synchronizace účtu dokončena" - }, - "syncstate.done": { - "message": "Příprava další položky na synchronizaci" - }, - "syncstate.eval.response.autodiscover": { - "message": "Zpracovávám aktualizované nastavení serveru" - }, - "syncstate.eval.response.deletefolder": { - "message": "Složka smazána" - }, - "syncstate.eval.response.estimate": { - "message": "Zpracovávám změnu odhadu" - }, - "syncstate.eval.response.folders": { - "message": "Zpracovávám aktualizaci seznamu složek" - }, - "syncstate.eval.response.localchanges": { - "message": "Zpracovávám potvrzení místních změn" - }, - "syncstate.eval.response.localdeletes": { - "message": "Zpracovávám potvrzení místních výmazů" - }, - "syncstate.eval.response.options": { - "message": "Zpracovávám možnosti serveru" - }, - "syncstate.eval.response.provision": { - "message": "Zpracovávám provision" - }, - "syncstate.eval.response.remotechanges": { - "message": "Zpracovávám změny ze serveru" - }, - "syncstate.eval.response.revertlocalchanges": { - "message": "Vracím zpět místní změny" - }, - "syncstate.eval.response.setdeviceinfo": { - "message": "Odesílám informace o zařízení" - }, - "syncstate.eval.response.synckey": { - "message": "Zpracovávám SyncKey" - }, - "syncstate.prepare.request.autodiscover": { - "message": "Žádám o aktualizované nastavení serveru" - }, - "syncstate.prepare.request.deletefolder": { - "message": "Připravuji vymazání složky" - }, - "syncstate.prepare.request.estimate": { - "message": "Žádám o změnu odhadu" - }, - "syncstate.prepare.request.folders": { - "message": "Odesílám aktualizaci seznamu složek" - }, - "syncstate.prepare.request.localchanges": { - "message": "Odesílám místní změny" - }, - "syncstate.prepare.request.localdeletes": { - "message": "Odesílám místní výmazy" - }, - "syncstate.prepare.request.options": { - "message": "Posílám požadavek na zaslání možností serveru" - }, - "syncstate.prepare.request.provision": { - "message": "Žádám o provision" - }, - "syncstate.prepare.request.remotechanges": { - "message": "Žádám o změny na serveru" - }, - "syncstate.prepare.request.revertlocalchanges": { - "message": "Shromažďuji místní změny" - }, - "syncstate.prepare.request.setdeviceinfo": { - "message": "Odesílám informace o zařízení" - }, - "syncstate.prepare.request.synckey": { - "message": "Žádám o SyncKey" - }, - "syncstate.preparing": { - "message": "Příprava další položky na synchronizaci" - }, - "syncstate.send.request.autodiscover": { - "message": "Čekám na aktualizované nastavení serveru" - }, - "syncstate.send.request.deletefolder": { - "message": "Čekám na vymazání složky" - }, - "syncstate.send.request.estimate": { - "message": "Čekám na změnu odhadu" - }, - "syncstate.send.request.folders": { - "message": "Čekám na aktualizaci seznamu složek" - }, - "syncstate.send.request.localchanges": { - "message": "Čekám na potvrzení místních změn" - }, - "syncstate.send.request.localdeletes": { - "message": "Čekám na potvrzení místních výmazů" - }, - "syncstate.send.request.options": { - "message": "Čekám na možnosti serveru" - }, - "syncstate.send.request.provision": { - "message": "Čekám na provision" - }, - "syncstate.send.request.remotechanges": { - "message": "Čekám na změny ze serveru" - }, - "syncstate.send.request.revertlocalchanges": { - "message": "Čekám na nejnovější verze" - }, - "syncstate.send.request.setdeviceinfo": { - "message": "Odesílám informace o zařízení" - }, - "syncstate.send.request.synckey": { - "message": "Čekám na SyncKey" - }, - "syncstate.syncing": { - "message": "Inicializuji synchronizaci" - } -} +{ + "abCard.Anniversary": { + "message": "Výročí:" + }, + "abCard.AssistantName": { + "message": "Asistent:" + }, + "abCard.AssistantPhoneNumber": { + "message": "Telefon asistenta:" + }, + "abCard.Business2PhoneNumber": { + "message": "Alternativní telefon do práce:" + }, + "abCard.BusinessFaxNumber": { + "message": "Fax do práce:" + }, + "abCard.CarPhoneNumber": { + "message": "Telefon do auta:" + }, + "abCard.CompanyMainPhone": { + "message": "Hlavní pracovní telefon:" + }, + "abCard.Email3Address": { + "message": "Alternativní e-mail:" + }, + "abCard.Home2PhoneNumber": { + "message": "Alternativní telefon domů:" + }, + "abCard.ManagerName": { + "message": "Manažer:" + }, + "abCard.MiddleName": { + "message": "Prostřední jméno:" + }, + "abCard.OtherAddress": { + "message": "Adresa:" + }, + "abCard.OtherCity": { + "message": "Město:" + }, + "abCard.OtherCountry": { + "message": "Země:" + }, + "abCard.OtherState": { + "message": "Stát:" + }, + "abCard.OtherZip": { + "message": "PSČ:" + }, + "abCard.RadioPhoneNumber": { + "message": "Radiotelefon:" + }, + "abCard.Spouse": { + "message": "Manžel(ka):" + }, + "abCard.header.eas": { + "message": "Další údaje (EAS)" + }, + "abCard.header.homenumbers": { + "message": "Další čísla domů:" + }, + "abCard.header.messaging": { + "message": "Zprávy:" + }, + "abCard.header.otheraddress": { + "message": "Další adresa (EAS)" + }, + "abCard.header.othernumbers": { + "message": "Další čísla:" + }, + "abCard.header.people": { + "message": "Lidé:" + }, + "abCard.header.worknumbers": { + "message": "Další čísla do práce:" + }, + "acl.readonly": { + "message": "Přistup na server pouze pro čtení (odstranit místní změny)" + }, + "acl.readwrite": { + "message": "Přístup na server pro čtení i zápis" + }, + "add.description": { + "message": "Vyberte prosím jednu z dostupných možností konfigurace serveru a zadejte požadované podrobnosti. " + }, + "add.name": { + "message": "Název účtu:" + }, + "add.ok": { + "message": "Přidat účet" + }, + "add.password": { + "message": "Heslo:" + }, + "add.server": { + "message": "Nastavení serveru:" + }, + "add.shortdescription": { + "message": "Informace o účtu" + }, + "add.title": { + "message": "Přidání nového účtu Exchange ActiveSync do TbSync" + }, + "add.url": { + "message": "Adresa serveru:" + }, + "add.urldescription": { + "message": "Mělo by stačit zadat pouze adresu serveru (např. mail.mujmail.cz). Nicméně můžete zadat i celou URL (např. https://mail.mujmail.cz/Microsoft-Server-ActiveSync)." + }, + "add.user": { + "message": "Uživatelské jméno (e-mailová adresa):" + }, + "autocomplete.serverdirectory": { + "message": "globální adresář serveru" + }, + "autodiscover.Failed": { + "message": "Automatické nastavení pro uživatele <##user##> selhalo. Buď nejsou zadané přihlašovací údaje správné, nebo má váš poskytovatel ActiveSync dočasný problém, anebo nepodporuje automatické nastavení." + }, + "autodiscover.NeedEmail": { + "message": "Funkce automatického nastavení Autodiscover vyžaduje zadání platné e-mailové adresy jako uživatelského jména." + }, + "autodiscover.Ok": { + "message": "Automatické nastavení bylo úspěšně dokončeno. Nyní si můžete projít volitelné nastavení a vytvořit synchronizační připojení." + }, + "autodiscover.Querying": { + "message": "Hledám nastavení…" + }, + "config.auto": { + "message": "Konfigurace serveru ActiveSync (Autodiscover)" + }, + "config.custom": { + "message": "Konfigurace serveru ActiveSync" + }, + "deletefolder.confirm": { + "message": "Opravdu chcete z koše TRVALE vymazat složku “##replace.1##”?" + }, + "deletefolder.menuentry": { + "message": "Trvale z koše vymazat složku “##replace.1##”" + }, + "deletefolder.notallowed": { + "message": "Prosím, odhlašte odběr složky “##replace.1##“ předtím, než se ji pokusíte odstranit z koše." + }, + "extensionDescription": { + "message": "Přidává do TbSync podporu synchronizace pro účty Exchange ActiveSync (kontakty, úkoly a kalendáře)." + }, + "extensionName": { + "message": "Modul poskytovatele pro Exchange ActiveSync" + }, + "helplink.BadItemSkipped": { + "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped" + }, + "helplink.global.clientdenied": { + "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F" + }, + "helplink.security": { + "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F" + }, + "manager.tabs.accountsettings": { + "message": "Nastavení účtu" + }, + "manager.tabs.outOfOffice": { + "message": "Automatická odpověď" + }, + "manager.tabs.syncsettings": { + "message": "Volby" + }, + "newaccount.add_auto": { + "message": "Vyhledat nastavení a přidat účet" + }, + "newaccount.add_custom": { + "message": "Přidat účet" + }, + "pref.AccountName": { + "message": "Pojmenování" + }, + "pref.ActiveSyncVersion": { + "message": "Verze ActiveSync" + }, + "pref.DeviceId": { + "message": "ID zařízení ActiveSync" + }, + "pref.ServerName": { + "message": "Adresa serveru" + }, + "pref.ServerNameDescription": { + "message": "např. mail.mujmail.cz" + }, + "pref.ShowTrashedFolders": { + "message": "Zobrazit složky nalezené v koši" + }, + "pref.UserName": { + "message": "Uživatelské jméno" + }, + "pref.UserNameDescription": { + "message": "Uživatelské jméno je obvykle e-mailová adresa vašeho účtu." + }, + "pref.autodetect": { + "message": "nejlepší možná" + }, + "pref.birthday": { + "message": "Odeslat informace o narozeninách" + }, + "pref.calendaroptions": { + "message": "Nastavení kalendáře" + }, + "pref.contactoptions": { + "message": "Kontakty" + }, + "pref.displayoverride": { + "message": "Vynutit zobrazování jména jako “křestní” + “příjmení”" + }, + "pref.generaloptions": { + "message": "Obecné" + }, + "pref.provision": { + "message": "Vynutit provisioning (vyžaduje Kerio)" + }, + "pref.seperator.comma": { + "message": "Čárka" + }, + "pref.seperator.description": { + "message": "Oddělovač pro víceřádkové pole adres." + }, + "pref.seperator.linebreak": { + "message": "Nový řádek" + }, + "pref.synclimit.1month": { + "message": "poslední 4 týdny" + }, + "pref.synclimit.2weeks": { + "message": "poslední 2 týdny" + }, + "pref.synclimit.3month": { + "message": "poslední 3 měsíce" + }, + "pref.synclimit.6month": { + "message": "posledních 6 měsíců" + }, + "pref.synclimit.all": { + "message": "vše" + }, + "pref.synclimit.description": { + "message": "Období pro synchronizaci: " + }, + "pref.usehttps": { + "message": "Použít zabezpečené připojení (přes https)" + }, + "recyclebin": { + "message": "Koš" + }, + "servertype.auto": { + "message": "Automatické nastavení pomocí ActiveSync Autodiscover" + }, + "servertype.custom": { + "message": "Ruční nastavení" + }, + "servertype.description.auto": { + "message": "Pro nastavení většiny ActiveSync serverů stačí zadat pouze e-mailovou adresu." + }, + "servertype.description.custom": { + "message": "Nastavte si účet pomocí ručního zadání adresy serveru." + }, + "servertype.description.office365": { + "message": "Účty Office 365 používají moderní proces ověřování s názvem OAuth 2.0, který také podporuje vícefaktorové ověřování (MFA)." + }, + "servertype.office365": { + "message": "Microsoft Office 365" + }, + "servertype.unlock": { + "message": "Dvojklikem odemknete všechna předdefinovaná nastavení serveru." + }, + "status.401": { + "message": "Chyba ověření, zkontrolujte uživatelské jméno a heslo (HTTP chyba 401)." + }, + "status.403": { + "message": "Server odmítl spojení (HTTP chyba 403)." + }, + "status.404": { + "message": "Uživatel nebyl nalezen (HTTP chyba 404)." + }, + "status.449": { + "message": "Server si vyžádal provisioning (HTTP chyba 449)." + }, + "status.500": { + "message": "Neznámá chyba serveru (HTTP chyba 500)." + }, + "status.503": { + "message": "Služba není dostupná (HTTP chyba 503)." + }, + "status.BadItemSkipped": { + "message": "Vynechána chybná položka: ##replace.1##" + }, + "status.FolderDelete.3": { + "message": "Systémovou složku nelze odstranit (status 3)" + }, + "status.FolderDelete.4": { + "message": "Složka neexistuje (status 4), opětovně synchronizuji" + }, + "status.FolderDelete.6": { + "message": "Příkaz nemohl být dokončen, došlo k chybě na serveru (status 6)" + }, + "status.FolderDelete.9": { + "message": "Neplatný synchronizační klíč (status 9), opětovně synchronizuji" + }, + "status.FolderSync.9": { + "message": "Neplatný synchronizační klíč (status 9), opětovně synchronizuji" + }, + "status.InvalidServerOptions": { + "message": "Server neposkytuje informaci o podporovaných verzích ActiveSync. Je pro tohoto uživatele nebo tohoto klienta (TbSync) EAS blokován? Můžete zkusit nastavit verzi ActiveSync ručně." + }, + "status.OK": { + "message": "OK" + }, + "status.ServerRejectedRequest": { + "message": "EAS Server poslední požadavek odmítl." + }, + "status.ServerRejectedSomeItems": { + "message": "Server EAS nepřijal ##replace.1## položek." + }, + "status.Sync.12": { + "message": "Změnila se struktura složky (status 12), opětovně synchronizuji" + }, + "status.Sync.3": { + "message": "Neplatný synchronizační klíč (status 3), opětovně synchronizuji" + }, + "status.Sync.4": { + "message": "Chybný požadavek (status 4)" + }, + "status.Sync.5": { + "message": "Dočasné potíže na serveru nebo neplatná položka (status 5)" + }, + "status.Sync.6": { + "message": "Neplatná položka (status 6)" + }, + "status.Sync.8": { + "message": "Objekt nebyl nalezen (status 8)" + }, + "status.aborted": { + "message": "Není synchronizováno" + }, + "status.disabled": { + "message": "Zakázáno" + }, + "status.empty-response": { + "message": "Server zaslal odpověď bez obsahu." + }, + "status.forbiddenCalendarItemInTasksFolder": { + "message": "V seznamu úkolů máte uložený záznam, který má patřit do kalendáře (prosím, přesuňte jej)" + }, + "status.forbiddenTasksItemInCalendarFolder": { + "message": "V kalendáři máte uložený záznam, který má patřit mezi úkoly (prosím, přesuňte jej)" + }, + "status.global.101": { + "message": "Požadavek obsahuje WBXML, ale nemohl být dekódován do XML (EAS chyba 101)." + }, + "status.global.102": { + "message": "Požadavek obsahuje WBXML, ale nemohl být dekódován do XML (EAS chyba 102)." + }, + "status.global.103": { + "message": "Poskytnuté XML data neodpovídají požadavkům protokolu (EAS chyba 103)." + }, + "status.global.110": { + "message": "Server nahlásil interní chybu, automatická synchronizace byla pozastavena na 30 minut (EAS chyba 110)." + }, + "status.global.clientdenied": { + "message": "EAS server nahlásil <##replace.2##> (status ##replace.1##) a nepovolil pro TbSync přístup k účtu." + }, + "status.httperror": { + "message": "Chyba komunikace (HTTP status ##replace.1##)." + }, + "status.invalid": { + "message": "Neplatná odpověď serveru." + }, + "status.malformed-xml": { + "message": "Nelze zpracovat XML. Podrobnosti naleznete v protokolu událostí." + }, + "status.modified": { + "message": "Místní změny" + }, + "status.network": { + "message": "Nelze se připojit k serveru (##replace.1##)." + }, + "status.networkerror": { + "message": "Nelze se připojit k serveru." + }, + "status.nosupportedeasversion": { + "message": "Server nepodporuje ActiveSync v2.5 nebo v14.0 (pouze ##replace.1##). TbSync nepodporuje tento typ ActiveSync serveru." + }, + "status.notargets": { + "message": "Synchronizace byla přerušena, protože nebylo možné vytvořit cíle pro synchronizaci." + }, + "status.notsupportedeasversion": { + "message": "Server nepodporuje vybranou verzi ActiveSync v##replace.1## (pouze ##replace.2##)." + }, + "status.notsyncronized": { + "message": "Účet musí být synchronizován, alespoň jedna položka není synchronizována." + }, + "status.nouserhost": { + "message": "Uživatel a/nebo server nebyl zadán. Prosím, doplňte chybějící hodnoty." + }, + "status.pending": { + "message": "Čeká se na synchronizaci" + }, + "status.policy.2": { + "message": "Chybí zásady pro tohoto klienta. Kontaktujte administrátora nebo zakažte provisioning pro tento účet." + }, + "status.policy.3": { + "message": "Neznámá hodnota PolicyType. Kontaktujte administrátora nebo zakažte provisioning pro tento účet." + }, + "status.policy.4": { + "message": "Data zásad na serveru jsou porušená. Kontaktujte administrátora nebo zakažte provisioning pro tento účet." + }, + "status.policy.5": { + "message": "Klient přijal špatný klíč zásad. Kontaktujte administrátora nebo zakažte provisioning pro tento účet." + }, + "status.provision": { + "message": "Provisioning skončil chybou <##replace.1##>" + }, + "status.response-contains-no-data": { + "message": "Odpověď serveru neobsahovala data." + }, + "status.resync-loop": { + "message": "Nastala chyba, kterou není možné napravit pouze opětovnou synchronizací. Prosím, zakažte tento účet a zkuste to znovu. (Chyba: zacyklená synchronizace)" + }, + "status.security": { + "message": "Nelze navázat zabezpečené spojení. Používáte samopodepsaný nebo jinak nedůvěryhodný certifikát, aniž byste jej importovali do Thunderbirdu? (##replace.1##)" + }, + "status.skipped": { + "message": "Ještě není podporováno, přeskočeno" + }, + "status.syncing": { + "message": "Probíhá synchronizace" + }, + "status.timeout": { + "message": "Časový limit komunikace vypršel." + }, + "status.wbxml-parse-error": { + "message": "Odpověď serveru byla nečitelná." + }, + "status.wbxmlerror": { + "message": "Chyba synchronizace. Server hlásí status <##replace.1##>." + }, + "status.wbxmlmissingfield": { + "message": "Porušení protokolu ActiveSync: Vyžadované pole <##replace.1##> v odpovědi serveru chybí." + }, + "syncstate.accountdone": { + "message": "Synchronizace účtu dokončena" + }, + "syncstate.done": { + "message": "Příprava další položky na synchronizaci" + }, + "syncstate.eval.response.autodiscover": { + "message": "Zpracovávám aktualizované nastavení serveru" + }, + "syncstate.eval.response.deletefolder": { + "message": "Složka smazána" + }, + "syncstate.eval.response.estimate": { + "message": "Zpracovávám změnu odhadu" + }, + "syncstate.eval.response.folders": { + "message": "Zpracovávám aktualizaci seznamu složek" + }, + "syncstate.eval.response.localchanges": { + "message": "Zpracovávám potvrzení místních změn" + }, + "syncstate.eval.response.localdeletes": { + "message": "Zpracovávám potvrzení místních výmazů" + }, + "syncstate.eval.response.options": { + "message": "Zpracovávám možnosti serveru" + }, + "syncstate.eval.response.provision": { + "message": "Zpracovávám provision" + }, + "syncstate.eval.response.remotechanges": { + "message": "Zpracovávám změny ze serveru" + }, + "syncstate.eval.response.revertlocalchanges": { + "message": "Vracím zpět místní změny" + }, + "syncstate.eval.response.setdeviceinfo": { + "message": "Odesílám informace o zařízení" + }, + "syncstate.eval.response.synckey": { + "message": "Zpracovávám SyncKey" + }, + "syncstate.prepare.request.autodiscover": { + "message": "Žádám o aktualizované nastavení serveru" + }, + "syncstate.prepare.request.deletefolder": { + "message": "Připravuji vymazání složky" + }, + "syncstate.prepare.request.estimate": { + "message": "Žádám o změnu odhadu" + }, + "syncstate.prepare.request.folders": { + "message": "Odesílám aktualizaci seznamu složek" + }, + "syncstate.prepare.request.localchanges": { + "message": "Odesílám místní změny" + }, + "syncstate.prepare.request.localdeletes": { + "message": "Odesílám místní výmazy" + }, + "syncstate.prepare.request.options": { + "message": "Posílám požadavek na zaslání možností serveru" + }, + "syncstate.prepare.request.provision": { + "message": "Žádám o provision" + }, + "syncstate.prepare.request.remotechanges": { + "message": "Žádám o změny na serveru" + }, + "syncstate.prepare.request.revertlocalchanges": { + "message": "Shromažďuji místní změny" + }, + "syncstate.prepare.request.setdeviceinfo": { + "message": "Odesílám informace o zařízení" + }, + "syncstate.prepare.request.synckey": { + "message": "Žádám o SyncKey" + }, + "syncstate.preparing": { + "message": "Příprava další položky na synchronizaci" + }, + "syncstate.send.request.autodiscover": { + "message": "Čekám na aktualizované nastavení serveru" + }, + "syncstate.send.request.deletefolder": { + "message": "Čekám na vymazání složky" + }, + "syncstate.send.request.estimate": { + "message": "Čekám na změnu odhadu" + }, + "syncstate.send.request.folders": { + "message": "Čekám na aktualizaci seznamu složek" + }, + "syncstate.send.request.localchanges": { + "message": "Čekám na potvrzení místních změn" + }, + "syncstate.send.request.localdeletes": { + "message": "Čekám na potvrzení místních výmazů" + }, + "syncstate.send.request.options": { + "message": "Čekám na možnosti serveru" + }, + "syncstate.send.request.provision": { + "message": "Čekám na provision" + }, + "syncstate.send.request.remotechanges": { + "message": "Čekám na změny ze serveru" + }, + "syncstate.send.request.revertlocalchanges": { + "message": "Čekám na nejnovější verze" + }, + "syncstate.send.request.setdeviceinfo": { + "message": "Odesílám informace o zařízení" + }, + "syncstate.send.request.synckey": { + "message": "Čekám na SyncKey" + }, + "syncstate.syncing": { + "message": "Inicializuji synchronizaci" + } +} diff -Nru eas4tbsync-4.11/_locales/de/messages.json eas4tbsync-4.17/_locales/de/messages.json --- eas4tbsync-4.11/_locales/de/messages.json 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/_locales/de/messages.json 2025-05-15 11:21:18.000000000 +0000 @@ -1,566 +1,566 @@ -{ - "abCard.Anniversary": { - "message": "Jubiläum:" - }, - "abCard.AssistantName": { - "message": "Assistent:" - }, - "abCard.AssistantPhoneNumber": { - "message": "Assistententelefon:" - }, - "abCard.Business2PhoneNumber": { - "message": "Telefon 2 Arbeit:" - }, - "abCard.BusinessFaxNumber": { - "message": "Fax Arbeit:" - }, - "abCard.CarPhoneNumber": { - "message": "Telefon Auto:" - }, - "abCard.CompanyMainPhone": { - "message": "Haupttelefon Arbeit:" - }, - "abCard.Email3Address": { - "message": "Alternative E-Mail:" - }, - "abCard.Home2PhoneNumber": { - "message": "Telefon 2 zu Hause:" - }, - "abCard.ManagerName": { - "message": "Manager:" - }, - "abCard.MiddleName": { - "message": "Zweiter Vorname:" - }, - "abCard.OtherAddress": { - "message": "Adresse:" - }, - "abCard.OtherCity": { - "message": "Stadt:" - }, - "abCard.OtherCountry": { - "message": "Land:" - }, - "abCard.OtherState": { - "message": "Bundesland:" - }, - "abCard.OtherZip": { - "message": "Postleitzahl:" - }, - "abCard.RadioPhoneNumber": { - "message": "Funktelefon:" - }, - "abCard.Spouse": { - "message": "Ehepartner:" - }, - "abCard.header.eas": { - "message": "Weitere Felder (EAS)" - }, - "abCard.header.homenumbers": { - "message": "Zusätzliche Nummern zu Hause:" - }, - "abCard.header.messaging": { - "message": "Nachrichten:" - }, - "abCard.header.otheraddress": { - "message": "Weitere Adresse (EAS)" - }, - "abCard.header.othernumbers": { - "message": "Zusätzliche Nummern:" - }, - "abCard.header.people": { - "message": "Personen:" - }, - "abCard.header.worknumbers": { - "message": "Zusätzliche Nummern Arbeit:" - }, - "acl.readonly": { - "message": "Serverzugriff nur lesend (verwerfe lokale Änderungen)" - }, - "acl.readwrite": { - "message": "Serverzugriff lesend und schreibend" - }, - "add.description": { - "message": "Bitte wählen Sie eine der verfügbaren Server-Konfigurationen aus und geben Sie die angeforderten Details ein. " - }, - "add.name": { - "message": "Kontoname:" - }, - "add.ok": { - "message": "Konto hinzufügen" - }, - "add.password": { - "message": "Passwort:" - }, - "add.server": { - "message": "Server Konfiguration:" - }, - "add.shortdescription": { - "message": "Kontoinformationen" - }, - "add.title": { - "message": "Exchange ActiveSync Konto hinzufügen" - }, - "add.url": { - "message": "Server Adresse:" - }, - "add.urldescription": { - "message": "Meist reicht die Angabe der einfachen Serveradresse (z.B.: mail.meinserver.de), alternativ kann aber auch die komplette URL angegeben werden (z.B.: https://mail.meinserver.de/Microsoft-Server-ActiveSync)." - }, - "add.user": { - "message": "Benutzername (E-Mail Adresse):" - }, - "autocomplete.serverdirectory": { - "message": "Globales Serververzeichnis" - }, - "autodiscover.Failed": { - "message": "Autodiscover für den Benutzer <##user##> war nicht erfolgreich. Entweder war das Passwort nicht korrekt, Ihr ActiveSync Server hat ein temporäres Problem oder unterstützt kein Autodiscover." - }, - "autodiscover.NeedEmail": { - "message": "Autodiscover benötigt eine gültige E-Mail Adresse als Benutzername." - }, - "autodiscover.Ok": { - "message": "Autodiscover war erfolgreich, Sie können nun die optionalen Einstellungen überprüfen und die Synchronisationsverbindung aktivieren." - }, - "autodiscover.Querying": { - "message": "Einstellungen werden gesucht ..." - }, - "config.auto": { - "message": "ActiveSync Server Konfiguration (Autodiscover)" - }, - "config.custom": { - "message": "ActiveSync Server Konfiguration" - }, - "deletefolder.confirm": { - "message": "Möchten Sie den Ordner '##replace.1##' wirklich ENDGÜLTIG aus dem Papierkorb ENTFERNEN?" - }, - "deletefolder.menuentry": { - "message": "Den Ordner '##replace.1##' endgültig aus dem Papierkorb entfernen" - }, - "deletefolder.notallowed": { - "message": "Bitte beenden Sie zunächst das Abonement des Ordner '##replace.1##', bevor Sie diesen aus dem Papierkorb entfernen." - }, - "extensionDescription": { - "message": "Erweitert TbSync und erlaubt die Synchronisation von Exchange ActiveSync Konten (Kontakte, Aufgaben und Kalender)." - }, - "extensionName": { - "message": "Provider für Exchange ActiveSync" - }, - "helplink.BadItemSkipped": { - "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped" - }, - "helplink.global.clientdenied": { - "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F" - }, - "helplink.security": { - "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F" - }, - "manager.tabs.accountsettings": { - "message": "Kontoeinstellungen" - }, - "manager.tabs.outOfOffice": { - "message": "Autoresponder" - }, - "manager.tabs.syncsettings": { - "message": "Optionen" - }, - "newaccount.add_auto": { - "message": "Einstellungen suchen und Konto hinzufügen" - }, - "newaccount.add_custom": { - "message": "Konto hinzufügen" - }, - "pref.AccountName": { - "message": "Kontoname" - }, - "pref.ActiveSyncVersion": { - "message": "ActiveSync Version" - }, - "pref.DeviceId": { - "message": "ActiveSync Geräte ID" - }, - "pref.ServerName": { - "message": "Server Adresse" - }, - "pref.ServerNameDescription": { - "message": "z.B. mail.meinserver.com" - }, - "pref.ShowTrashedFolders": { - "message": "Im Papierkorb gefundene Ordner anzeigen" - }, - "pref.UserName": { - "message": "Benutzername" - }, - "pref.UserNameDescription": { - "message": "Der Benutzername ist meistens die E-Mail Adresse Ihres Kontos." - }, - "pref.autodetect": { - "message": "bestmöglich" - }, - "pref.birthday": { - "message": "Sende Geburtstagsinformation" - }, - "pref.calendaroptions": { - "message": "Kalender Optionen" - }, - "pref.contactoptions": { - "message": "Kontakt Optionen" - }, - "pref.displayoverride": { - "message": "Überschreibe Anzeigename mit 'Vorname' + 'Nachname'" - }, - "pref.generaloptions": { - "message": "Allgemeine Optionen" - }, - "pref.provision": { - "message": "Provisionierung erzwingen (wird von Kerio benötigt)" - }, - "pref.seperator.comma": { - "message": "Komma" - }, - "pref.seperator.description": { - "message": "Separator für mehrzeilige Adressfelder: " - }, - "pref.seperator.linebreak": { - "message": "Zeilenumbruch" - }, - "pref.synclimit.1month": { - "message": "ab vor 4 Wochen" - }, - "pref.synclimit.2weeks": { - "message": "ab vor 2 Wochen" - }, - "pref.synclimit.3month": { - "message": "ab vor 3 Monaten" - }, - "pref.synclimit.6month": { - "message": "ab vor 6 Monaten" - }, - "pref.synclimit.all": { - "message": "alles" - }, - "pref.synclimit.description": { - "message": "Synchronisationszeitraum: " - }, - "pref.usehttps": { - "message": "Sichere Verbindungen verwenden (via https://)" - }, - "recyclebin": { - "message": "Papierkorb" - }, - "servertype.auto": { - "message": "Automatische Konfiguration" - }, - "servertype.custom": { - "message": "Benutzerspezifische Konfiguration" - }, - "servertype.description.auto": { - "message": "Die Konfiguration vieler ActiveSync Server kann allein durch die Angabe Ihrer E-Mail-Adresse erfolgen." - }, - "servertype.description.custom": { - "message": "Richten Sie Ihr Konto ein, indem Sie die Adresse des Servers angeben, mit dem Sie sich verbinden möchten." - }, - "servertype.description.office365": { - "message": "Konten, die mit Office 365 verbunden sind, verwenden den modernen OAuth 2.0 Authentifizierungsprozess, der auch Multi-Factor-Authentication (MFA) unterstützt." - }, - "servertype.office365": { - "message": "Microsoft Office 365" - }, - "servertype.unlock": { - "message": "Doppelklick um die vordefinierten Servereinstellungen zu entsperren." - }, - "status.401": { - "message": "Authentifizierung fehlgeschlagen, überprüfen Sie den Benutzernamen und das Passwort." - }, - "status.403": { - "message": "Verbindung vom Server abgelehnt (nicht erlaubt)." - }, - "status.404": { - "message": "Unbekanner Benutzer (HTTP Fehler 404)." - }, - "status.449": { - "message": "Server erwartet Provisionierung." - }, - "status.500": { - "message": "Unbekannter Server Fehler (HTTP Fehler 500)." - }, - "status.503": { - "message": "Service nicht erreichbar." - }, - "status.BadItemSkipped": { - "message": "Ein Element wurde nicht synchronisiert: ##replace.1##" - }, - "status.FolderDelete.3": { - "message": "Systemordner können nicht gelöscht werden." - }, - "status.FolderDelete.4": { - "message": "Ordner existiert nicht, es wird neu synchronisiert" - }, - "status.FolderDelete.6": { - "message": "Das Kommando konnte nicht abgeschlossen werden, auf dem Server ist ein Fehler aufgetreten." - }, - "status.FolderDelete.9": { - "message": "Ungültiger Synchronisationsschlüssel, es wird neu synchronisiert" - }, - "status.FolderSync.9": { - "message": "Ungültiger Synchronisationsschlüssel, es wird neu synchronisiert" - }, - "status.InvalidServerOptions": { - "message": "Der Server sendet keine Informationen zu den unterstützten ActiveSync Versionen. Ist EAS für diesen Benutzer bzw. für dieses Programm (TbSync) freigeschaltet? Sie können versuchen, die ActiveSync Version manuell festzulegen." - }, - "status.OK": { - "message": "Ok" - }, - "status.ServerRejectedRequest": { - "message": "Der EAS Server hat die letzte Anforderung zurückgewiesen." - }, - "status.ServerRejectedSomeItems": { - "message": "Der EAS Server hat ##replace.1## Elemente nicht akzeptiert." - }, - "status.Sync.12": { - "message": "Ordnerhierarchie hat sich geändert, es wird neu synchronisiert" - }, - "status.Sync.3": { - "message": "Ungültiger Synchronisationsschlüssel, es wird neu synchronisiert" - }, - "status.Sync.4": { - "message": "Fehlerhafte Anfrage (Status 4)" - }, - "status.Sync.5": { - "message": "Temporäres Serverproblem oder ungültiges Element (Status 5)" - }, - "status.Sync.6": { - "message": "Ungültiges Element (Status 6)" - }, - "status.Sync.8": { - "message": "Objekt nicht gefunden (Status 8)" - }, - "status.aborted": { - "message": "Nicht synchronisiert" - }, - "status.disabled": { - "message": "Konto ist deaktiviert, Synchronisation ist ausgeschaltet." - }, - "status.empty-response": { - "message": "Server sendet unerwartete leere Antwort." - }, - "status.forbiddenCalendarItemInTasksFolder": { - "message": "Unerlaubtes Kalender-Element in einem Aufgaben-Objekt (bitte umsortieren)" - }, - "status.forbiddenTasksItemInCalendarFolder": { - "message": "Unerlaubtes Aufgaben-Element in einem Kalender-Objekt (bitte umsortieren)" - }, - "status.global.101": { - "message": "Das WBXML der Anfrage konnte nicht in gültiges XML dekodiert werden (EAS Fehler 101)." - }, - "status.global.102": { - "message": "Das WBXML der Anfrage konnte nicht in gültiges XML dekodiert werden (EAS Fehler 102)." - }, - "status.global.103": { - "message": "Das XML der Anfrage entspricht nicht den Protokollanforderungen (EAS Fehler 103)." - }, - "status.global.110": { - "message": "Der Server meldet einen internen Fehler und es soll nicht unmittelbar ein erneuter Verbindungsaufbau durchgeführt werden. Die automatische periodische Synchronisation wird für 30 Minuten ausgesetzt (EAS Fehler 110)." - }, - "status.global.clientdenied": { - "message": "Der EAS Server antwortet mit <##replace.2##> (status ##replace.1##) und verweigert TbSync den Zugriff auf Ihr Konto." - }, - "status.httperror": { - "message": "Kommunikationsfehler (HTTP Status ##replace.1##)." - }, - "status.invalid": { - "message": "Ungültige Serverantwort." - }, - "status.malformed-xml": { - "message": "Antwort enthält fehlerhaftes XML, Sync angebrochen. Prüfen Sie bitte das Ereignisprotokoll für weitere Details." - }, - "status.modified": { - "message": "Lokale Änderungen" - }, - "status.network": { - "message": "Verbindung zum Server fehlgeschlagen (##replace.1##)." - }, - "status.networkerror": { - "message": "Verbindung zum Server fehlgeschlagen." - }, - "status.nosupportedeasversion": { - "message": "Der Server unterstützt kein ActiveSync v2.5 oder v14.0 (nur ##replace.1##). TbSync kann nicht mit diesem Server arbeiten." - }, - "status.notargets": { - "message": "Synchronisation abgebrochen da die Elemente zum Synchronisieren nicht erstellt werden konnten." - }, - "status.notsupportedeasversion": { - "message": "Der Server unterstützt nicht die ausgewählte ActiveSync Version v##replace.1## (nur ##replace.2##)." - }, - "status.notsyncronized": { - "message": "Konto muss synchronisiert werden." - }, - "status.nouserhost": { - "message": "Angabe des Benutzernamens und/oder des Servers fehlt. Bitte die korrekten Informationen eintragen." - }, - "status.pending": { - "message": "Warten auf Synchronisation" - }, - "status.policy.2": { - "message": "Es gibt keine Regel (policy) für diesen Klient. Kontaktieren Sie Ihren Server Administrator oder deaktivieren Sie die Provisionierungsoption für dieses Konto in TbSync." - }, - "status.policy.3": { - "message": "Unbekannter Wert für den Regeltyp (policy type). Kontaktieren Sie Ihren Server Administrator oder deaktivieren Sie die Provisionierungsoption für dieses Konto in TbSync." - }, - "status.policy.4": { - "message": "Die Daten für die Regeln auf dem Server sind beschädigt (möglicherweise manipuliert). Kontaktieren Sie Ihren Server Administrator oder deaktivieren Sie die Provisionierungsoption für dieses Konto in TbSync." - }, - "status.policy.5": { - "message": "Der Klient bestätigt einen falschen Richtlinienschlüssel (policy key). Kontaktieren Sie Ihren Server Administrator oder deaktivieren Sie die Provisionierungsoption für dieses Konto in TbSync." - }, - "status.provision": { - "message": "Provisionierung fehlerhaft mit folgendem Status <##replace.1##>" - }, - "status.response-contains-no-data": { - "message": "Antwort vom Server enthält keine Daten." - }, - "status.resync-loop": { - "message": "Es ist ein Fehler aufgetreten, der nicht durch wiederholtes Synchronisieren des Kontos behoben werden konnte. Bitte deaktivieren sie das Konto und wiederholen den Vorgang. (Fehler: Synchronisationsschleife)" - }, - "status.security": { - "message": "Fehler beim Aufbau einer sicherern Verbindung. Benutzen Sie eventuell ein selbst signiertes Zertifikat oder ein andersartiges nicht vertrauenswürdiges Zertifikat welches nicht in Thunderbird importiert ist? (##replace.1##)" - }, - "status.skipped": { - "message": "Nicht unterstützt" - }, - "status.syncing": { - "message": "Synchronisierung" - }, - "status.timeout": { - "message": "Kommunikations-Timeout." - }, - "status.wbxml-parse-error": { - "message": "Server sendet nicht lesbare Antwort." - }, - "status.wbxmlerror": { - "message": "Synchronisation fehlgeschlagen. Der Server antwortete mit dem Status <##replace.1##>." - }, - "status.wbxmlmissingfield": { - "message": "Verletzung des ActiveSync Protokolls: Notwendiges Feld <##replace.1##> ist nicht in der Serverantwort enthalten." - }, - "syncstate.accountdone": { - "message": "Kontosynchronisation abgeschlossen" - }, - "syncstate.done": { - "message": "Bereite das nächste Element für die Synchronisation vor" - }, - "syncstate.eval.response.autodiscover": { - "message": "Verarbeite aktualisierte Servereinstellungen" - }, - "syncstate.eval.response.deletefolder": { - "message": "Ordner erfolgreich gelöscht" - }, - "syncstate.eval.response.estimate": { - "message": "Verarbeite geschätzte Änderungen" - }, - "syncstate.eval.response.folders": { - "message": "Verarbeite aktualisierte Ordnerliste" - }, - "syncstate.eval.response.localchanges": { - "message": "Verarbeite Bestätigung der lokalen Änderungen" - }, - "syncstate.eval.response.localdeletes": { - "message": "Verarbeite Bestätigung lokal gelöschten Elemente" - }, - "syncstate.eval.response.options": { - "message": "Verarbeite aktualisierte Serveroptionen" - }, - "syncstate.eval.response.provision": { - "message": "Verarbeite Provisionierung" - }, - "syncstate.eval.response.remotechanges": { - "message": "Verarbeite aktualisierte Elemente" - }, - "syncstate.eval.response.revertlocalchanges": { - "message": "Lokale Änderungen werden verworfen" - }, - "syncstate.eval.response.setdeviceinfo": { - "message": "Sende Geräteinformationen" - }, - "syncstate.eval.response.synckey": { - "message": "Verarbeite Synchronisationsschlüssel" - }, - "syncstate.prepare.request.autodiscover": { - "message": "Sende Anfrage bzgl. aktualisierter Servereinstellungen" - }, - "syncstate.prepare.request.deletefolder": { - "message": "Löschen des Ordners wird vorbereitet" - }, - "syncstate.prepare.request.estimate": { - "message": "Sende Anfrage bzgl. geschätzter Änderungen" - }, - "syncstate.prepare.request.folders": { - "message": "Sende Anfrage bzgl. aktualisierter Ordnerliste" - }, - "syncstate.prepare.request.localchanges": { - "message": "Sende lokale Änderungen" - }, - "syncstate.prepare.request.localdeletes": { - "message": "Sende die lokal gelöschten Elemente" - }, - "syncstate.prepare.request.options": { - "message": "Sende Anfrage bzgl. aktualisierter Serveroptionen" - }, - "syncstate.prepare.request.provision": { - "message": "Sende Anfrage bzgl. Provisionierung" - }, - "syncstate.prepare.request.remotechanges": { - "message": "Sende Anfrage bzgl. Änderungen" - }, - "syncstate.prepare.request.revertlocalchanges": { - "message": "Prüfe lokale Änderungen" - }, - "syncstate.prepare.request.setdeviceinfo": { - "message": "Sende Geräteinformationen" - }, - "syncstate.prepare.request.synckey": { - "message": "Sende Anfrage bzgl. Synchronisationsschlüssel" - }, - "syncstate.preparing": { - "message": "Bereite das nächste Element für die Synchronisation vor" - }, - "syncstate.send.request.autodiscover": { - "message": "Warte auf aktualisierte Servereinstellungen" - }, - "syncstate.send.request.deletefolder": { - "message": "Ordner wird gelöscht" - }, - "syncstate.send.request.estimate": { - "message": "Warte auf geschätzte Änderungen" - }, - "syncstate.send.request.folders": { - "message": "Warte auf aktualisierte Ordnerliste" - }, - "syncstate.send.request.localchanges": { - "message": "Warte auf Bestätigung der lokalen Änderungen" - }, - "syncstate.send.request.localdeletes": { - "message": "Warte auf Bestätigung lokal gelöschten Elemente" - }, - "syncstate.send.request.options": { - "message": "Warte auf aktualisierte Serveroptionen" - }, - "syncstate.send.request.provision": { - "message": "Warte auf Provisionierung" - }, - "syncstate.send.request.remotechanges": { - "message": "Warte auf aktualisierte Elemente" - }, - "syncstate.send.request.revertlocalchanges": { - "message": "Warte auf aktuelle Versionen" - }, - "syncstate.send.request.setdeviceinfo": { - "message": "Sende Geräteinformationen" - }, - "syncstate.send.request.synckey": { - "message": "Warte auf Synchronisationsschlüssel" - }, - "syncstate.syncing": { - "message": "Initiiere Synchronisation" - } -} +{ + "abCard.Anniversary": { + "message": "Jubiläum:" + }, + "abCard.AssistantName": { + "message": "Assistent:" + }, + "abCard.AssistantPhoneNumber": { + "message": "Assistententelefon:" + }, + "abCard.Business2PhoneNumber": { + "message": "Telefon 2 Arbeit:" + }, + "abCard.BusinessFaxNumber": { + "message": "Fax Arbeit:" + }, + "abCard.CarPhoneNumber": { + "message": "Telefon Auto:" + }, + "abCard.CompanyMainPhone": { + "message": "Haupttelefon Arbeit:" + }, + "abCard.Email3Address": { + "message": "Alternative E-Mail:" + }, + "abCard.Home2PhoneNumber": { + "message": "Telefon 2 zu Hause:" + }, + "abCard.ManagerName": { + "message": "Manager:" + }, + "abCard.MiddleName": { + "message": "Zweiter Vorname:" + }, + "abCard.OtherAddress": { + "message": "Adresse:" + }, + "abCard.OtherCity": { + "message": "Stadt:" + }, + "abCard.OtherCountry": { + "message": "Land:" + }, + "abCard.OtherState": { + "message": "Bundesland:" + }, + "abCard.OtherZip": { + "message": "Postleitzahl:" + }, + "abCard.RadioPhoneNumber": { + "message": "Funktelefon:" + }, + "abCard.Spouse": { + "message": "Ehepartner:" + }, + "abCard.header.eas": { + "message": "Weitere Felder (EAS)" + }, + "abCard.header.homenumbers": { + "message": "Zusätzliche Nummern zu Hause:" + }, + "abCard.header.messaging": { + "message": "Nachrichten:" + }, + "abCard.header.otheraddress": { + "message": "Weitere Adresse (EAS)" + }, + "abCard.header.othernumbers": { + "message": "Zusätzliche Nummern:" + }, + "abCard.header.people": { + "message": "Personen:" + }, + "abCard.header.worknumbers": { + "message": "Zusätzliche Nummern Arbeit:" + }, + "acl.readonly": { + "message": "Serverzugriff nur lesend (verwerfe lokale Änderungen)" + }, + "acl.readwrite": { + "message": "Serverzugriff lesend und schreibend" + }, + "add.description": { + "message": "Bitte wählen Sie eine der verfügbaren Server-Konfigurationen aus und geben Sie die angeforderten Details ein. " + }, + "add.name": { + "message": "Kontoname:" + }, + "add.ok": { + "message": "Konto hinzufügen" + }, + "add.password": { + "message": "Passwort:" + }, + "add.server": { + "message": "Server Konfiguration:" + }, + "add.shortdescription": { + "message": "Kontoinformationen" + }, + "add.title": { + "message": "Exchange ActiveSync Konto hinzufügen" + }, + "add.url": { + "message": "Server Adresse:" + }, + "add.urldescription": { + "message": "Meist reicht die Angabe der einfachen Serveradresse (z.B.: mail.meinserver.de), alternativ kann aber auch die komplette URL angegeben werden (z.B.: https://mail.meinserver.de/Microsoft-Server-ActiveSync)." + }, + "add.user": { + "message": "Benutzername (E-Mail Adresse):" + }, + "autocomplete.serverdirectory": { + "message": "Globales Serververzeichnis" + }, + "autodiscover.Failed": { + "message": "Autodiscover für den Benutzer <##user##> war nicht erfolgreich. Entweder war das Passwort nicht korrekt, Ihr ActiveSync Server hat ein temporäres Problem oder unterstützt kein Autodiscover." + }, + "autodiscover.NeedEmail": { + "message": "Autodiscover benötigt eine gültige E-Mail Adresse als Benutzername." + }, + "autodiscover.Ok": { + "message": "Autodiscover war erfolgreich, Sie können nun die optionalen Einstellungen überprüfen und die Synchronisationsverbindung aktivieren." + }, + "autodiscover.Querying": { + "message": "Einstellungen werden gesucht ..." + }, + "config.auto": { + "message": "ActiveSync Server Konfiguration (Autodiscover)" + }, + "config.custom": { + "message": "ActiveSync Server Konfiguration" + }, + "deletefolder.confirm": { + "message": "Möchten Sie den Ordner '##replace.1##' wirklich ENDGÜLTIG aus dem Papierkorb ENTFERNEN?" + }, + "deletefolder.menuentry": { + "message": "Den Ordner '##replace.1##' endgültig aus dem Papierkorb entfernen" + }, + "deletefolder.notallowed": { + "message": "Bitte beenden Sie zunächst das Abonement des Ordner '##replace.1##', bevor Sie diesen aus dem Papierkorb entfernen." + }, + "extensionDescription": { + "message": "Erweitert TbSync und erlaubt die Synchronisation von Exchange ActiveSync Konten (Kontakte, Aufgaben und Kalender)." + }, + "extensionName": { + "message": "Provider für Exchange ActiveSync" + }, + "helplink.BadItemSkipped": { + "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped" + }, + "helplink.global.clientdenied": { + "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F" + }, + "helplink.security": { + "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F" + }, + "manager.tabs.accountsettings": { + "message": "Kontoeinstellungen" + }, + "manager.tabs.outOfOffice": { + "message": "Autoresponder" + }, + "manager.tabs.syncsettings": { + "message": "Optionen" + }, + "newaccount.add_auto": { + "message": "Einstellungen suchen und Konto hinzufügen" + }, + "newaccount.add_custom": { + "message": "Konto hinzufügen" + }, + "pref.AccountName": { + "message": "Kontoname" + }, + "pref.ActiveSyncVersion": { + "message": "ActiveSync Version" + }, + "pref.DeviceId": { + "message": "ActiveSync Geräte ID" + }, + "pref.ServerName": { + "message": "Server Adresse" + }, + "pref.ServerNameDescription": { + "message": "z.B. mail.meinserver.com" + }, + "pref.ShowTrashedFolders": { + "message": "Im Papierkorb gefundene Ordner anzeigen" + }, + "pref.UserName": { + "message": "Benutzername" + }, + "pref.UserNameDescription": { + "message": "Der Benutzername ist meistens die E-Mail Adresse Ihres Kontos." + }, + "pref.autodetect": { + "message": "bestmöglich" + }, + "pref.birthday": { + "message": "Sende Geburtstagsinformation" + }, + "pref.calendaroptions": { + "message": "Kalender Optionen" + }, + "pref.contactoptions": { + "message": "Kontakt Optionen" + }, + "pref.displayoverride": { + "message": "Überschreibe Anzeigename mit 'Vorname' + 'Nachname'" + }, + "pref.generaloptions": { + "message": "Allgemeine Optionen" + }, + "pref.provision": { + "message": "Provisionierung erzwingen (wird von Kerio benötigt)" + }, + "pref.seperator.comma": { + "message": "Komma" + }, + "pref.seperator.description": { + "message": "Separator für mehrzeilige Adressfelder: " + }, + "pref.seperator.linebreak": { + "message": "Zeilenumbruch" + }, + "pref.synclimit.1month": { + "message": "ab vor 4 Wochen" + }, + "pref.synclimit.2weeks": { + "message": "ab vor 2 Wochen" + }, + "pref.synclimit.3month": { + "message": "ab vor 3 Monaten" + }, + "pref.synclimit.6month": { + "message": "ab vor 6 Monaten" + }, + "pref.synclimit.all": { + "message": "alles" + }, + "pref.synclimit.description": { + "message": "Synchronisationszeitraum: " + }, + "pref.usehttps": { + "message": "Sichere Verbindungen verwenden (via https://)" + }, + "recyclebin": { + "message": "Papierkorb" + }, + "servertype.auto": { + "message": "Automatische Konfiguration" + }, + "servertype.custom": { + "message": "Benutzerspezifische Konfiguration" + }, + "servertype.description.auto": { + "message": "Die Konfiguration vieler ActiveSync Server kann allein durch die Angabe Ihrer E-Mail-Adresse erfolgen." + }, + "servertype.description.custom": { + "message": "Richten Sie Ihr Konto ein, indem Sie die Adresse des Servers angeben, mit dem Sie sich verbinden möchten." + }, + "servertype.description.office365": { + "message": "Konten, die mit Office 365 verbunden sind, verwenden den modernen OAuth 2.0 Authentifizierungsprozess, der auch Multi-Factor-Authentication (MFA) unterstützt." + }, + "servertype.office365": { + "message": "Microsoft Office 365" + }, + "servertype.unlock": { + "message": "Doppelklick um die vordefinierten Servereinstellungen zu entsperren." + }, + "status.401": { + "message": "Authentifizierung fehlgeschlagen, überprüfen Sie den Benutzernamen und das Passwort." + }, + "status.403": { + "message": "Verbindung vom Server abgelehnt (nicht erlaubt)." + }, + "status.404": { + "message": "Unbekanner Benutzer (HTTP Fehler 404)." + }, + "status.449": { + "message": "Server erwartet Provisionierung." + }, + "status.500": { + "message": "Unbekannter Server Fehler (HTTP Fehler 500)." + }, + "status.503": { + "message": "Service nicht erreichbar." + }, + "status.BadItemSkipped": { + "message": "Ein Element wurde nicht synchronisiert: ##replace.1##" + }, + "status.FolderDelete.3": { + "message": "Systemordner können nicht gelöscht werden." + }, + "status.FolderDelete.4": { + "message": "Ordner existiert nicht, es wird neu synchronisiert" + }, + "status.FolderDelete.6": { + "message": "Das Kommando konnte nicht abgeschlossen werden, auf dem Server ist ein Fehler aufgetreten." + }, + "status.FolderDelete.9": { + "message": "Ungültiger Synchronisationsschlüssel, es wird neu synchronisiert" + }, + "status.FolderSync.9": { + "message": "Ungültiger Synchronisationsschlüssel, es wird neu synchronisiert" + }, + "status.InvalidServerOptions": { + "message": "Der Server sendet keine Informationen zu den unterstützten ActiveSync Versionen. Ist EAS für diesen Benutzer bzw. für dieses Programm (TbSync) freigeschaltet? Sie können versuchen, die ActiveSync Version manuell festzulegen." + }, + "status.OK": { + "message": "Ok" + }, + "status.ServerRejectedRequest": { + "message": "Der EAS Server hat die letzte Anforderung zurückgewiesen." + }, + "status.ServerRejectedSomeItems": { + "message": "Der EAS Server hat ##replace.1## Elemente nicht akzeptiert." + }, + "status.Sync.12": { + "message": "Ordnerhierarchie hat sich geändert, es wird neu synchronisiert" + }, + "status.Sync.3": { + "message": "Ungültiger Synchronisationsschlüssel, es wird neu synchronisiert" + }, + "status.Sync.4": { + "message": "Fehlerhafte Anfrage (Status 4)" + }, + "status.Sync.5": { + "message": "Temporäres Serverproblem oder ungültiges Element (Status 5)" + }, + "status.Sync.6": { + "message": "Ungültiges Element (Status 6)" + }, + "status.Sync.8": { + "message": "Objekt nicht gefunden (Status 8)" + }, + "status.aborted": { + "message": "Nicht synchronisiert" + }, + "status.disabled": { + "message": "Konto ist deaktiviert, Synchronisation ist ausgeschaltet." + }, + "status.empty-response": { + "message": "Server sendet unerwartete leere Antwort." + }, + "status.forbiddenCalendarItemInTasksFolder": { + "message": "Unerlaubtes Kalender-Element in einem Aufgaben-Objekt (bitte umsortieren)" + }, + "status.forbiddenTasksItemInCalendarFolder": { + "message": "Unerlaubtes Aufgaben-Element in einem Kalender-Objekt (bitte umsortieren)" + }, + "status.global.101": { + "message": "Das WBXML der Anfrage konnte nicht in gültiges XML dekodiert werden (EAS Fehler 101)." + }, + "status.global.102": { + "message": "Das WBXML der Anfrage konnte nicht in gültiges XML dekodiert werden (EAS Fehler 102)." + }, + "status.global.103": { + "message": "Das XML der Anfrage entspricht nicht den Protokollanforderungen (EAS Fehler 103)." + }, + "status.global.110": { + "message": "Der Server meldet einen internen Fehler und es soll nicht unmittelbar ein erneuter Verbindungsaufbau durchgeführt werden. Die automatische periodische Synchronisation wird für 30 Minuten ausgesetzt (EAS Fehler 110)." + }, + "status.global.clientdenied": { + "message": "Der EAS Server antwortet mit <##replace.2##> (status ##replace.1##) und verweigert TbSync den Zugriff auf Ihr Konto." + }, + "status.httperror": { + "message": "Kommunikationsfehler (HTTP Status ##replace.1##)." + }, + "status.invalid": { + "message": "Ungültige Serverantwort." + }, + "status.malformed-xml": { + "message": "Antwort enthält fehlerhaftes XML, Sync angebrochen. Prüfen Sie bitte das Ereignisprotokoll für weitere Details." + }, + "status.modified": { + "message": "Lokale Änderungen" + }, + "status.network": { + "message": "Verbindung zum Server fehlgeschlagen (##replace.1##)." + }, + "status.networkerror": { + "message": "Verbindung zum Server fehlgeschlagen." + }, + "status.nosupportedeasversion": { + "message": "Der Server unterstützt kein ActiveSync v2.5 oder v14.0 (nur ##replace.1##). TbSync kann nicht mit diesem Server arbeiten." + }, + "status.notargets": { + "message": "Synchronisation abgebrochen da die Elemente zum Synchronisieren nicht erstellt werden konnten." + }, + "status.notsupportedeasversion": { + "message": "Der Server unterstützt nicht die ausgewählte ActiveSync Version v##replace.1## (nur ##replace.2##)." + }, + "status.notsyncronized": { + "message": "Konto muss synchronisiert werden." + }, + "status.nouserhost": { + "message": "Angabe des Benutzernamens und/oder des Servers fehlt. Bitte die korrekten Informationen eintragen." + }, + "status.pending": { + "message": "Warten auf Synchronisation" + }, + "status.policy.2": { + "message": "Es gibt keine Regel (policy) für diesen Klient. Kontaktieren Sie Ihren Server Administrator oder deaktivieren Sie die Provisionierungsoption für dieses Konto in TbSync." + }, + "status.policy.3": { + "message": "Unbekannter Wert für den Regeltyp (policy type). Kontaktieren Sie Ihren Server Administrator oder deaktivieren Sie die Provisionierungsoption für dieses Konto in TbSync." + }, + "status.policy.4": { + "message": "Die Daten für die Regeln auf dem Server sind beschädigt (möglicherweise manipuliert). Kontaktieren Sie Ihren Server Administrator oder deaktivieren Sie die Provisionierungsoption für dieses Konto in TbSync." + }, + "status.policy.5": { + "message": "Der Klient bestätigt einen falschen Richtlinienschlüssel (policy key). Kontaktieren Sie Ihren Server Administrator oder deaktivieren Sie die Provisionierungsoption für dieses Konto in TbSync." + }, + "status.provision": { + "message": "Provisionierung fehlerhaft mit folgendem Status <##replace.1##>" + }, + "status.response-contains-no-data": { + "message": "Antwort vom Server enthält keine Daten." + }, + "status.resync-loop": { + "message": "Es ist ein Fehler aufgetreten, der nicht durch wiederholtes Synchronisieren des Kontos behoben werden konnte. Bitte deaktivieren sie das Konto und wiederholen den Vorgang. (Fehler: Synchronisationsschleife)" + }, + "status.security": { + "message": "Fehler beim Aufbau einer sicherern Verbindung. Benutzen Sie eventuell ein selbst signiertes Zertifikat oder ein andersartiges nicht vertrauenswürdiges Zertifikat welches nicht in Thunderbird importiert ist? (##replace.1##)" + }, + "status.skipped": { + "message": "Nicht unterstützt" + }, + "status.syncing": { + "message": "Synchronisierung" + }, + "status.timeout": { + "message": "Kommunikations-Timeout." + }, + "status.wbxml-parse-error": { + "message": "Server sendet nicht lesbare Antwort." + }, + "status.wbxmlerror": { + "message": "Synchronisation fehlgeschlagen. Der Server antwortete mit dem Status <##replace.1##>." + }, + "status.wbxmlmissingfield": { + "message": "Verletzung des ActiveSync Protokolls: Notwendiges Feld <##replace.1##> ist nicht in der Serverantwort enthalten." + }, + "syncstate.accountdone": { + "message": "Kontosynchronisation abgeschlossen" + }, + "syncstate.done": { + "message": "Bereite das nächste Element für die Synchronisation vor" + }, + "syncstate.eval.response.autodiscover": { + "message": "Verarbeite aktualisierte Servereinstellungen" + }, + "syncstate.eval.response.deletefolder": { + "message": "Ordner erfolgreich gelöscht" + }, + "syncstate.eval.response.estimate": { + "message": "Verarbeite geschätzte Änderungen" + }, + "syncstate.eval.response.folders": { + "message": "Verarbeite aktualisierte Ordnerliste" + }, + "syncstate.eval.response.localchanges": { + "message": "Verarbeite Bestätigung der lokalen Änderungen" + }, + "syncstate.eval.response.localdeletes": { + "message": "Verarbeite Bestätigung lokal gelöschten Elemente" + }, + "syncstate.eval.response.options": { + "message": "Verarbeite aktualisierte Serveroptionen" + }, + "syncstate.eval.response.provision": { + "message": "Verarbeite Provisionierung" + }, + "syncstate.eval.response.remotechanges": { + "message": "Verarbeite aktualisierte Elemente" + }, + "syncstate.eval.response.revertlocalchanges": { + "message": "Lokale Änderungen werden verworfen" + }, + "syncstate.eval.response.setdeviceinfo": { + "message": "Sende Geräteinformationen" + }, + "syncstate.eval.response.synckey": { + "message": "Verarbeite Synchronisationsschlüssel" + }, + "syncstate.prepare.request.autodiscover": { + "message": "Sende Anfrage bzgl. aktualisierter Servereinstellungen" + }, + "syncstate.prepare.request.deletefolder": { + "message": "Löschen des Ordners wird vorbereitet" + }, + "syncstate.prepare.request.estimate": { + "message": "Sende Anfrage bzgl. geschätzter Änderungen" + }, + "syncstate.prepare.request.folders": { + "message": "Sende Anfrage bzgl. aktualisierter Ordnerliste" + }, + "syncstate.prepare.request.localchanges": { + "message": "Sende lokale Änderungen" + }, + "syncstate.prepare.request.localdeletes": { + "message": "Sende die lokal gelöschten Elemente" + }, + "syncstate.prepare.request.options": { + "message": "Sende Anfrage bzgl. aktualisierter Serveroptionen" + }, + "syncstate.prepare.request.provision": { + "message": "Sende Anfrage bzgl. Provisionierung" + }, + "syncstate.prepare.request.remotechanges": { + "message": "Sende Anfrage bzgl. Änderungen" + }, + "syncstate.prepare.request.revertlocalchanges": { + "message": "Prüfe lokale Änderungen" + }, + "syncstate.prepare.request.setdeviceinfo": { + "message": "Sende Geräteinformationen" + }, + "syncstate.prepare.request.synckey": { + "message": "Sende Anfrage bzgl. Synchronisationsschlüssel" + }, + "syncstate.preparing": { + "message": "Bereite das nächste Element für die Synchronisation vor" + }, + "syncstate.send.request.autodiscover": { + "message": "Warte auf aktualisierte Servereinstellungen" + }, + "syncstate.send.request.deletefolder": { + "message": "Ordner wird gelöscht" + }, + "syncstate.send.request.estimate": { + "message": "Warte auf geschätzte Änderungen" + }, + "syncstate.send.request.folders": { + "message": "Warte auf aktualisierte Ordnerliste" + }, + "syncstate.send.request.localchanges": { + "message": "Warte auf Bestätigung der lokalen Änderungen" + }, + "syncstate.send.request.localdeletes": { + "message": "Warte auf Bestätigung lokal gelöschten Elemente" + }, + "syncstate.send.request.options": { + "message": "Warte auf aktualisierte Serveroptionen" + }, + "syncstate.send.request.provision": { + "message": "Warte auf Provisionierung" + }, + "syncstate.send.request.remotechanges": { + "message": "Warte auf aktualisierte Elemente" + }, + "syncstate.send.request.revertlocalchanges": { + "message": "Warte auf aktuelle Versionen" + }, + "syncstate.send.request.setdeviceinfo": { + "message": "Sende Geräteinformationen" + }, + "syncstate.send.request.synckey": { + "message": "Warte auf Synchronisationsschlüssel" + }, + "syncstate.syncing": { + "message": "Initiiere Synchronisation" + } +} diff -Nru eas4tbsync-4.11/_locales/en-US/messages.json eas4tbsync-4.17/_locales/en-US/messages.json --- eas4tbsync-4.11/_locales/en-US/messages.json 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/_locales/en-US/messages.json 2025-05-15 11:21:18.000000000 +0000 @@ -1,566 +1,566 @@ -{ - "abCard.Anniversary": { - "message": "Anniversary:" - }, - "abCard.AssistantName": { - "message": "Assistant:" - }, - "abCard.AssistantPhoneNumber": { - "message": "Assistant Phone:" - }, - "abCard.Business2PhoneNumber": { - "message": "Work Alternative Phone:" - }, - "abCard.BusinessFaxNumber": { - "message": "Work Fax:" - }, - "abCard.CarPhoneNumber": { - "message": "Car Phone:" - }, - "abCard.CompanyMainPhone": { - "message": "Work Main Phone:" - }, - "abCard.Email3Address": { - "message": "Alternative Email:" - }, - "abCard.Home2PhoneNumber": { - "message": "Home Alternative Phone:" - }, - "abCard.ManagerName": { - "message": "Manager:" - }, - "abCard.MiddleName": { - "message": "Middle name:" - }, - "abCard.OtherAddress": { - "message": "Address:" - }, - "abCard.OtherCity": { - "message": "City:" - }, - "abCard.OtherCountry": { - "message": "Country:" - }, - "abCard.OtherState": { - "message": "State:" - }, - "abCard.OtherZip": { - "message": "ZIP Code:" - }, - "abCard.RadioPhoneNumber": { - "message": "Radio Phone:" - }, - "abCard.Spouse": { - "message": "Spouse:" - }, - "abCard.header.eas": { - "message": "Other Fields (EAS)" - }, - "abCard.header.homenumbers": { - "message": "Additional home numbers:" - }, - "abCard.header.messaging": { - "message": "Messaging:" - }, - "abCard.header.otheraddress": { - "message": "Other Address (EAS)" - }, - "abCard.header.othernumbers": { - "message": "Additional numbers:" - }, - "abCard.header.people": { - "message": "People:" - }, - "abCard.header.worknumbers": { - "message": "Additional work numbers:" - }, - "acl.readonly": { - "message": "Read-only server access (revert local changes)" - }, - "acl.readwrite": { - "message": "Read from and write to server" - }, - "add.description": { - "message": "Please select one of the available server configuration options and enter the requested details. " - }, - "add.name": { - "message": "Account name:" - }, - "add.ok": { - "message": "Add account" - }, - "add.password": { - "message": "Password:" - }, - "add.server": { - "message": "Server configuration:" - }, - "add.shortdescription": { - "message": "Account information" - }, - "add.title": { - "message": "Adding an Exchange ActiveSync account to TbSync" - }, - "add.url": { - "message": "Server address:" - }, - "add.urldescription": { - "message": "It should be sufficient to provide just the basic server address (e.g.: mail.yourserver.com). However, it is also possible to provide the full URL (e.g.: https://mail.yourserver.com/Microsoft-Server-ActiveSync)." - }, - "add.user": { - "message": "User name (email address):" - }, - "autocomplete.serverdirectory": { - "message": "global server directory" - }, - "autodiscover.Failed": { - "message": "Autodiscover for user <##user##> failed. Either the provided credentials were wrong or your ActiveSync provider has a temporary issue, or does not support Autodiscover." - }, - "autodiscover.NeedEmail": { - "message": "Autodiscover needs a valid email address as user name." - }, - "autodiscover.Ok": { - "message": "Autodiscover completed successfully, you can now check the optional settings and establish the synchronization connection." - }, - "autodiscover.Querying": { - "message": "Searching for settings…" - }, - "config.auto": { - "message": "ActiveSync server configuration (Autodiscover)" - }, - "config.custom": { - "message": "ActiveSync server configuration" - }, - "deletefolder.confirm": { - "message": "Do you really want to PERMANENTLY PURGE folder “##replace.1##” from trash?" - }, - "deletefolder.menuentry": { - "message": "Permanently purge folder “##replace.1##” from trash" - }, - "deletefolder.notallowed": { - "message": "Please unsubscribe folder “##replace.1##” before trying to purge it from trash." - }, - "extensionDescription": { - "message": "Add sync support for Exchange ActiveSync accounts to TbSync (contacts, tasks and calendars)." - }, - "extensionName": { - "message": "Provider for Exchange ActiveSync" - }, - "helplink.BadItemSkipped": { - "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped" - }, - "helplink.global.clientdenied": { - "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F" - }, - "helplink.security": { - "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F" - }, - "manager.tabs.accountsettings": { - "message": "Account settings" - }, - "manager.tabs.outOfOffice": { - "message": "Auto responder" - }, - "manager.tabs.syncsettings": { - "message": "Options" - }, - "newaccount.add_auto": { - "message": "Autodiscover settings and add account" - }, - "newaccount.add_custom": { - "message": "Add account" - }, - "pref.AccountName": { - "message": "Description" - }, - "pref.ActiveSyncVersion": { - "message": "ActiveSync version" - }, - "pref.DeviceId": { - "message": "ActiveSync device ID" - }, - "pref.ServerName": { - "message": "Server address" - }, - "pref.ServerNameDescription": { - "message": "e.g. mail.yourserver.com" - }, - "pref.ShowTrashedFolders": { - "message": "Show folders found in trash" - }, - "pref.UserName": { - "message": "User name" - }, - "pref.UserNameDescription": { - "message": "User name is usually the email address of your account." - }, - "pref.autodetect": { - "message": "best available" - }, - "pref.birthday": { - "message": "Send birthday information" - }, - "pref.calendaroptions": { - "message": "Calendar options" - }, - "pref.contactoptions": { - "message": "Contact options" - }, - "pref.displayoverride": { - "message": "Override Display Name with “First Name” + “Second Name”" - }, - "pref.generaloptions": { - "message": "General options" - }, - "pref.provision": { - "message": "Enforce provisioning (required by Kerio)" - }, - "pref.seperator.comma": { - "message": "Comma" - }, - "pref.seperator.description": { - "message": "Separator for multiline address field." - }, - "pref.seperator.linebreak": { - "message": "Line break" - }, - "pref.synclimit.1month": { - "message": "from 4 weeks ago" - }, - "pref.synclimit.2weeks": { - "message": "from 2 weeks ago" - }, - "pref.synclimit.3month": { - "message": "from 3 months ago" - }, - "pref.synclimit.6month": { - "message": "from 6 months ago" - }, - "pref.synclimit.all": { - "message": "everything" - }, - "pref.synclimit.description": { - "message": "Synchronization period: " - }, - "pref.usehttps": { - "message": "Use secure connection (connect via https)" - }, - "recyclebin": { - "message": "Trash" - }, - "servertype.auto": { - "message": "Automatic configuration" - }, - "servertype.custom": { - "message": "Custom configuration" - }, - "servertype.description.auto": { - "message": "The configuration for many ActiveSync servers can be discovered by providing just your email address." - }, - "servertype.description.custom": { - "message": "Setup your account by manually providing the address of the server you want to connect." - }, - "servertype.description.office365": { - "message": "Accounts connected to Office 365 use a modern authentication process called OAuth 2.0 which also supports Multi-Factor-Authentication (MFA)." - }, - "servertype.office365": { - "message": "Microsoft Office 365" - }, - "servertype.unlock": { - "message": "Double click to unlock all predefined server settings." - }, - "status.401": { - "message": "Could not authenticate, check username and password (HTTP Error 401)." - }, - "status.403": { - "message": "Server rejected connection (forbidden) (HTTP Error 403)." - }, - "status.404": { - "message": "User not found (HTTP Error 404)." - }, - "status.449": { - "message": "Server requests provisioning (HTTP Error 449)." - }, - "status.500": { - "message": "Unknown Server Error (HTTP Error 500)." - }, - "status.503": { - "message": "Service unavailable (HTTP Error 503)." - }, - "status.BadItemSkipped": { - "message": "Bad Item Skipped: ##replace.1##" - }, - "status.FolderDelete.3": { - "message": "Cannot delete a system folder (status 3)" - }, - "status.FolderDelete.4": { - "message": "Folder does not exist (status 4), resyncing" - }, - "status.FolderDelete.6": { - "message": "Command could not be completed, an error occurred on the server (status 6)" - }, - "status.FolderDelete.9": { - "message": "Invalid synchronization key (status 9), resyncing" - }, - "status.FolderSync.9": { - "message": "Invalid synchronization key (status 9), resyncing" - }, - "status.InvalidServerOptions": { - "message": "The server does not provide information about the supported ActiveSync versions. Is EAS blocked for this user or this client (TbSync)? You could try to set the ActiveSync version manually." - }, - "status.OK": { - "message": "OK" - }, - "status.ServerRejectedRequest": { - "message": "The EAS Server rejected the last request." - }, - "status.ServerRejectedSomeItems": { - "message": "The EAS server did not accept ##replace.1## elements." - }, - "status.Sync.12": { - "message": "Folder hierarchy changed (status 12), resyncing" - }, - "status.Sync.3": { - "message": "Invalid synchronization key (status 3), resyncing" - }, - "status.Sync.4": { - "message": "Malformed request (status 4)" - }, - "status.Sync.5": { - "message": "Temporary server issues or invalid item (status 5)" - }, - "status.Sync.6": { - "message": "Invalid item (status 6)" - }, - "status.Sync.8": { - "message": "Object not found (status 8)" - }, - "status.aborted": { - "message": "Not synchronized" - }, - "status.disabled": { - "message": "Disabled" - }, - "status.empty-response": { - "message": "Server sends unexpected empty response." - }, - "status.forbiddenCalendarItemInTasksFolder": { - "message": "Forbidden calendar item in a task folder (please resort)" - }, - "status.forbiddenTasksItemInCalendarFolder": { - "message": "Forbidden task item in a calendar folder (please resort)" - }, - "status.global.101": { - "message": "The request contains WBXML but it could not be decoded into XML (EAS Error 101)." - }, - "status.global.102": { - "message": "The request contains WBXML but it could not be decoded into XML (EAS Error 102)." - }, - "status.global.103": { - "message": "The XML provided in the request does not follow the protocol requirements (EAS Error 103)." - }, - "status.global.110": { - "message": "The server reported an internal error and we should not retry immediately. Automatic periodic sync has been disabled for 30 minutes (EAS Error 110)." - }, - "status.global.clientdenied": { - "message": "The EAS server reports <##replace.2##> (status ##replace.1##) and does not allow TbSync to access your account." - }, - "status.httperror": { - "message": "Communication error (HTTP status ##replace.1##)." - }, - "status.invalid": { - "message": "Invalid server response (junk)." - }, - "status.malformed-xml": { - "message": "Could not parse XML. Check event log for details." - }, - "status.modified": { - "message": "Local modifications" - }, - "status.network": { - "message": "Could not connect to server (##replace.1##)." - }, - "status.networkerror": { - "message": "Could not connect to server." - }, - "status.nosupportedeasversion": { - "message": "Server does not support ActiveSync v2.5 or v14.0 (only ##replace.1##). TbSync will not work with this ActiveSync server." - }, - "status.notargets": { - "message": "Aborting Sync, because sync targets could not be created." - }, - "status.notsupportedeasversion": { - "message": "Server does not support selected ActiveSync v##replace.1## (only ##replace.2##)." - }, - "status.notsyncronized": { - "message": "Account needs to be synchronized, at least one item is out of sync." - }, - "status.nouserhost": { - "message": "Missing username and/or server. Please provide those values." - }, - "status.pending": { - "message": "Waiting to be synchronized" - }, - "status.policy.2": { - "message": "There is no policy for this client. Contact your server administrator or disable provisioning for this account." - }, - "status.policy.3": { - "message": "Unknown PolicyType value. Contact your server administrator or disable provisioning for this account." - }, - "status.policy.4": { - "message": "The policy data on the server is corrupted (possibly tampered with). Contact your server administrator or disable provisioning for this account." - }, - "status.policy.5": { - "message": "The client is acknowledging the wrong policy key. Contact your server administrator or disable provisioning for this account." - }, - "status.provision": { - "message": "Provisioning failed with status <##replace.1##>" - }, - "status.response-contains-no-data": { - "message": "Response from the server contains no data." - }, - "status.resync-loop": { - "message": "There was an error from which we could not recover by resyncing the account. Please disable the account and try again. (Error: resync loop)" - }, - "status.security": { - "message": "Could not establish a secure connection. Are you using a self-signed or otherwise untrusted certificate without importing it into Thunderbird? (##replace.1##)" - }, - "status.skipped": { - "message": "Not yet supported, skipped" - }, - "status.syncing": { - "message": "Synchronizing" - }, - "status.timeout": { - "message": "Communication timeout." - }, - "status.wbxml-parse-error": { - "message": "Server sends unreadable response." - }, - "status.wbxmlerror": { - "message": "Sync failed. Server responded with status <##replace.1##>." - }, - "status.wbxmlmissingfield": { - "message": "ActiveSync protocol violation: Mandatory field <##replace.1##> is missing from server response." - }, - "syncstate.accountdone": { - "message": "Finished account" - }, - "syncstate.done": { - "message": "Preparing next item for synchronization" - }, - "syncstate.eval.response.autodiscover": { - "message": "Processing updated server settings" - }, - "syncstate.eval.response.deletefolder": { - "message": "Folder deleted" - }, - "syncstate.eval.response.estimate": { - "message": "Processing change estimate" - }, - "syncstate.eval.response.folders": { - "message": "Processing folder list update" - }, - "syncstate.eval.response.localchanges": { - "message": "Processing acknowledgment of local changes" - }, - "syncstate.eval.response.localdeletes": { - "message": "Processing acknowledgment of local deletes" - }, - "syncstate.eval.response.options": { - "message": "Processing server options" - }, - "syncstate.eval.response.provision": { - "message": "Processing provision" - }, - "syncstate.eval.response.remotechanges": { - "message": "Processing remote changes" - }, - "syncstate.eval.response.revertlocalchanges": { - "message": "Reverting local changes" - }, - "syncstate.eval.response.setdeviceinfo": { - "message": "Sending device information" - }, - "syncstate.eval.response.synckey": { - "message": "Processing SyncKey" - }, - "syncstate.prepare.request.autodiscover": { - "message": "Requesting updated server settings" - }, - "syncstate.prepare.request.deletefolder": { - "message": "Preparing to delete folder" - }, - "syncstate.prepare.request.estimate": { - "message": "Requesting change estimate" - }, - "syncstate.prepare.request.folders": { - "message": "Sending folder list update" - }, - "syncstate.prepare.request.localchanges": { - "message": "Sending local changes" - }, - "syncstate.prepare.request.localdeletes": { - "message": "Sending local deletes" - }, - "syncstate.prepare.request.options": { - "message": "Requesting server options" - }, - "syncstate.prepare.request.provision": { - "message": "Requesting provision" - }, - "syncstate.prepare.request.remotechanges": { - "message": "Requesting remote changes" - }, - "syncstate.prepare.request.revertlocalchanges": { - "message": "Collecting local changes" - }, - "syncstate.prepare.request.setdeviceinfo": { - "message": "Sending device information" - }, - "syncstate.prepare.request.synckey": { - "message": "Requesting SyncKey" - }, - "syncstate.preparing": { - "message": "Preparing next item for synchronization" - }, - "syncstate.send.request.autodiscover": { - "message": "Waiting for updated server settings" - }, - "syncstate.send.request.deletefolder": { - "message": "Waiting for folder to be deleted" - }, - "syncstate.send.request.estimate": { - "message": "Waiting for change estimate" - }, - "syncstate.send.request.folders": { - "message": "Waiting for folder list update" - }, - "syncstate.send.request.localchanges": { - "message": "Waiting for acknowledgment of local changes" - }, - "syncstate.send.request.localdeletes": { - "message": "Waiting for acknowledgment of local deletes" - }, - "syncstate.send.request.options": { - "message": "Waiting for server options" - }, - "syncstate.send.request.provision": { - "message": "Waiting for provision" - }, - "syncstate.send.request.remotechanges": { - "message": "Waiting for remote changes" - }, - "syncstate.send.request.revertlocalchanges": { - "message": "Waiting for most recent versions" - }, - "syncstate.send.request.setdeviceinfo": { - "message": "Sending device information" - }, - "syncstate.send.request.synckey": { - "message": "Waiting for SyncKey" - }, - "syncstate.syncing": { - "message": "Initialize synchronization" - } -} +{ + "abCard.Anniversary": { + "message": "Anniversary:" + }, + "abCard.AssistantName": { + "message": "Assistant:" + }, + "abCard.AssistantPhoneNumber": { + "message": "Assistant Phone:" + }, + "abCard.Business2PhoneNumber": { + "message": "Work Alternative Phone:" + }, + "abCard.BusinessFaxNumber": { + "message": "Work Fax:" + }, + "abCard.CarPhoneNumber": { + "message": "Car Phone:" + }, + "abCard.CompanyMainPhone": { + "message": "Work Main Phone:" + }, + "abCard.Email3Address": { + "message": "Alternative Email:" + }, + "abCard.Home2PhoneNumber": { + "message": "Home Alternative Phone:" + }, + "abCard.ManagerName": { + "message": "Manager:" + }, + "abCard.MiddleName": { + "message": "Middle name:" + }, + "abCard.OtherAddress": { + "message": "Address:" + }, + "abCard.OtherCity": { + "message": "City:" + }, + "abCard.OtherCountry": { + "message": "Country:" + }, + "abCard.OtherState": { + "message": "State:" + }, + "abCard.OtherZip": { + "message": "ZIP Code:" + }, + "abCard.RadioPhoneNumber": { + "message": "Radio Phone:" + }, + "abCard.Spouse": { + "message": "Spouse:" + }, + "abCard.header.eas": { + "message": "Other Fields (EAS)" + }, + "abCard.header.homenumbers": { + "message": "Additional home numbers:" + }, + "abCard.header.messaging": { + "message": "Messaging:" + }, + "abCard.header.otheraddress": { + "message": "Other Address (EAS)" + }, + "abCard.header.othernumbers": { + "message": "Additional numbers:" + }, + "abCard.header.people": { + "message": "People:" + }, + "abCard.header.worknumbers": { + "message": "Additional work numbers:" + }, + "acl.readonly": { + "message": "Read-only server access (revert local changes)" + }, + "acl.readwrite": { + "message": "Read from and write to server" + }, + "add.description": { + "message": "Please select one of the available server configuration options and enter the requested details. " + }, + "add.name": { + "message": "Account name:" + }, + "add.ok": { + "message": "Add account" + }, + "add.password": { + "message": "Password:" + }, + "add.server": { + "message": "Server configuration:" + }, + "add.shortdescription": { + "message": "Account information" + }, + "add.title": { + "message": "Adding an Exchange ActiveSync account to TbSync" + }, + "add.url": { + "message": "Server address:" + }, + "add.urldescription": { + "message": "It should be sufficient to provide just the basic server address (e.g.: mail.yourserver.com). However, it is also possible to provide the full URL (e.g.: https://mail.yourserver.com/Microsoft-Server-ActiveSync)." + }, + "add.user": { + "message": "User name (email address):" + }, + "autocomplete.serverdirectory": { + "message": "global server directory" + }, + "autodiscover.Failed": { + "message": "Autodiscover for user <##user##> failed. Either the provided credentials were wrong or your ActiveSync provider has a temporary issue, or does not support Autodiscover." + }, + "autodiscover.NeedEmail": { + "message": "Autodiscover needs a valid email address as user name." + }, + "autodiscover.Ok": { + "message": "Autodiscover completed successfully, you can now check the optional settings and establish the synchronization connection." + }, + "autodiscover.Querying": { + "message": "Searching for settings…" + }, + "config.auto": { + "message": "ActiveSync server configuration (Autodiscover)" + }, + "config.custom": { + "message": "ActiveSync server configuration" + }, + "deletefolder.confirm": { + "message": "Do you really want to PERMANENTLY PURGE folder “##replace.1##” from trash?" + }, + "deletefolder.menuentry": { + "message": "Permanently purge folder “##replace.1##” from trash" + }, + "deletefolder.notallowed": { + "message": "Please unsubscribe folder “##replace.1##” before trying to purge it from trash." + }, + "extensionDescription": { + "message": "Add sync support for Exchange ActiveSync accounts to TbSync (contacts, tasks and calendars)." + }, + "extensionName": { + "message": "Provider for Exchange ActiveSync" + }, + "helplink.BadItemSkipped": { + "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped" + }, + "helplink.global.clientdenied": { + "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F" + }, + "helplink.security": { + "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F" + }, + "manager.tabs.accountsettings": { + "message": "Account settings" + }, + "manager.tabs.outOfOffice": { + "message": "Auto responder" + }, + "manager.tabs.syncsettings": { + "message": "Options" + }, + "newaccount.add_auto": { + "message": "Autodiscover settings and add account" + }, + "newaccount.add_custom": { + "message": "Add account" + }, + "pref.AccountName": { + "message": "Description" + }, + "pref.ActiveSyncVersion": { + "message": "ActiveSync version" + }, + "pref.DeviceId": { + "message": "ActiveSync device ID" + }, + "pref.ServerName": { + "message": "Server address" + }, + "pref.ServerNameDescription": { + "message": "e.g. mail.yourserver.com" + }, + "pref.ShowTrashedFolders": { + "message": "Show folders found in trash" + }, + "pref.UserName": { + "message": "User name" + }, + "pref.UserNameDescription": { + "message": "User name is usually the email address of your account." + }, + "pref.autodetect": { + "message": "best available" + }, + "pref.birthday": { + "message": "Send birthday information" + }, + "pref.calendaroptions": { + "message": "Calendar options" + }, + "pref.contactoptions": { + "message": "Contact options" + }, + "pref.displayoverride": { + "message": "Override Display Name with “First Name” + “Second Name”" + }, + "pref.generaloptions": { + "message": "General options" + }, + "pref.provision": { + "message": "Enforce provisioning (required by Kerio)" + }, + "pref.seperator.comma": { + "message": "Comma" + }, + "pref.seperator.description": { + "message": "Separator for multiline address field." + }, + "pref.seperator.linebreak": { + "message": "Line break" + }, + "pref.synclimit.1month": { + "message": "from 4 weeks ago" + }, + "pref.synclimit.2weeks": { + "message": "from 2 weeks ago" + }, + "pref.synclimit.3month": { + "message": "from 3 months ago" + }, + "pref.synclimit.6month": { + "message": "from 6 months ago" + }, + "pref.synclimit.all": { + "message": "everything" + }, + "pref.synclimit.description": { + "message": "Synchronization period: " + }, + "pref.usehttps": { + "message": "Use secure connection (connect via https)" + }, + "recyclebin": { + "message": "Trash" + }, + "servertype.auto": { + "message": "Automatic configuration" + }, + "servertype.custom": { + "message": "Custom configuration" + }, + "servertype.description.auto": { + "message": "The configuration for many ActiveSync servers can be discovered by providing just your email address." + }, + "servertype.description.custom": { + "message": "Setup your account by manually providing the address of the server you want to connect." + }, + "servertype.description.office365": { + "message": "Accounts connected to Office 365 use a modern authentication process called OAuth 2.0 which also supports Multi-Factor-Authentication (MFA)." + }, + "servertype.office365": { + "message": "Microsoft Office 365" + }, + "servertype.unlock": { + "message": "Double click to unlock all predefined server settings." + }, + "status.401": { + "message": "Could not authenticate, check username and password (HTTP Error 401)." + }, + "status.403": { + "message": "Server rejected connection (forbidden) (HTTP Error 403)." + }, + "status.404": { + "message": "User not found (HTTP Error 404)." + }, + "status.449": { + "message": "Server requests provisioning (HTTP Error 449)." + }, + "status.500": { + "message": "Unknown Server Error (HTTP Error 500)." + }, + "status.503": { + "message": "Service unavailable (HTTP Error 503)." + }, + "status.BadItemSkipped": { + "message": "Bad Item Skipped: ##replace.1##" + }, + "status.FolderDelete.3": { + "message": "Cannot delete a system folder (status 3)" + }, + "status.FolderDelete.4": { + "message": "Folder does not exist (status 4), resyncing" + }, + "status.FolderDelete.6": { + "message": "Command could not be completed, an error occurred on the server (status 6)" + }, + "status.FolderDelete.9": { + "message": "Invalid synchronization key (status 9), resyncing" + }, + "status.FolderSync.9": { + "message": "Invalid synchronization key (status 9), resyncing" + }, + "status.InvalidServerOptions": { + "message": "The server does not provide information about the supported ActiveSync versions. Is EAS blocked for this user or this client (TbSync)? You could try to set the ActiveSync version manually." + }, + "status.OK": { + "message": "OK" + }, + "status.ServerRejectedRequest": { + "message": "The EAS Server rejected the last request." + }, + "status.ServerRejectedSomeItems": { + "message": "The EAS server did not accept ##replace.1## elements." + }, + "status.Sync.12": { + "message": "Folder hierarchy changed (status 12), resyncing" + }, + "status.Sync.3": { + "message": "Invalid synchronization key (status 3), resyncing" + }, + "status.Sync.4": { + "message": "Malformed request (status 4)" + }, + "status.Sync.5": { + "message": "Temporary server issues or invalid item (status 5)" + }, + "status.Sync.6": { + "message": "Invalid item (status 6)" + }, + "status.Sync.8": { + "message": "Object not found (status 8)" + }, + "status.aborted": { + "message": "Not synchronized" + }, + "status.disabled": { + "message": "Disabled" + }, + "status.empty-response": { + "message": "Server sends unexpected empty response." + }, + "status.forbiddenCalendarItemInTasksFolder": { + "message": "Forbidden calendar item in a task folder (please resort)" + }, + "status.forbiddenTasksItemInCalendarFolder": { + "message": "Forbidden task item in a calendar folder (please resort)" + }, + "status.global.101": { + "message": "The request contains WBXML but it could not be decoded into XML (EAS Error 101)." + }, + "status.global.102": { + "message": "The request contains WBXML but it could not be decoded into XML (EAS Error 102)." + }, + "status.global.103": { + "message": "The XML provided in the request does not follow the protocol requirements (EAS Error 103)." + }, + "status.global.110": { + "message": "The server reported an internal error and we should not retry immediately. Automatic periodic sync has been disabled for 30 minutes (EAS Error 110)." + }, + "status.global.clientdenied": { + "message": "The EAS server reports <##replace.2##> (status ##replace.1##) and does not allow TbSync to access your account." + }, + "status.httperror": { + "message": "Communication error (HTTP status ##replace.1##)." + }, + "status.invalid": { + "message": "Invalid server response (junk)." + }, + "status.malformed-xml": { + "message": "Could not parse XML. Check event log for details." + }, + "status.modified": { + "message": "Local modifications" + }, + "status.network": { + "message": "Could not connect to server (##replace.1##)." + }, + "status.networkerror": { + "message": "Could not connect to server." + }, + "status.nosupportedeasversion": { + "message": "Server does not support ActiveSync v2.5 or v14.0 (only ##replace.1##). TbSync will not work with this ActiveSync server." + }, + "status.notargets": { + "message": "Aborting Sync, because sync targets could not be created." + }, + "status.notsupportedeasversion": { + "message": "Server does not support selected ActiveSync v##replace.1## (only ##replace.2##)." + }, + "status.notsyncronized": { + "message": "Account needs to be synchronized, at least one item is out of sync." + }, + "status.nouserhost": { + "message": "Missing username and/or server. Please provide those values." + }, + "status.pending": { + "message": "Waiting to be synchronized" + }, + "status.policy.2": { + "message": "There is no policy for this client. Contact your server administrator or disable provisioning for this account." + }, + "status.policy.3": { + "message": "Unknown PolicyType value. Contact your server administrator or disable provisioning for this account." + }, + "status.policy.4": { + "message": "The policy data on the server is corrupted (possibly tampered with). Contact your server administrator or disable provisioning for this account." + }, + "status.policy.5": { + "message": "The client is acknowledging the wrong policy key. Contact your server administrator or disable provisioning for this account." + }, + "status.provision": { + "message": "Provisioning failed with status <##replace.1##>" + }, + "status.response-contains-no-data": { + "message": "Response from the server contains no data." + }, + "status.resync-loop": { + "message": "There was an error from which we could not recover by resyncing the account. Please disable the account and try again. (Error: resync loop)" + }, + "status.security": { + "message": "Could not establish a secure connection. Are you using a self-signed or otherwise untrusted certificate without importing it into Thunderbird? (##replace.1##)" + }, + "status.skipped": { + "message": "Not yet supported, skipped" + }, + "status.syncing": { + "message": "Synchronizing" + }, + "status.timeout": { + "message": "Communication timeout." + }, + "status.wbxml-parse-error": { + "message": "Server sends unreadable response." + }, + "status.wbxmlerror": { + "message": "Sync failed. Server responded with status <##replace.1##>." + }, + "status.wbxmlmissingfield": { + "message": "ActiveSync protocol violation: Mandatory field <##replace.1##> is missing from server response." + }, + "syncstate.accountdone": { + "message": "Finished account" + }, + "syncstate.done": { + "message": "Preparing next item for synchronization" + }, + "syncstate.eval.response.autodiscover": { + "message": "Processing updated server settings" + }, + "syncstate.eval.response.deletefolder": { + "message": "Folder deleted" + }, + "syncstate.eval.response.estimate": { + "message": "Processing change estimate" + }, + "syncstate.eval.response.folders": { + "message": "Processing folder list update" + }, + "syncstate.eval.response.localchanges": { + "message": "Processing acknowledgment of local changes" + }, + "syncstate.eval.response.localdeletes": { + "message": "Processing acknowledgment of local deletes" + }, + "syncstate.eval.response.options": { + "message": "Processing server options" + }, + "syncstate.eval.response.provision": { + "message": "Processing provision" + }, + "syncstate.eval.response.remotechanges": { + "message": "Processing remote changes" + }, + "syncstate.eval.response.revertlocalchanges": { + "message": "Reverting local changes" + }, + "syncstate.eval.response.setdeviceinfo": { + "message": "Sending device information" + }, + "syncstate.eval.response.synckey": { + "message": "Processing SyncKey" + }, + "syncstate.prepare.request.autodiscover": { + "message": "Requesting updated server settings" + }, + "syncstate.prepare.request.deletefolder": { + "message": "Preparing to delete folder" + }, + "syncstate.prepare.request.estimate": { + "message": "Requesting change estimate" + }, + "syncstate.prepare.request.folders": { + "message": "Sending folder list update" + }, + "syncstate.prepare.request.localchanges": { + "message": "Sending local changes" + }, + "syncstate.prepare.request.localdeletes": { + "message": "Sending local deletes" + }, + "syncstate.prepare.request.options": { + "message": "Requesting server options" + }, + "syncstate.prepare.request.provision": { + "message": "Requesting provision" + }, + "syncstate.prepare.request.remotechanges": { + "message": "Requesting remote changes" + }, + "syncstate.prepare.request.revertlocalchanges": { + "message": "Collecting local changes" + }, + "syncstate.prepare.request.setdeviceinfo": { + "message": "Sending device information" + }, + "syncstate.prepare.request.synckey": { + "message": "Requesting SyncKey" + }, + "syncstate.preparing": { + "message": "Preparing next item for synchronization" + }, + "syncstate.send.request.autodiscover": { + "message": "Waiting for updated server settings" + }, + "syncstate.send.request.deletefolder": { + "message": "Waiting for folder to be deleted" + }, + "syncstate.send.request.estimate": { + "message": "Waiting for change estimate" + }, + "syncstate.send.request.folders": { + "message": "Waiting for folder list update" + }, + "syncstate.send.request.localchanges": { + "message": "Waiting for acknowledgment of local changes" + }, + "syncstate.send.request.localdeletes": { + "message": "Waiting for acknowledgment of local deletes" + }, + "syncstate.send.request.options": { + "message": "Waiting for server options" + }, + "syncstate.send.request.provision": { + "message": "Waiting for provision" + }, + "syncstate.send.request.remotechanges": { + "message": "Waiting for remote changes" + }, + "syncstate.send.request.revertlocalchanges": { + "message": "Waiting for most recent versions" + }, + "syncstate.send.request.setdeviceinfo": { + "message": "Sending device information" + }, + "syncstate.send.request.synckey": { + "message": "Waiting for SyncKey" + }, + "syncstate.syncing": { + "message": "Initialize synchronization" + } +} diff -Nru eas4tbsync-4.11/_locales/es/messages.json eas4tbsync-4.17/_locales/es/messages.json --- eas4tbsync-4.11/_locales/es/messages.json 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/_locales/es/messages.json 2025-05-15 11:21:18.000000000 +0000 @@ -1,566 +1,566 @@ -{ - "abCard.Anniversary": { - "message": "Aniversario:" - }, - "abCard.AssistantName": { - "message": "Asistente:" - }, - "abCard.AssistantPhoneNumber": { - "message": "Teléfono de asistente:" - }, - "abCard.Business2PhoneNumber": { - "message": "Teléfono de trabajo alternativo:" - }, - "abCard.BusinessFaxNumber": { - "message": "Fax de trabajo:" - }, - "abCard.CarPhoneNumber": { - "message": "Teléfono del coche:" - }, - "abCard.CompanyMainPhone": { - "message": "Teléfono del trabajo:" - }, - "abCard.Email3Address": { - "message": "Correo electrónico alternativo:" - }, - "abCard.Home2PhoneNumber": { - "message": "Teléfono de casa alternativo:" - }, - "abCard.ManagerName": { - "message": "Jefe:" - }, - "abCard.MiddleName": { - "message": "Segundo nombre:" - }, - "abCard.OtherAddress": { - "message": "Dirección:" - }, - "abCard.OtherCity": { - "message": "Ciudad:" - }, - "abCard.OtherCountry": { - "message": "País:" - }, - "abCard.OtherState": { - "message": "Estado:" - }, - "abCard.OtherZip": { - "message": "Código postal:" - }, - "abCard.RadioPhoneNumber": { - "message": "Radioteléfono:" - }, - "abCard.Spouse": { - "message": "Pareja:" - }, - "abCard.header.eas": { - "message": "Otros campos (EAS)" - }, - "abCard.header.homenumbers": { - "message": "Números de casa adicionales:" - }, - "abCard.header.messaging": { - "message": "Mensajes:" - }, - "abCard.header.otheraddress": { - "message": "Otra dirección (EAS)" - }, - "abCard.header.othernumbers": { - "message": "Números adicionales:" - }, - "abCard.header.people": { - "message": "Personas:" - }, - "abCard.header.worknumbers": { - "message": "Números de trabajo adicionales:" - }, - "acl.readonly": { - "message": "Acceso de solo lectura al servidor (revertir cambios locales)" - }, - "acl.readwrite": { - "message": "Leer y escribir en el servidor" - }, - "add.description": { - "message": "Seleccione una de las opciones de configuración del servidor disponibles y escriba los detalles solicitados. " - }, - "add.name": { - "message": "Nombre de cuenta:" - }, - "add.ok": { - "message": "Añadir cuenta" - }, - "add.password": { - "message": "Contraseña:" - }, - "add.server": { - "message": "Configuración del servidor:" - }, - "add.shortdescription": { - "message": "Información de la cuenta" - }, - "add.title": { - "message": "Añadir una cuenta de Exchange ActiveSync a TbSync" - }, - "add.url": { - "message": "Dirección del servidor:" - }, - "add.urldescription": { - "message": "La dirección básica del servidor debería ser suficiente (por ejemplo, correo.servidor.com). Sin embargo, también es posible proporcionar la URL completa (por ejemplo, https://correo.servidor.com/Servidor-Microsoft-ActiveSync)." - }, - "add.user": { - "message": "Nombre de usuario (correo electrónico):" - }, - "autocomplete.serverdirectory": { - "message": "servidor de directorio global" - }, - "autodiscover.Failed": { - "message": "Ha fallado la detección automática del usuario «##user##». Es posible que las credenciales sean incorrectas, que su proveedor de ActiveSync tengo a un problema eventual o que no admita la detección automática." - }, - "autodiscover.NeedEmail": { - "message": "La detección automática requiere una dirección de correo electrónico válida como nombre de usuario." - }, - "autodiscover.Ok": { - "message": "La detección automática ha sido correcta. Ya puede revisar los ajustes opcionales y establecer la conexión de sincronización." - }, - "autodiscover.Querying": { - "message": "Buscando ajustes…" - }, - "config.auto": { - "message": "Configuración del servidor de ActiveSync (detección automática)" - }, - "config.custom": { - "message": "Configuración del servidor de ActiveSync" - }, - "deletefolder.confirm": { - "message": "¿Realmente quiere ELIMINAR DEFINITIVAMENTE la carpeta «##replace.1##» de la papelera?" - }, - "deletefolder.menuentry": { - "message": "Eliminar definitivamente la carpeta «##replace.1##» de la papelera" - }, - "deletefolder.notallowed": { - "message": "Cancele la suscripción a la carpeta «##replace.1##» para poder eliminarla de la papelera." - }, - "extensionDescription": { - "message": "Añade soporte para sincronización de cuentas de Exchange ActiveSync a TbSync (contactos, tareas y calendarios)." - }, - "extensionName": { - "message": "Proveedor de Exchange ActiveSync" - }, - "helplink.BadItemSkipped": { - "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped" - }, - "helplink.global.clientdenied": { - "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F" - }, - "helplink.security": { - "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F" - }, - "manager.tabs.accountsettings": { - "message": "Ajustes de la cuenta" - }, - "manager.tabs.outOfOffice": { - "message": "Respuesta automática" - }, - "manager.tabs.syncsettings": { - "message": "Opciones" - }, - "newaccount.add_auto": { - "message": "Detectar ajustes automáticamente y añadir cuenta" - }, - "newaccount.add_custom": { - "message": "Añadir cuenta" - }, - "pref.AccountName": { - "message": "Descripción" - }, - "pref.ActiveSyncVersion": { - "message": "Versión de ActiveSync" - }, - "pref.DeviceId": { - "message": "ID de dispositivo de ActiveSync" - }, - "pref.ServerName": { - "message": "Dirección del servidor" - }, - "pref.ServerNameDescription": { - "message": "por ejemplo, correo.servidor.com" - }, - "pref.ShowTrashedFolders": { - "message": "Mostrar carpetas encontradas en la papelera" - }, - "pref.UserName": { - "message": "Nombre de usuario" - }, - "pref.UserNameDescription": { - "message": "El nombre de usuario suele ser la dirección de correo electrónico de su cuenta." - }, - "pref.autodetect": { - "message": "mejor disponible" - }, - "pref.birthday": { - "message": "Enviar información de cumpleaños" - }, - "pref.calendaroptions": { - "message": "Opciones de calendario" - }, - "pref.contactoptions": { - "message": "Opciones de contactos" - }, - "pref.displayoverride": { - "message": "Reemplazar nombre de pantalla con «Nombre» + «Segundo nombre»" - }, - "pref.generaloptions": { - "message": "Opciones generales" - }, - "pref.provision": { - "message": "Forzar aprovisionamiento (requerido por Kerio)" - }, - "pref.seperator.comma": { - "message": "Coma" - }, - "pref.seperator.description": { - "message": "Separador para campo de dirección en varias líneas." - }, - "pref.seperator.linebreak": { - "message": "Salto de línea" - }, - "pref.synclimit.1month": { - "message": "desde 4 semanas atrás" - }, - "pref.synclimit.2weeks": { - "message": "desde 2 semanas atrás" - }, - "pref.synclimit.3month": { - "message": "desde 3 meses atrás" - }, - "pref.synclimit.6month": { - "message": "desde 6 meses atrás" - }, - "pref.synclimit.all": { - "message": "todo" - }, - "pref.synclimit.description": { - "message": "Periodo de sincronización: " - }, - "pref.usehttps": { - "message": "Usar conexión segura (conectar mediante https)" - }, - "recyclebin": { - "message": "Papelera" - }, - "servertype.auto": { - "message": "Configuración automática" - }, - "servertype.custom": { - "message": "Configuración personalizada" - }, - "servertype.description.auto": { - "message": "Es posible detectar la configuración de muchos servidores de ActiveSync con solo proporcionar su dirección de correo electrónico." - }, - "servertype.description.custom": { - "message": "Configure la cuenta proporcionando manualmente la dirección del servidor al que desea conectar." - }, - "servertype.description.office365": { - "message": "Las cuentas conectadas a Office 365 utilizan un proceso de autenticación avanzado, llamado OAuth 2.0, que también admite autenticación multifactor (MFA)." - }, - "servertype.office365": { - "message": "Microsoft Office 365" - }, - "servertype.unlock": { - "message": "Haga doble clic para desbloquear todos los ajustes predefinidos del servidor." - }, - "status.401": { - "message": "No ha sido posible autentificar, compruebe el nombre de usuario y contraseña (error HTTP 401)." - }, - "status.403": { - "message": "El servidor rechazó la conexión (prohibida) (error HTTP 403)." - }, - "status.404": { - "message": "Usuario no encontrado (error HTTP 404)." - }, - "status.449": { - "message": "El servidor solicita aprovisionamiento (error HTTP 449)." - }, - "status.500": { - "message": "Error de servidor desconocido (error HTTP 500)." - }, - "status.503": { - "message": "Servicio no disponible (error HTTP 503)." - }, - "status.BadItemSkipped": { - "message": "Objeto incorrecto omitido: ##replace.1##" - }, - "status.FolderDelete.3": { - "message": "No es posible eliminar una carpeta del sistema (estado 3)" - }, - "status.FolderDelete.4": { - "message": "La carpeta no existe (estado 4), resincronizando" - }, - "status.FolderDelete.6": { - "message": "No ha sido posible completar el comando, se ha producido un error en el servidor (estado 6)" - }, - "status.FolderDelete.9": { - "message": "Clave de sincronización no válida (estado 9), resincronizando" - }, - "status.FolderSync.9": { - "message": "Clave de sincronización no válida (estado 9), resincronizando" - }, - "status.InvalidServerOptions": { - "message": "El servidor no proporciona información sobre las versiones de ActiveSync compatibles. ¿Está EAS bloqueado para este usuario o este cliente (TbSync)? Puede intentar configurar la versión de ActiveSync manualmente." - }, - "status.OK": { - "message": "OK" - }, - "status.ServerRejectedRequest": { - "message": "El servidor de EAS rechazó la última petición." - }, - "status.ServerRejectedSomeItems": { - "message": "El servidor de EAS no aceptó ##replace.1## elementos." - }, - "status.Sync.12": { - "message": "Jerarquía de carpetas cambiada (estado 12), resincronizando" - }, - "status.Sync.3": { - "message": "Clave de sincronización no válida (estado 3), resincronizando" - }, - "status.Sync.4": { - "message": "Solicitud mal formada (estado 4)" - }, - "status.Sync.5": { - "message": "Problemas temporales del servidor o elemento no válido (estado 5)" - }, - "status.Sync.6": { - "message": "Elemento no válido (estado 6)" - }, - "status.Sync.8": { - "message": "Objeto no encontrado (estado 8)" - }, - "status.aborted": { - "message": "Sin sincronizar" - }, - "status.disabled": { - "message": "Desactivado" - }, - "status.empty-response": { - "message": "El servidor envía una respuesta vacía inesperada." - }, - "status.forbiddenCalendarItemInTasksFolder": { - "message": "Elemento de calendario prohibido en una carpeta de tareas (reorganice, por favor)" - }, - "status.forbiddenTasksItemInCalendarFolder": { - "message": "Elemento de tareas prohibido en una carpeta de calendario (reorganice, por favor)" - }, - "status.global.101": { - "message": "La solicitud contiene WBXML pero no se pudo decodificar como XML (error EAS 101)." - }, - "status.global.102": { - "message": "La solicitud contiene WBXML pero no se pudo decodificar como XML (error EAS 102)." - }, - "status.global.103": { - "message": "El XML proporcionado en la solicitud no cumple los requisitos de protocolo (error EAS 103)." - }, - "status.global.110": { - "message": "El servidor informó de un error interno y no deberíamos volver a intentarlo inmediatamente. La sincronización periódica automática se ha desactivado durante 30 minutos (error EAS 110)." - }, - "status.global.clientdenied": { - "message": "El servidor de EAS notifica <##replace.2##> (estado ##replace.1##) y no permite a TbSync acceder a tu cuenta." - }, - "status.httperror": { - "message": "Error de comunicación (estado HTTP ##replace.1##)." - }, - "status.invalid": { - "message": "Respuesta del servidor no válida (corrupta)." - }, - "status.malformed-xml": { - "message": "No ha sido posible analizar el XML. Compruebe el registro de eventos para más detalles." - }, - "status.modified": { - "message": "Modificaciones locales" - }, - "status.network": { - "message": "No ha sido posible conectar al servidor (##replace.1##)." - }, - "status.networkerror": { - "message": "No ha sido posible conectar al servidor." - }, - "status.nosupportedeasversion": { - "message": "El servidor no es compatible con las versiones de ActiveSync 2.5 y 14.0 (solo ##replace.1##). TbSync no funcionará con este servidor de ActiveSync." - }, - "status.notargets": { - "message": "Sincronización interrumpida porque no se han podido crear los destinos de la sincronización." - }, - "status.notsupportedeasversion": { - "message": "El servidor no es compatible con la versión seleccionada de ActiveSync, ##replace.1## (solo ##replace.2##)." - }, - "status.notsyncronized": { - "message": "Es necesario sincronizar la cuenta: uno o varios elementos están sin sincronizar." - }, - "status.nouserhost": { - "message": "Falta el nombre de usuario o el servidor. Por favor, proporcione esos datos." - }, - "status.pending": { - "message": "Esperando sincronización" - }, - "status.policy.2": { - "message": "No hay ninguna directiva para este cliente. Póngase en contacto con el administrador del servidor o deshabilite el aprovisionamiento de esta cuenta." - }, - "status.policy.3": { - "message": "El valor PolicyType es desconocido. Póngase en contacto con el administrador del servidor o deshabilite el aprovisionamiento de esta cuenta." - }, - "status.policy.4": { - "message": "Los datos de directivas del servidor están dañados (posiblemente manipulados). Póngase en contacto con el administrador del servidor o deshabilite el aprovisionamiento de esta cuenta." - }, - "status.policy.5": { - "message": "El cliente está reconociendo la clave de directiva incorrecta. Póngase en contacto con el administrador del servidor o deshabilite el aprovisionamiento de esta cuenta." - }, - "status.provision": { - "message": "El aprovisionamiento falló con el estado <##replace.1##>" - }, - "status.response-contains-no-data": { - "message": "La respuesta del servidor no contiene datos." - }, - "status.resync-loop": { - "message": "Se ha producido un error que no se pudo corregir volviendo a sincronizar la cuenta. Desactive la cuenta e inténtelo de nuevo (error: bucle de resincronización)." - }, - "status.security": { - "message": "No ha sido posible establecer una conexión segura. ¿Estás usando un certificado autofirmado, o que no es de confianza, sin importarlo a Thunderbird? (##replace.1##)" - }, - "status.skipped": { - "message": "No se admite aún; omitido" - }, - "status.syncing": { - "message": "Sincronizando" - }, - "status.timeout": { - "message": "Tiempo de comunicación agotado." - }, - "status.wbxml-parse-error": { - "message": "El servidor envía una respuesta ilegible." - }, - "status.wbxmlerror": { - "message": "Error al sincronizar. El servidor respondió con el estado <##replace.1##>." - }, - "status.wbxmlmissingfield": { - "message": "Violación del protocolo de ActiveSync: falta el campo obligatorio <##replace.1##> en la respuesta del servidor." - }, - "syncstate.accountdone": { - "message": "Cuenta finalizada" - }, - "syncstate.done": { - "message": "Preparando el siguiente elemento para la sincronización" - }, - "syncstate.eval.response.autodiscover": { - "message": "Procesando la configuración actualizada del servidor" - }, - "syncstate.eval.response.deletefolder": { - "message": "Carpeta eliminada" - }, - "syncstate.eval.response.estimate": { - "message": "Procesando estimación de cambio" - }, - "syncstate.eval.response.folders": { - "message": "Procesando la lista de carpetas actualizada" - }, - "syncstate.eval.response.localchanges": { - "message": "Procesando el reconocimiento de cambios locales" - }, - "syncstate.eval.response.localdeletes": { - "message": "Procesando el reconocimiento de eliminaciones locales" - }, - "syncstate.eval.response.options": { - "message": "Procesando opciones del servidor" - }, - "syncstate.eval.response.provision": { - "message": "Procesando aprovisionamiento" - }, - "syncstate.eval.response.remotechanges": { - "message": "Procesando los cambios remotos" - }, - "syncstate.eval.response.revertlocalchanges": { - "message": "Revirtiendo los cambios locales" - }, - "syncstate.eval.response.setdeviceinfo": { - "message": "Enviando información del dispositivo" - }, - "syncstate.eval.response.synckey": { - "message": "Procesando SyncKey" - }, - "syncstate.prepare.request.autodiscover": { - "message": "Solicitando la configuración actualizada del servidor" - }, - "syncstate.prepare.request.deletefolder": { - "message": "Preparando la eliminación de la carpeta" - }, - "syncstate.prepare.request.estimate": { - "message": "Solicitando estimación de cambios" - }, - "syncstate.prepare.request.folders": { - "message": "Enviando actualización de lista de carpetas" - }, - "syncstate.prepare.request.localchanges": { - "message": "Enviando los cambios locales" - }, - "syncstate.prepare.request.localdeletes": { - "message": "Enviando las eliminaciones locales" - }, - "syncstate.prepare.request.options": { - "message": "Solicitando opciones de servidor" - }, - "syncstate.prepare.request.provision": { - "message": "Solicitud de aprovisionamiento" - }, - "syncstate.prepare.request.remotechanges": { - "message": "Procesando los cambios remotos" - }, - "syncstate.prepare.request.revertlocalchanges": { - "message": "Recopilando los cambios locales" - }, - "syncstate.prepare.request.setdeviceinfo": { - "message": "Enviando información del dispositivo" - }, - "syncstate.prepare.request.synckey": { - "message": "Solicitando SyncKey" - }, - "syncstate.preparing": { - "message": "Preparando el siguiente elemento para la sincronización" - }, - "syncstate.send.request.autodiscover": { - "message": "Esperando la configuración actualizada del servidor" - }, - "syncstate.send.request.deletefolder": { - "message": "Esperando la eliminación de la carpeta" - }, - "syncstate.send.request.estimate": { - "message": "Esperando la estimación de cambios" - }, - "syncstate.send.request.folders": { - "message": "Esperando la actualización de la lista de carpetas" - }, - "syncstate.send.request.localchanges": { - "message": "Esperando el reconocimiento de cambios locales" - }, - "syncstate.send.request.localdeletes": { - "message": "Esperando el reconocimiento de eliminaciones locales" - }, - "syncstate.send.request.options": { - "message": "Esperando las opciones del servidor" - }, - "syncstate.send.request.provision": { - "message": "Esperando el aprovisionamiento" - }, - "syncstate.send.request.remotechanges": { - "message": "Esperando los cambios remotos" - }, - "syncstate.send.request.revertlocalchanges": { - "message": "Esperando las versiones más recientes" - }, - "syncstate.send.request.setdeviceinfo": { - "message": "Enviando información del dispositivo" - }, - "syncstate.send.request.synckey": { - "message": "Esperando a SyncKey" - }, - "syncstate.syncing": { - "message": "Iniciar sincronización" - } -} +{ + "abCard.Anniversary": { + "message": "Aniversario:" + }, + "abCard.AssistantName": { + "message": "Asistente:" + }, + "abCard.AssistantPhoneNumber": { + "message": "Teléfono de asistente:" + }, + "abCard.Business2PhoneNumber": { + "message": "Teléfono de trabajo alternativo:" + }, + "abCard.BusinessFaxNumber": { + "message": "Fax de trabajo:" + }, + "abCard.CarPhoneNumber": { + "message": "Teléfono del coche:" + }, + "abCard.CompanyMainPhone": { + "message": "Teléfono del trabajo:" + }, + "abCard.Email3Address": { + "message": "Correo electrónico alternativo:" + }, + "abCard.Home2PhoneNumber": { + "message": "Teléfono de casa alternativo:" + }, + "abCard.ManagerName": { + "message": "Jefe:" + }, + "abCard.MiddleName": { + "message": "Segundo nombre:" + }, + "abCard.OtherAddress": { + "message": "Dirección:" + }, + "abCard.OtherCity": { + "message": "Ciudad:" + }, + "abCard.OtherCountry": { + "message": "País:" + }, + "abCard.OtherState": { + "message": "Estado:" + }, + "abCard.OtherZip": { + "message": "Código postal:" + }, + "abCard.RadioPhoneNumber": { + "message": "Radioteléfono:" + }, + "abCard.Spouse": { + "message": "Pareja:" + }, + "abCard.header.eas": { + "message": "Otros campos (EAS)" + }, + "abCard.header.homenumbers": { + "message": "Números de casa adicionales:" + }, + "abCard.header.messaging": { + "message": "Mensajes:" + }, + "abCard.header.otheraddress": { + "message": "Otra dirección (EAS)" + }, + "abCard.header.othernumbers": { + "message": "Números adicionales:" + }, + "abCard.header.people": { + "message": "Personas:" + }, + "abCard.header.worknumbers": { + "message": "Números de trabajo adicionales:" + }, + "acl.readonly": { + "message": "Acceso de solo lectura al servidor (revertir cambios locales)" + }, + "acl.readwrite": { + "message": "Leer y escribir en el servidor" + }, + "add.description": { + "message": "Seleccione una de las opciones de configuración del servidor disponibles y escriba los detalles solicitados. " + }, + "add.name": { + "message": "Nombre de cuenta:" + }, + "add.ok": { + "message": "Añadir cuenta" + }, + "add.password": { + "message": "Contraseña:" + }, + "add.server": { + "message": "Configuración del servidor:" + }, + "add.shortdescription": { + "message": "Información de la cuenta" + }, + "add.title": { + "message": "Añadir una cuenta de Exchange ActiveSync a TbSync" + }, + "add.url": { + "message": "Dirección del servidor:" + }, + "add.urldescription": { + "message": "La dirección básica del servidor debería ser suficiente (por ejemplo, correo.servidor.com). Sin embargo, también es posible proporcionar la URL completa (por ejemplo, https://correo.servidor.com/Servidor-Microsoft-ActiveSync)." + }, + "add.user": { + "message": "Nombre de usuario (correo electrónico):" + }, + "autocomplete.serverdirectory": { + "message": "servidor de directorio global" + }, + "autodiscover.Failed": { + "message": "Ha fallado la detección automática del usuario «##user##». Es posible que las credenciales sean incorrectas, que su proveedor de ActiveSync tengo a un problema eventual o que no admita la detección automática." + }, + "autodiscover.NeedEmail": { + "message": "La detección automática requiere una dirección de correo electrónico válida como nombre de usuario." + }, + "autodiscover.Ok": { + "message": "La detección automática ha sido correcta. Ya puede revisar los ajustes opcionales y establecer la conexión de sincronización." + }, + "autodiscover.Querying": { + "message": "Buscando ajustes…" + }, + "config.auto": { + "message": "Configuración del servidor de ActiveSync (detección automática)" + }, + "config.custom": { + "message": "Configuración del servidor de ActiveSync" + }, + "deletefolder.confirm": { + "message": "¿Realmente quiere ELIMINAR DEFINITIVAMENTE la carpeta «##replace.1##» de la papelera?" + }, + "deletefolder.menuentry": { + "message": "Eliminar definitivamente la carpeta «##replace.1##» de la papelera" + }, + "deletefolder.notallowed": { + "message": "Cancele la suscripción a la carpeta «##replace.1##» para poder eliminarla de la papelera." + }, + "extensionDescription": { + "message": "Añade soporte para sincronización de cuentas de Exchange ActiveSync a TbSync (contactos, tareas y calendarios)." + }, + "extensionName": { + "message": "Proveedor de Exchange ActiveSync" + }, + "helplink.BadItemSkipped": { + "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped" + }, + "helplink.global.clientdenied": { + "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F" + }, + "helplink.security": { + "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F" + }, + "manager.tabs.accountsettings": { + "message": "Ajustes de la cuenta" + }, + "manager.tabs.outOfOffice": { + "message": "Respuesta automática" + }, + "manager.tabs.syncsettings": { + "message": "Opciones" + }, + "newaccount.add_auto": { + "message": "Detectar ajustes automáticamente y añadir cuenta" + }, + "newaccount.add_custom": { + "message": "Añadir cuenta" + }, + "pref.AccountName": { + "message": "Descripción" + }, + "pref.ActiveSyncVersion": { + "message": "Versión de ActiveSync" + }, + "pref.DeviceId": { + "message": "ID de dispositivo de ActiveSync" + }, + "pref.ServerName": { + "message": "Dirección del servidor" + }, + "pref.ServerNameDescription": { + "message": "por ejemplo, correo.servidor.com" + }, + "pref.ShowTrashedFolders": { + "message": "Mostrar carpetas encontradas en la papelera" + }, + "pref.UserName": { + "message": "Nombre de usuario" + }, + "pref.UserNameDescription": { + "message": "El nombre de usuario suele ser la dirección de correo electrónico de su cuenta." + }, + "pref.autodetect": { + "message": "mejor disponible" + }, + "pref.birthday": { + "message": "Enviar información de cumpleaños" + }, + "pref.calendaroptions": { + "message": "Opciones de calendario" + }, + "pref.contactoptions": { + "message": "Opciones de contactos" + }, + "pref.displayoverride": { + "message": "Reemplazar nombre de pantalla con «Nombre» + «Segundo nombre»" + }, + "pref.generaloptions": { + "message": "Opciones generales" + }, + "pref.provision": { + "message": "Forzar aprovisionamiento (requerido por Kerio)" + }, + "pref.seperator.comma": { + "message": "Coma" + }, + "pref.seperator.description": { + "message": "Separador para campo de dirección en varias líneas." + }, + "pref.seperator.linebreak": { + "message": "Salto de línea" + }, + "pref.synclimit.1month": { + "message": "desde 4 semanas atrás" + }, + "pref.synclimit.2weeks": { + "message": "desde 2 semanas atrás" + }, + "pref.synclimit.3month": { + "message": "desde 3 meses atrás" + }, + "pref.synclimit.6month": { + "message": "desde 6 meses atrás" + }, + "pref.synclimit.all": { + "message": "todo" + }, + "pref.synclimit.description": { + "message": "Periodo de sincronización: " + }, + "pref.usehttps": { + "message": "Usar conexión segura (conectar mediante https)" + }, + "recyclebin": { + "message": "Papelera" + }, + "servertype.auto": { + "message": "Configuración automática" + }, + "servertype.custom": { + "message": "Configuración personalizada" + }, + "servertype.description.auto": { + "message": "Es posible detectar la configuración de muchos servidores de ActiveSync con solo proporcionar su dirección de correo electrónico." + }, + "servertype.description.custom": { + "message": "Configure la cuenta proporcionando manualmente la dirección del servidor al que desea conectar." + }, + "servertype.description.office365": { + "message": "Las cuentas conectadas a Office 365 utilizan un proceso de autenticación avanzado, llamado OAuth 2.0, que también admite autenticación multifactor (MFA)." + }, + "servertype.office365": { + "message": "Microsoft Office 365" + }, + "servertype.unlock": { + "message": "Haga doble clic para desbloquear todos los ajustes predefinidos del servidor." + }, + "status.401": { + "message": "No ha sido posible autentificar, compruebe el nombre de usuario y contraseña (error HTTP 401)." + }, + "status.403": { + "message": "El servidor rechazó la conexión (prohibida) (error HTTP 403)." + }, + "status.404": { + "message": "Usuario no encontrado (error HTTP 404)." + }, + "status.449": { + "message": "El servidor solicita aprovisionamiento (error HTTP 449)." + }, + "status.500": { + "message": "Error de servidor desconocido (error HTTP 500)." + }, + "status.503": { + "message": "Servicio no disponible (error HTTP 503)." + }, + "status.BadItemSkipped": { + "message": "Objeto incorrecto omitido: ##replace.1##" + }, + "status.FolderDelete.3": { + "message": "No es posible eliminar una carpeta del sistema (estado 3)" + }, + "status.FolderDelete.4": { + "message": "La carpeta no existe (estado 4), resincronizando" + }, + "status.FolderDelete.6": { + "message": "No ha sido posible completar el comando, se ha producido un error en el servidor (estado 6)" + }, + "status.FolderDelete.9": { + "message": "Clave de sincronización no válida (estado 9), resincronizando" + }, + "status.FolderSync.9": { + "message": "Clave de sincronización no válida (estado 9), resincronizando" + }, + "status.InvalidServerOptions": { + "message": "El servidor no proporciona información sobre las versiones de ActiveSync compatibles. ¿Está EAS bloqueado para este usuario o este cliente (TbSync)? Puede intentar configurar la versión de ActiveSync manualmente." + }, + "status.OK": { + "message": "OK" + }, + "status.ServerRejectedRequest": { + "message": "El servidor de EAS rechazó la última petición." + }, + "status.ServerRejectedSomeItems": { + "message": "El servidor de EAS no aceptó ##replace.1## elementos." + }, + "status.Sync.12": { + "message": "Jerarquía de carpetas cambiada (estado 12), resincronizando" + }, + "status.Sync.3": { + "message": "Clave de sincronización no válida (estado 3), resincronizando" + }, + "status.Sync.4": { + "message": "Solicitud mal formada (estado 4)" + }, + "status.Sync.5": { + "message": "Problemas temporales del servidor o elemento no válido (estado 5)" + }, + "status.Sync.6": { + "message": "Elemento no válido (estado 6)" + }, + "status.Sync.8": { + "message": "Objeto no encontrado (estado 8)" + }, + "status.aborted": { + "message": "Sin sincronizar" + }, + "status.disabled": { + "message": "Desactivado" + }, + "status.empty-response": { + "message": "El servidor envía una respuesta vacía inesperada." + }, + "status.forbiddenCalendarItemInTasksFolder": { + "message": "Elemento de calendario prohibido en una carpeta de tareas (reorganice, por favor)" + }, + "status.forbiddenTasksItemInCalendarFolder": { + "message": "Elemento de tareas prohibido en una carpeta de calendario (reorganice, por favor)" + }, + "status.global.101": { + "message": "La solicitud contiene WBXML pero no se pudo decodificar como XML (error EAS 101)." + }, + "status.global.102": { + "message": "La solicitud contiene WBXML pero no se pudo decodificar como XML (error EAS 102)." + }, + "status.global.103": { + "message": "El XML proporcionado en la solicitud no cumple los requisitos de protocolo (error EAS 103)." + }, + "status.global.110": { + "message": "El servidor informó de un error interno y no deberíamos volver a intentarlo inmediatamente. La sincronización periódica automática se ha desactivado durante 30 minutos (error EAS 110)." + }, + "status.global.clientdenied": { + "message": "El servidor de EAS notifica <##replace.2##> (estado ##replace.1##) y no permite a TbSync acceder a tu cuenta." + }, + "status.httperror": { + "message": "Error de comunicación (estado HTTP ##replace.1##)." + }, + "status.invalid": { + "message": "Respuesta del servidor no válida (corrupta)." + }, + "status.malformed-xml": { + "message": "No ha sido posible analizar el XML. Compruebe el registro de eventos para más detalles." + }, + "status.modified": { + "message": "Modificaciones locales" + }, + "status.network": { + "message": "No ha sido posible conectar al servidor (##replace.1##)." + }, + "status.networkerror": { + "message": "No ha sido posible conectar al servidor." + }, + "status.nosupportedeasversion": { + "message": "El servidor no es compatible con las versiones de ActiveSync 2.5 y 14.0 (solo ##replace.1##). TbSync no funcionará con este servidor de ActiveSync." + }, + "status.notargets": { + "message": "Sincronización interrumpida porque no se han podido crear los destinos de la sincronización." + }, + "status.notsupportedeasversion": { + "message": "El servidor no es compatible con la versión seleccionada de ActiveSync, ##replace.1## (solo ##replace.2##)." + }, + "status.notsyncronized": { + "message": "Es necesario sincronizar la cuenta: uno o varios elementos están sin sincronizar." + }, + "status.nouserhost": { + "message": "Falta el nombre de usuario o el servidor. Por favor, proporcione esos datos." + }, + "status.pending": { + "message": "Esperando sincronización" + }, + "status.policy.2": { + "message": "No hay ninguna directiva para este cliente. Póngase en contacto con el administrador del servidor o deshabilite el aprovisionamiento de esta cuenta." + }, + "status.policy.3": { + "message": "El valor PolicyType es desconocido. Póngase en contacto con el administrador del servidor o deshabilite el aprovisionamiento de esta cuenta." + }, + "status.policy.4": { + "message": "Los datos de directivas del servidor están dañados (posiblemente manipulados). Póngase en contacto con el administrador del servidor o deshabilite el aprovisionamiento de esta cuenta." + }, + "status.policy.5": { + "message": "El cliente está reconociendo la clave de directiva incorrecta. Póngase en contacto con el administrador del servidor o deshabilite el aprovisionamiento de esta cuenta." + }, + "status.provision": { + "message": "El aprovisionamiento falló con el estado <##replace.1##>" + }, + "status.response-contains-no-data": { + "message": "La respuesta del servidor no contiene datos." + }, + "status.resync-loop": { + "message": "Se ha producido un error que no se pudo corregir volviendo a sincronizar la cuenta. Desactive la cuenta e inténtelo de nuevo (error: bucle de resincronización)." + }, + "status.security": { + "message": "No ha sido posible establecer una conexión segura. ¿Estás usando un certificado autofirmado, o que no es de confianza, sin importarlo a Thunderbird? (##replace.1##)" + }, + "status.skipped": { + "message": "No se admite aún; omitido" + }, + "status.syncing": { + "message": "Sincronizando" + }, + "status.timeout": { + "message": "Tiempo de comunicación agotado." + }, + "status.wbxml-parse-error": { + "message": "El servidor envía una respuesta ilegible." + }, + "status.wbxmlerror": { + "message": "Error al sincronizar. El servidor respondió con el estado <##replace.1##>." + }, + "status.wbxmlmissingfield": { + "message": "Violación del protocolo de ActiveSync: falta el campo obligatorio <##replace.1##> en la respuesta del servidor." + }, + "syncstate.accountdone": { + "message": "Cuenta finalizada" + }, + "syncstate.done": { + "message": "Preparando el siguiente elemento para la sincronización" + }, + "syncstate.eval.response.autodiscover": { + "message": "Procesando la configuración actualizada del servidor" + }, + "syncstate.eval.response.deletefolder": { + "message": "Carpeta eliminada" + }, + "syncstate.eval.response.estimate": { + "message": "Procesando estimación de cambio" + }, + "syncstate.eval.response.folders": { + "message": "Procesando la lista de carpetas actualizada" + }, + "syncstate.eval.response.localchanges": { + "message": "Procesando el reconocimiento de cambios locales" + }, + "syncstate.eval.response.localdeletes": { + "message": "Procesando el reconocimiento de eliminaciones locales" + }, + "syncstate.eval.response.options": { + "message": "Procesando opciones del servidor" + }, + "syncstate.eval.response.provision": { + "message": "Procesando aprovisionamiento" + }, + "syncstate.eval.response.remotechanges": { + "message": "Procesando los cambios remotos" + }, + "syncstate.eval.response.revertlocalchanges": { + "message": "Revirtiendo los cambios locales" + }, + "syncstate.eval.response.setdeviceinfo": { + "message": "Enviando información del dispositivo" + }, + "syncstate.eval.response.synckey": { + "message": "Procesando SyncKey" + }, + "syncstate.prepare.request.autodiscover": { + "message": "Solicitando la configuración actualizada del servidor" + }, + "syncstate.prepare.request.deletefolder": { + "message": "Preparando la eliminación de la carpeta" + }, + "syncstate.prepare.request.estimate": { + "message": "Solicitando estimación de cambios" + }, + "syncstate.prepare.request.folders": { + "message": "Enviando actualización de lista de carpetas" + }, + "syncstate.prepare.request.localchanges": { + "message": "Enviando los cambios locales" + }, + "syncstate.prepare.request.localdeletes": { + "message": "Enviando las eliminaciones locales" + }, + "syncstate.prepare.request.options": { + "message": "Solicitando opciones de servidor" + }, + "syncstate.prepare.request.provision": { + "message": "Solicitud de aprovisionamiento" + }, + "syncstate.prepare.request.remotechanges": { + "message": "Procesando los cambios remotos" + }, + "syncstate.prepare.request.revertlocalchanges": { + "message": "Recopilando los cambios locales" + }, + "syncstate.prepare.request.setdeviceinfo": { + "message": "Enviando información del dispositivo" + }, + "syncstate.prepare.request.synckey": { + "message": "Solicitando SyncKey" + }, + "syncstate.preparing": { + "message": "Preparando el siguiente elemento para la sincronización" + }, + "syncstate.send.request.autodiscover": { + "message": "Esperando la configuración actualizada del servidor" + }, + "syncstate.send.request.deletefolder": { + "message": "Esperando la eliminación de la carpeta" + }, + "syncstate.send.request.estimate": { + "message": "Esperando la estimación de cambios" + }, + "syncstate.send.request.folders": { + "message": "Esperando la actualización de la lista de carpetas" + }, + "syncstate.send.request.localchanges": { + "message": "Esperando el reconocimiento de cambios locales" + }, + "syncstate.send.request.localdeletes": { + "message": "Esperando el reconocimiento de eliminaciones locales" + }, + "syncstate.send.request.options": { + "message": "Esperando las opciones del servidor" + }, + "syncstate.send.request.provision": { + "message": "Esperando el aprovisionamiento" + }, + "syncstate.send.request.remotechanges": { + "message": "Esperando los cambios remotos" + }, + "syncstate.send.request.revertlocalchanges": { + "message": "Esperando las versiones más recientes" + }, + "syncstate.send.request.setdeviceinfo": { + "message": "Enviando información del dispositivo" + }, + "syncstate.send.request.synckey": { + "message": "Esperando a SyncKey" + }, + "syncstate.syncing": { + "message": "Iniciar sincronización" + } +} diff -Nru eas4tbsync-4.11/_locales/fr/messages.json eas4tbsync-4.17/_locales/fr/messages.json --- eas4tbsync-4.11/_locales/fr/messages.json 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/_locales/fr/messages.json 2025-05-15 11:21:18.000000000 +0000 @@ -1,566 +1,566 @@ -{ - "abCard.Anniversary": { - "message": "Anniversaire :" - }, - "abCard.AssistantName": { - "message": "Assistant(e) :" - }, - "abCard.AssistantPhoneNumber": { - "message": "Téléphone Assistant(e) :" - }, - "abCard.Business2PhoneNumber": { - "message": "Téléphone Bureau Alternatif :" - }, - "abCard.BusinessFaxNumber": { - "message": "Fax de bureau :" - }, - "abCard.CarPhoneNumber": { - "message": "Téléphone Voiture :" - }, - "abCard.CompanyMainPhone": { - "message": "Téléphone de Bureau Principal :" - }, - "abCard.Email3Address": { - "message": "Courriel alternatif :" - }, - "abCard.Home2PhoneNumber": { - "message": "Téléphone Domicile Alternatif :" - }, - "abCard.ManagerName": { - "message": "Supérieur(e) :" - }, - "abCard.MiddleName": { - "message": "Deuxième prénom :" - }, - "abCard.OtherAddress": { - "message": "Adresse :" - }, - "abCard.OtherCity": { - "message": "Ville :" - }, - "abCard.OtherCountry": { - "message": "Pays :" - }, - "abCard.OtherState": { - "message": "État :" - }, - "abCard.OtherZip": { - "message": "Code postal :" - }, - "abCard.RadioPhoneNumber": { - "message": "Téléphone Radio :" - }, - "abCard.Spouse": { - "message": "Épou(x/se) :" - }, - "abCard.header.eas": { - "message": "Autres champs (EAS)" - }, - "abCard.header.homenumbers": { - "message": "Téléphones domicile supplémentaires :" - }, - "abCard.header.messaging": { - "message": "Messagerie :" - }, - "abCard.header.otheraddress": { - "message": "Autre Adresse (EAS)" - }, - "abCard.header.othernumbers": { - "message": "Numéros de téléphone supplémentaires :" - }, - "abCard.header.people": { - "message": "Personnes :" - }, - "abCard.header.worknumbers": { - "message": "Téléphones de bureau supplémentaires :" - }, - "acl.readonly": { - "message": "Accès au serveur en lecture seule (annule les modifications locales)" - }, - "acl.readwrite": { - "message": "Lecture et écriture sur le serveur" - }, - "add.description": { - "message": "Veuillez sélectionner une des options de configuration du serveur disponibles et entrer les détails demandés. " - }, - "add.name": { - "message": "Nom du compte :" - }, - "add.ok": { - "message": "Ajouter un compte" - }, - "add.password": { - "message": "Mot de passe :" - }, - "add.server": { - "message": "Configuration du serveur :" - }, - "add.shortdescription": { - "message": "Informations du compte" - }, - "add.title": { - "message": "Ajout d'un compte Exchange ActiveSync à TbSync" - }, - "add.url": { - "message": "Adresse du serveur :" - }, - "add.urldescription": { - "message": "Il devrait suffire de fournir uniquement l'adresse de base du serveur (par exemple : mail.votreserveur.com). Cependant, il est également possible de fournir l'URL complète (par exemple : https://mail.votreserveur.com/Microsoft-Server-ActiveSync)." - }, - "add.user": { - "message": "Nom d'utilisateur (adresse e-mail) :" - }, - "autocomplete.serverdirectory": { - "message": "annuaire global du serveur" - }, - "autodiscover.Failed": { - "message": "L'Autodiscover pour l'utilisateur <##user##> a échoué. Soit les informations d'identification fournies étaient erronées, soit votre fournisseur ActiveSync a un problème temporaire, soit il ne prend pas en charge l'Autodiscover." - }, - "autodiscover.NeedEmail": { - "message": "L'Autodiscover a besoin d'une adresse courriel valide comme nom d'utilisateur." - }, - "autodiscover.Ok": { - "message": "L'Autodiscover est terminée avec succès, vous pouvez maintenant vérifier les paramètres optionnels et établir la connexion de synchronisation." - }, - "autodiscover.Querying": { - "message": "Recherche de paramètres…" - }, - "config.auto": { - "message": "Configuration du serveur ActiveSync (Autodiscover)" - }, - "config.custom": { - "message": "Configuration du serveur ActiveSync" - }, - "deletefolder.confirm": { - "message": "Voulez-vous vraiment SUPPRIMER DÉFINITIVEMENT le dossier « ##replace.1##» de la corbeille ?" - }, - "deletefolder.menuentry": { - "message": "Supprimer définitivement le dossier « ##replace.1##» de la corbeille" - }, - "deletefolder.notallowed": { - "message": "Veuillez vous désabonner du dossier « ##replace.1##» avant d'essayer de le supprimer de la corbeille." - }, - "extensionDescription": { - "message": "Ajouter la prise en charge de la synchronisation des comptes Exchange ActiveSync à TbSync (contacts, tâches et calendriers)." - }, - "extensionName": { - "message": "Fournisseur pour Exchange ActiveSync" - }, - "helplink.BadItemSkipped": { - "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped" - }, - "helplink.global.clientdenied": { - "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F" - }, - "helplink.security": { - "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F" - }, - "manager.tabs.accountsettings": { - "message": "Paramètres du compte" - }, - "manager.tabs.outOfOffice": { - "message": "Répondeur automatique" - }, - "manager.tabs.syncsettings": { - "message": "Paramètres" - }, - "newaccount.add_auto": { - "message": "Paramètres Autodiscover et ajout de compte" - }, - "newaccount.add_custom": { - "message": "Ajouter un compte" - }, - "pref.AccountName": { - "message": "Description" - }, - "pref.ActiveSyncVersion": { - "message": "Version d'ActiveSync" - }, - "pref.DeviceId": { - "message": "ID de périphérique ActiveSync" - }, - "pref.ServerName": { - "message": "Adresse du serveur" - }, - "pref.ServerNameDescription": { - "message": "par exemple mail.votreserveur.com" - }, - "pref.ShowTrashedFolders": { - "message": "Afficher les dossiers trouvés dans la corbeille" - }, - "pref.UserName": { - "message": "Nom d'utilisateur" - }, - "pref.UserNameDescription": { - "message": "Le nom d'utilisateur est généralement l'adresse e-mail de votre compte." - }, - "pref.autodetect": { - "message": "le meilleur disponible" - }, - "pref.birthday": { - "message": "Envoyer la date de naissance" - }, - "pref.calendaroptions": { - "message": "Options de calendrier" - }, - "pref.contactoptions": { - "message": "Options des contacts" - }, - "pref.displayoverride": { - "message": "Remplacer le nom affiché par « Prénom » + « Nom »" - }, - "pref.generaloptions": { - "message": "Options générales" - }, - "pref.provision": { - "message": "Forcer l'approvisionnement (requis par Kerio)" - }, - "pref.seperator.comma": { - "message": "Virgule" - }, - "pref.seperator.description": { - "message": "Séparateur pour le champ d'adresse multiligne." - }, - "pref.seperator.linebreak": { - "message": "Saut de ligne" - }, - "pref.synclimit.1month": { - "message": "les 4 dernières semaines" - }, - "pref.synclimit.2weeks": { - "message": "les 2 dernières semaines" - }, - "pref.synclimit.3month": { - "message": "les 3 derniers mois" - }, - "pref.synclimit.6month": { - "message": "les 6 derniers mois" - }, - "pref.synclimit.all": { - "message": "tout" - }, - "pref.synclimit.description": { - "message": "Période de synchronisation : " - }, - "pref.usehttps": { - "message": "Utiliser une connexion sécurisée (se connecter via https)" - }, - "recyclebin": { - "message": "Corbeille" - }, - "servertype.auto": { - "message": "Configuration automatique" - }, - "servertype.custom": { - "message": "Configuration personnalisée" - }, - "servertype.description.auto": { - "message": "La configuration de nombreux serveurs ActiveSync peut être découverte en fournissant uniquement votre adresse e-mail." - }, - "servertype.description.custom": { - "message": "Configurez votre compte en fournissant manuellement l'adresse du serveur que vous souhaitez connecter." - }, - "servertype.description.office365": { - "message": "Les comptes connectés à Office 365 utilisent un processus d'authentification moderne appelé OAuth 2.0 qui supporte également l'authentification multi-facteur (MFA)." - }, - "servertype.office365": { - "message": "Microsoft Office 365" - }, - "servertype.unlock": { - "message": "Double-cliquez pour déverrouiller tous les paramètres prédéfinis du serveur." - }, - "status.401": { - "message": "L'authentification a échoué. Veuillez vérifier le couple nom d'utilisateur/mot de passe (erreur HTTP 401)." - }, - "status.403": { - "message": "Le serveur a rejeté la connexion (interdite) (Erreur HTTP 403)." - }, - "status.404": { - "message": "Utilisateur introuvable (Erreur HTTP 404)." - }, - "status.449": { - "message": "Le serveur demande le provisionnement (erreur HTTP 449)." - }, - "status.500": { - "message": "Erreur serveur inconnue (Erreur HTTP 500)." - }, - "status.503": { - "message": "Service indisponible (Erreur HTTP 503)." - }, - "status.BadItemSkipped": { - "message": "Mauvais élément ignoré : ##replace.1##" - }, - "status.FolderDelete.3": { - "message": "Impossible de supprimer un dossier système (statut 3)" - }, - "status.FolderDelete.4": { - "message": "Le dossier n'existe pas (statut 4), resynchronisation" - }, - "status.FolderDelete.6": { - "message": "La commande n'a pas pu être terminée, une erreur est survenue sur le serveur (statut 6)" - }, - "status.FolderDelete.9": { - "message": "Clé de synchronisation invalide (statut 9), resynchronisation" - }, - "status.FolderSync.9": { - "message": "Clé de synchronisation invalide (statut 9), resynchronisation" - }, - "status.InvalidServerOptions": { - "message": "Le serveur ne fournit pas d'informations sur les versions ActiveSync supportées. EAS est-il bloqué pour cet utilisateur ou ce client (TbSync) ? Vous pouvez essayer de définir manuellement la version ActiveSync." - }, - "status.OK": { - "message": "OK" - }, - "status.ServerRejectedRequest": { - "message": "Le serveur EAS a rejeté la dernière demande." - }, - "status.ServerRejectedSomeItems": { - "message": "Le serveur EAS n'a pas accepté les éléments ##replace.1##." - }, - "status.Sync.12": { - "message": "La hiérarchie des dossiers a changé (statut 12), resynchronisation" - }, - "status.Sync.3": { - "message": "Clé de synchronisation invalide (statut 3), resynchronisation" - }, - "status.Sync.4": { - "message": "Requête mal formée (statut 4)" - }, - "status.Sync.5": { - "message": "Problèmes de serveur temporaires ou élément invalide (statut 5)" - }, - "status.Sync.6": { - "message": "Élément invalide (statut 6)" - }, - "status.Sync.8": { - "message": "Objet introuvable (statut 8)" - }, - "status.aborted": { - "message": "Non synchronisé" - }, - "status.disabled": { - "message": "Désactivé" - }, - "status.empty-response": { - "message": "Le serveur a renvoyé une réponse vide inattendue." - }, - "status.forbiddenCalendarItemInTasksFolder": { - "message": "Élément de calendrier interdit dans un dossier de tâche (veuillez intervenir)" - }, - "status.forbiddenTasksItemInCalendarFolder": { - "message": "Élément de calendrier interdit dans un dossier de tâche (veuillez intervenir)" - }, - "status.global.101": { - "message": "La requête contient WBXML mais n'a pas pu être décodée en XML (EAS Error 101)." - }, - "status.global.102": { - "message": "La requête contient WBXML mais n'a pas pu être décodée en XML (EAS Error 102)." - }, - "status.global.103": { - "message": "Le XML fourni dans la requête ne respecte pas les exigences du protocole (EAS Error 103)." - }, - "status.global.110": { - "message": "Le serveur a signalé une erreur interne et nous ne devrions pas réessayer immédiatement. La synchronisation périodique automatique a été désactivée pendant 30 minutes (EAS Error 110)." - }, - "status.global.clientdenied": { - "message": "Le serveur EAS signale <##replace.2##> (status ##replace.1##) et n'autorise pas TbSync à accéder à votre compte." - }, - "status.httperror": { - "message": "Erreur de communication (statut HTTP ##replace.1##)." - }, - "status.invalid": { - "message": "Réponse du serveur invalide (pourriels)." - }, - "status.malformed-xml": { - "message": "Impossible d’analyser le XML. Vérifiez le journal des événements pour plus de détails." - }, - "status.modified": { - "message": "Modifications locales présentes" - }, - "status.network": { - "message": "Impossible de se connecter au serveur (##replace.1##)." - }, - "status.networkerror": { - "message": "La connexion au serveur a échoué." - }, - "status.nosupportedeasversion": { - "message": "Le serveur ne prend pas en charge ActiveSync v2.5 ou v14.0 (seulement ##replace.1##). TbSync ne fonctionnera pas avec ce serveur ActiveSync." - }, - "status.notargets": { - "message": "Annulation de la synchronisation en cours : il est impossible de créer les destinations de synchronisation." - }, - "status.notsupportedeasversion": { - "message": "Le serveur ne prend pas en charge la sélection ActiveSync v##replace.1## (seulement ##replace.2##)." - }, - "status.notsyncronized": { - "message": "Le compte doit être synchronisé : au moins un éléments n'est pas synchronisé." - }, - "status.nouserhost": { - "message": "Nom d'utilisateur et/ou serveur manquant. Veuillez fournir ces valeurs." - }, - "status.pending": { - "message": "En attente de synchronisation" - }, - "status.policy.2": { - "message": "Il n'y a pas de politique pour ce client. Contactez l'administrateur de votre serveur ou désactivez le provisioning pour ce compte." - }, - "status.policy.3": { - "message": "Valeur de PolicyType inconnue. Contactez l'administrateur du serveur ou désactivez le provisioning pour ce compte." - }, - "status.policy.4": { - "message": "Les données de stratégie sur le serveur sont corrompues (potentiellement altérées). Contactez l'administrateur de votre serveur ou désactivez le provisioning pour ce compte." - }, - "status.policy.5": { - "message": "Le client reconnaît la mauvaise clé de stratégie. Contactez l'administrateur du serveur ou désactivez le provisioning pour ce compte." - }, - "status.provision": { - "message": "Le provisioning a échoué avec le statut <##replace.1##>" - }, - "status.response-contains-no-data": { - "message": "La réponse du serveur ne contient aucune donnée." - }, - "status.resync-loop": { - "message": "Il y a eu une erreur à partir de laquelle nous n'avons pas pu rétablir la situation en resynchronisant le compte. Veuillez désactiver le compte et réessayer. (Erreur : boucle de resynchronisation)" - }, - "status.security": { - "message": "Impossible d'établir une connexion sécurisée. Utilisez-vous un certificat auto-signé ou autrement non fiable sans l'importer dans Thunderbird ? (##replace.1##)" - }, - "status.skipped": { - "message": "Pas encore pris en charge, ignoré" - }, - "status.syncing": { - "message": "Synchronisation en cours" - }, - "status.timeout": { - "message": "Délai de communication expiré." - }, - "status.wbxml-parse-error": { - "message": "Le serveur envoie une réponse illisible." - }, - "status.wbxmlerror": { - "message": "La synchronisation a échoué. Le serveur a répondu avec le statut <##replace.1##>." - }, - "status.wbxmlmissingfield": { - "message": "Violation du protocole ActiveSync : le champ obligatoire <##replace.1##> est absent de la réponse du serveur." - }, - "syncstate.accountdone": { - "message": "Synchronisation du compte terminée" - }, - "syncstate.done": { - "message": "Préparation du prochain élément pour la synchronisation" - }, - "syncstate.eval.response.autodiscover": { - "message": "Traitement des paramètres du serveur mis à jour" - }, - "syncstate.eval.response.deletefolder": { - "message": "Dossier supprimé" - }, - "syncstate.eval.response.estimate": { - "message": "Traitement de l'estimation des changements" - }, - "syncstate.eval.response.folders": { - "message": "Mise à jour de la liste des dossiers en cours de traitement" - }, - "syncstate.eval.response.localchanges": { - "message": "Traitement de la confirmation de réception des modifications locales" - }, - "syncstate.eval.response.localdeletes": { - "message": "Traitement de la confirmation de réception des suppressions locales" - }, - "syncstate.eval.response.options": { - "message": "Traitement des options du serveur" - }, - "syncstate.eval.response.provision": { - "message": "Traitement de la provision" - }, - "syncstate.eval.response.remotechanges": { - "message": "Traitement des modifications à distance" - }, - "syncstate.eval.response.revertlocalchanges": { - "message": "Rétablissement des modification locales" - }, - "syncstate.eval.response.setdeviceinfo": { - "message": "Envoi des informations de l'appareil" - }, - "syncstate.eval.response.synckey": { - "message": "Traitement de la clé de synchronisation" - }, - "syncstate.prepare.request.autodiscover": { - "message": "Demande de mise à jour des paramètres du serveur" - }, - "syncstate.prepare.request.deletefolder": { - "message": "Préparation de la suppression du dossier" - }, - "syncstate.prepare.request.estimate": { - "message": "Demande de l'estimation des changements" - }, - "syncstate.prepare.request.folders": { - "message": "Envoi de la mise à jour de la liste de dossiers" - }, - "syncstate.prepare.request.localchanges": { - "message": "Envoi des modifications locales" - }, - "syncstate.prepare.request.localdeletes": { - "message": "Envoi des suppressions locales" - }, - "syncstate.prepare.request.options": { - "message": "Demande des options du serveur" - }, - "syncstate.prepare.request.provision": { - "message": "Demande de provision" - }, - "syncstate.prepare.request.remotechanges": { - "message": "Traitement des modifications à distance" - }, - "syncstate.prepare.request.revertlocalchanges": { - "message": "Collecte des modifications locales" - }, - "syncstate.prepare.request.setdeviceinfo": { - "message": "Envoi des informations de l'appareil" - }, - "syncstate.prepare.request.synckey": { - "message": "Demande de clé de synchronisation" - }, - "syncstate.preparing": { - "message": "Préparation du prochain élément pour la synchronisation" - }, - "syncstate.send.request.autodiscover": { - "message": "En attente de mise à jour des paramètres du serveur" - }, - "syncstate.send.request.deletefolder": { - "message": "En attente de la suppression du dossier" - }, - "syncstate.send.request.estimate": { - "message": "En attente de l'estimation des changements" - }, - "syncstate.send.request.folders": { - "message": "En attente de mise à jour de la liste des dossiers" - }, - "syncstate.send.request.localchanges": { - "message": "En attente de la confirmation de réception des modifications locales" - }, - "syncstate.send.request.localdeletes": { - "message": "En attente de la confirmation de réception des suppressions locales" - }, - "syncstate.send.request.options": { - "message": "En attente des options du serveur" - }, - "syncstate.send.request.provision": { - "message": "En attente de provision" - }, - "syncstate.send.request.remotechanges": { - "message": "En attente des modifications à distance" - }, - "syncstate.send.request.revertlocalchanges": { - "message": "En attente des versions les plus récentes" - }, - "syncstate.send.request.setdeviceinfo": { - "message": "Envoi des informations de l'appareil" - }, - "syncstate.send.request.synckey": { - "message": "En attente de clé de synchronisation" - }, - "syncstate.syncing": { - "message": "Initialisation de la synchronisation" - } -} +{ + "abCard.Anniversary": { + "message": "Anniversaire :" + }, + "abCard.AssistantName": { + "message": "Assistant(e) :" + }, + "abCard.AssistantPhoneNumber": { + "message": "Téléphone Assistant(e) :" + }, + "abCard.Business2PhoneNumber": { + "message": "Téléphone Bureau Alternatif :" + }, + "abCard.BusinessFaxNumber": { + "message": "Fax de bureau :" + }, + "abCard.CarPhoneNumber": { + "message": "Téléphone Voiture :" + }, + "abCard.CompanyMainPhone": { + "message": "Téléphone de Bureau Principal :" + }, + "abCard.Email3Address": { + "message": "Courriel alternatif :" + }, + "abCard.Home2PhoneNumber": { + "message": "Téléphone Domicile Alternatif :" + }, + "abCard.ManagerName": { + "message": "Supérieur(e) :" + }, + "abCard.MiddleName": { + "message": "Deuxième prénom :" + }, + "abCard.OtherAddress": { + "message": "Adresse :" + }, + "abCard.OtherCity": { + "message": "Ville :" + }, + "abCard.OtherCountry": { + "message": "Pays :" + }, + "abCard.OtherState": { + "message": "État :" + }, + "abCard.OtherZip": { + "message": "Code postal :" + }, + "abCard.RadioPhoneNumber": { + "message": "Téléphone Radio :" + }, + "abCard.Spouse": { + "message": "Épou(x/se) :" + }, + "abCard.header.eas": { + "message": "Autres champs (EAS)" + }, + "abCard.header.homenumbers": { + "message": "Téléphones domicile supplémentaires :" + }, + "abCard.header.messaging": { + "message": "Messagerie :" + }, + "abCard.header.otheraddress": { + "message": "Autre Adresse (EAS)" + }, + "abCard.header.othernumbers": { + "message": "Numéros de téléphone supplémentaires :" + }, + "abCard.header.people": { + "message": "Personnes :" + }, + "abCard.header.worknumbers": { + "message": "Téléphones de bureau supplémentaires :" + }, + "acl.readonly": { + "message": "Accès au serveur en lecture seule (annule les modifications locales)" + }, + "acl.readwrite": { + "message": "Lecture et écriture sur le serveur" + }, + "add.description": { + "message": "Veuillez sélectionner une des options de configuration du serveur disponibles et entrer les détails demandés. " + }, + "add.name": { + "message": "Nom du compte :" + }, + "add.ok": { + "message": "Ajouter un compte" + }, + "add.password": { + "message": "Mot de passe :" + }, + "add.server": { + "message": "Configuration du serveur :" + }, + "add.shortdescription": { + "message": "Informations du compte" + }, + "add.title": { + "message": "Ajout d'un compte Exchange ActiveSync à TbSync" + }, + "add.url": { + "message": "Adresse du serveur :" + }, + "add.urldescription": { + "message": "Il devrait suffire de fournir uniquement l'adresse de base du serveur (par exemple : mail.votreserveur.com). Cependant, il est également possible de fournir l'URL complète (par exemple : https://mail.votreserveur.com/Microsoft-Server-ActiveSync)." + }, + "add.user": { + "message": "Nom d'utilisateur (adresse e-mail) :" + }, + "autocomplete.serverdirectory": { + "message": "annuaire global du serveur" + }, + "autodiscover.Failed": { + "message": "L'Autodiscover pour l'utilisateur <##user##> a échoué. Soit les informations d'identification fournies étaient erronées, soit votre fournisseur ActiveSync a un problème temporaire, soit il ne prend pas en charge l'Autodiscover." + }, + "autodiscover.NeedEmail": { + "message": "L'Autodiscover a besoin d'une adresse courriel valide comme nom d'utilisateur." + }, + "autodiscover.Ok": { + "message": "L'Autodiscover est terminée avec succès, vous pouvez maintenant vérifier les paramètres optionnels et établir la connexion de synchronisation." + }, + "autodiscover.Querying": { + "message": "Recherche de paramètres…" + }, + "config.auto": { + "message": "Configuration du serveur ActiveSync (Autodiscover)" + }, + "config.custom": { + "message": "Configuration du serveur ActiveSync" + }, + "deletefolder.confirm": { + "message": "Voulez-vous vraiment SUPPRIMER DÉFINITIVEMENT le dossier « ##replace.1##» de la corbeille ?" + }, + "deletefolder.menuentry": { + "message": "Supprimer définitivement le dossier « ##replace.1##» de la corbeille" + }, + "deletefolder.notallowed": { + "message": "Veuillez vous désabonner du dossier « ##replace.1##» avant d'essayer de le supprimer de la corbeille." + }, + "extensionDescription": { + "message": "Ajouter la prise en charge de la synchronisation des comptes Exchange ActiveSync à TbSync (contacts, tâches et calendriers)." + }, + "extensionName": { + "message": "Fournisseur pour Exchange ActiveSync" + }, + "helplink.BadItemSkipped": { + "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped" + }, + "helplink.global.clientdenied": { + "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F" + }, + "helplink.security": { + "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F" + }, + "manager.tabs.accountsettings": { + "message": "Paramètres du compte" + }, + "manager.tabs.outOfOffice": { + "message": "Répondeur automatique" + }, + "manager.tabs.syncsettings": { + "message": "Paramètres" + }, + "newaccount.add_auto": { + "message": "Paramètres Autodiscover et ajout de compte" + }, + "newaccount.add_custom": { + "message": "Ajouter un compte" + }, + "pref.AccountName": { + "message": "Description" + }, + "pref.ActiveSyncVersion": { + "message": "Version d'ActiveSync" + }, + "pref.DeviceId": { + "message": "ID de périphérique ActiveSync" + }, + "pref.ServerName": { + "message": "Adresse du serveur" + }, + "pref.ServerNameDescription": { + "message": "par exemple mail.votreserveur.com" + }, + "pref.ShowTrashedFolders": { + "message": "Afficher les dossiers trouvés dans la corbeille" + }, + "pref.UserName": { + "message": "Nom d'utilisateur" + }, + "pref.UserNameDescription": { + "message": "Le nom d'utilisateur est généralement l'adresse e-mail de votre compte." + }, + "pref.autodetect": { + "message": "le meilleur disponible" + }, + "pref.birthday": { + "message": "Envoyer la date de naissance" + }, + "pref.calendaroptions": { + "message": "Options de calendrier" + }, + "pref.contactoptions": { + "message": "Options des contacts" + }, + "pref.displayoverride": { + "message": "Remplacer le nom affiché par « Prénom » + « Nom »" + }, + "pref.generaloptions": { + "message": "Options générales" + }, + "pref.provision": { + "message": "Forcer l'approvisionnement (requis par Kerio)" + }, + "pref.seperator.comma": { + "message": "Virgule" + }, + "pref.seperator.description": { + "message": "Séparateur pour le champ d'adresse multiligne." + }, + "pref.seperator.linebreak": { + "message": "Saut de ligne" + }, + "pref.synclimit.1month": { + "message": "les 4 dernières semaines" + }, + "pref.synclimit.2weeks": { + "message": "les 2 dernières semaines" + }, + "pref.synclimit.3month": { + "message": "les 3 derniers mois" + }, + "pref.synclimit.6month": { + "message": "les 6 derniers mois" + }, + "pref.synclimit.all": { + "message": "tout" + }, + "pref.synclimit.description": { + "message": "Période de synchronisation : " + }, + "pref.usehttps": { + "message": "Utiliser une connexion sécurisée (se connecter via https)" + }, + "recyclebin": { + "message": "Corbeille" + }, + "servertype.auto": { + "message": "Configuration automatique" + }, + "servertype.custom": { + "message": "Configuration personnalisée" + }, + "servertype.description.auto": { + "message": "La configuration de nombreux serveurs ActiveSync peut être découverte en fournissant uniquement votre adresse e-mail." + }, + "servertype.description.custom": { + "message": "Configurez votre compte en fournissant manuellement l'adresse du serveur que vous souhaitez connecter." + }, + "servertype.description.office365": { + "message": "Les comptes connectés à Office 365 utilisent un processus d'authentification moderne appelé OAuth 2.0 qui supporte également l'authentification multi-facteur (MFA)." + }, + "servertype.office365": { + "message": "Microsoft Office 365" + }, + "servertype.unlock": { + "message": "Double-cliquez pour déverrouiller tous les paramètres prédéfinis du serveur." + }, + "status.401": { + "message": "L'authentification a échoué. Veuillez vérifier le couple nom d'utilisateur/mot de passe (erreur HTTP 401)." + }, + "status.403": { + "message": "Le serveur a rejeté la connexion (interdite) (Erreur HTTP 403)." + }, + "status.404": { + "message": "Utilisateur introuvable (Erreur HTTP 404)." + }, + "status.449": { + "message": "Le serveur demande le provisionnement (erreur HTTP 449)." + }, + "status.500": { + "message": "Erreur serveur inconnue (Erreur HTTP 500)." + }, + "status.503": { + "message": "Service indisponible (Erreur HTTP 503)." + }, + "status.BadItemSkipped": { + "message": "Mauvais élément ignoré : ##replace.1##" + }, + "status.FolderDelete.3": { + "message": "Impossible de supprimer un dossier système (statut 3)" + }, + "status.FolderDelete.4": { + "message": "Le dossier n'existe pas (statut 4), resynchronisation" + }, + "status.FolderDelete.6": { + "message": "La commande n'a pas pu être terminée, une erreur est survenue sur le serveur (statut 6)" + }, + "status.FolderDelete.9": { + "message": "Clé de synchronisation invalide (statut 9), resynchronisation" + }, + "status.FolderSync.9": { + "message": "Clé de synchronisation invalide (statut 9), resynchronisation" + }, + "status.InvalidServerOptions": { + "message": "Le serveur ne fournit pas d'informations sur les versions ActiveSync supportées. EAS est-il bloqué pour cet utilisateur ou ce client (TbSync) ? Vous pouvez essayer de définir manuellement la version ActiveSync." + }, + "status.OK": { + "message": "OK" + }, + "status.ServerRejectedRequest": { + "message": "Le serveur EAS a rejeté la dernière demande." + }, + "status.ServerRejectedSomeItems": { + "message": "Le serveur EAS n'a pas accepté les éléments ##replace.1##." + }, + "status.Sync.12": { + "message": "La hiérarchie des dossiers a changé (statut 12), resynchronisation" + }, + "status.Sync.3": { + "message": "Clé de synchronisation invalide (statut 3), resynchronisation" + }, + "status.Sync.4": { + "message": "Requête mal formée (statut 4)" + }, + "status.Sync.5": { + "message": "Problèmes de serveur temporaires ou élément invalide (statut 5)" + }, + "status.Sync.6": { + "message": "Élément invalide (statut 6)" + }, + "status.Sync.8": { + "message": "Objet introuvable (statut 8)" + }, + "status.aborted": { + "message": "Non synchronisé" + }, + "status.disabled": { + "message": "Désactivé" + }, + "status.empty-response": { + "message": "Le serveur a renvoyé une réponse vide inattendue." + }, + "status.forbiddenCalendarItemInTasksFolder": { + "message": "Élément de calendrier interdit dans un dossier de tâche (veuillez intervenir)" + }, + "status.forbiddenTasksItemInCalendarFolder": { + "message": "Élément de calendrier interdit dans un dossier de tâche (veuillez intervenir)" + }, + "status.global.101": { + "message": "La requête contient WBXML mais n'a pas pu être décodée en XML (EAS Error 101)." + }, + "status.global.102": { + "message": "La requête contient WBXML mais n'a pas pu être décodée en XML (EAS Error 102)." + }, + "status.global.103": { + "message": "Le XML fourni dans la requête ne respecte pas les exigences du protocole (EAS Error 103)." + }, + "status.global.110": { + "message": "Le serveur a signalé une erreur interne et nous ne devrions pas réessayer immédiatement. La synchronisation périodique automatique a été désactivée pendant 30 minutes (EAS Error 110)." + }, + "status.global.clientdenied": { + "message": "Le serveur EAS signale <##replace.2##> (status ##replace.1##) et n'autorise pas TbSync à accéder à votre compte." + }, + "status.httperror": { + "message": "Erreur de communication (statut HTTP ##replace.1##)." + }, + "status.invalid": { + "message": "Réponse du serveur invalide (pourriels)." + }, + "status.malformed-xml": { + "message": "Impossible d’analyser le XML. Vérifiez le journal des événements pour plus de détails." + }, + "status.modified": { + "message": "Modifications locales présentes" + }, + "status.network": { + "message": "Impossible de se connecter au serveur (##replace.1##)." + }, + "status.networkerror": { + "message": "La connexion au serveur a échoué." + }, + "status.nosupportedeasversion": { + "message": "Le serveur ne prend pas en charge ActiveSync v2.5 ou v14.0 (seulement ##replace.1##). TbSync ne fonctionnera pas avec ce serveur ActiveSync." + }, + "status.notargets": { + "message": "Annulation de la synchronisation en cours : il est impossible de créer les destinations de synchronisation." + }, + "status.notsupportedeasversion": { + "message": "Le serveur ne prend pas en charge la sélection ActiveSync v##replace.1## (seulement ##replace.2##)." + }, + "status.notsyncronized": { + "message": "Le compte doit être synchronisé : au moins un éléments n'est pas synchronisé." + }, + "status.nouserhost": { + "message": "Nom d'utilisateur et/ou serveur manquant. Veuillez fournir ces valeurs." + }, + "status.pending": { + "message": "En attente de synchronisation" + }, + "status.policy.2": { + "message": "Il n'y a pas de politique pour ce client. Contactez l'administrateur de votre serveur ou désactivez le provisioning pour ce compte." + }, + "status.policy.3": { + "message": "Valeur de PolicyType inconnue. Contactez l'administrateur du serveur ou désactivez le provisioning pour ce compte." + }, + "status.policy.4": { + "message": "Les données de stratégie sur le serveur sont corrompues (potentiellement altérées). Contactez l'administrateur de votre serveur ou désactivez le provisioning pour ce compte." + }, + "status.policy.5": { + "message": "Le client reconnaît la mauvaise clé de stratégie. Contactez l'administrateur du serveur ou désactivez le provisioning pour ce compte." + }, + "status.provision": { + "message": "Le provisioning a échoué avec le statut <##replace.1##>" + }, + "status.response-contains-no-data": { + "message": "La réponse du serveur ne contient aucune donnée." + }, + "status.resync-loop": { + "message": "Il y a eu une erreur à partir de laquelle nous n'avons pas pu rétablir la situation en resynchronisant le compte. Veuillez désactiver le compte et réessayer. (Erreur : boucle de resynchronisation)" + }, + "status.security": { + "message": "Impossible d'établir une connexion sécurisée. Utilisez-vous un certificat auto-signé ou autrement non fiable sans l'importer dans Thunderbird ? (##replace.1##)" + }, + "status.skipped": { + "message": "Pas encore pris en charge, ignoré" + }, + "status.syncing": { + "message": "Synchronisation en cours" + }, + "status.timeout": { + "message": "Délai de communication expiré." + }, + "status.wbxml-parse-error": { + "message": "Le serveur envoie une réponse illisible." + }, + "status.wbxmlerror": { + "message": "La synchronisation a échoué. Le serveur a répondu avec le statut <##replace.1##>." + }, + "status.wbxmlmissingfield": { + "message": "Violation du protocole ActiveSync : le champ obligatoire <##replace.1##> est absent de la réponse du serveur." + }, + "syncstate.accountdone": { + "message": "Synchronisation du compte terminée" + }, + "syncstate.done": { + "message": "Préparation du prochain élément pour la synchronisation" + }, + "syncstate.eval.response.autodiscover": { + "message": "Traitement des paramètres du serveur mis à jour" + }, + "syncstate.eval.response.deletefolder": { + "message": "Dossier supprimé" + }, + "syncstate.eval.response.estimate": { + "message": "Traitement de l'estimation des changements" + }, + "syncstate.eval.response.folders": { + "message": "Mise à jour de la liste des dossiers en cours de traitement" + }, + "syncstate.eval.response.localchanges": { + "message": "Traitement de la confirmation de réception des modifications locales" + }, + "syncstate.eval.response.localdeletes": { + "message": "Traitement de la confirmation de réception des suppressions locales" + }, + "syncstate.eval.response.options": { + "message": "Traitement des options du serveur" + }, + "syncstate.eval.response.provision": { + "message": "Traitement de la provision" + }, + "syncstate.eval.response.remotechanges": { + "message": "Traitement des modifications à distance" + }, + "syncstate.eval.response.revertlocalchanges": { + "message": "Rétablissement des modification locales" + }, + "syncstate.eval.response.setdeviceinfo": { + "message": "Envoi des informations de l'appareil" + }, + "syncstate.eval.response.synckey": { + "message": "Traitement de la clé de synchronisation" + }, + "syncstate.prepare.request.autodiscover": { + "message": "Demande de mise à jour des paramètres du serveur" + }, + "syncstate.prepare.request.deletefolder": { + "message": "Préparation de la suppression du dossier" + }, + "syncstate.prepare.request.estimate": { + "message": "Demande de l'estimation des changements" + }, + "syncstate.prepare.request.folders": { + "message": "Envoi de la mise à jour de la liste de dossiers" + }, + "syncstate.prepare.request.localchanges": { + "message": "Envoi des modifications locales" + }, + "syncstate.prepare.request.localdeletes": { + "message": "Envoi des suppressions locales" + }, + "syncstate.prepare.request.options": { + "message": "Demande des options du serveur" + }, + "syncstate.prepare.request.provision": { + "message": "Demande de provision" + }, + "syncstate.prepare.request.remotechanges": { + "message": "Traitement des modifications à distance" + }, + "syncstate.prepare.request.revertlocalchanges": { + "message": "Collecte des modifications locales" + }, + "syncstate.prepare.request.setdeviceinfo": { + "message": "Envoi des informations de l'appareil" + }, + "syncstate.prepare.request.synckey": { + "message": "Demande de clé de synchronisation" + }, + "syncstate.preparing": { + "message": "Préparation du prochain élément pour la synchronisation" + }, + "syncstate.send.request.autodiscover": { + "message": "En attente de mise à jour des paramètres du serveur" + }, + "syncstate.send.request.deletefolder": { + "message": "En attente de la suppression du dossier" + }, + "syncstate.send.request.estimate": { + "message": "En attente de l'estimation des changements" + }, + "syncstate.send.request.folders": { + "message": "En attente de mise à jour de la liste des dossiers" + }, + "syncstate.send.request.localchanges": { + "message": "En attente de la confirmation de réception des modifications locales" + }, + "syncstate.send.request.localdeletes": { + "message": "En attente de la confirmation de réception des suppressions locales" + }, + "syncstate.send.request.options": { + "message": "En attente des options du serveur" + }, + "syncstate.send.request.provision": { + "message": "En attente de provision" + }, + "syncstate.send.request.remotechanges": { + "message": "En attente des modifications à distance" + }, + "syncstate.send.request.revertlocalchanges": { + "message": "En attente des versions les plus récentes" + }, + "syncstate.send.request.setdeviceinfo": { + "message": "Envoi des informations de l'appareil" + }, + "syncstate.send.request.synckey": { + "message": "En attente de clé de synchronisation" + }, + "syncstate.syncing": { + "message": "Initialisation de la synchronisation" + } +} diff -Nru eas4tbsync-4.11/_locales/gl/messages.json eas4tbsync-4.17/_locales/gl/messages.json --- eas4tbsync-4.11/_locales/gl/messages.json 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/_locales/gl/messages.json 2025-05-15 11:21:18.000000000 +0000 @@ -1,566 +1,566 @@ -{ - "abCard.Anniversary": { - "message": "Aniversario:" - }, - "abCard.AssistantName": { - "message": "Asistente:" - }, - "abCard.AssistantPhoneNumber": { - "message": "Teléfono do asistente:" - }, - "abCard.Business2PhoneNumber": { - "message": "Teléfono alternativo do traballo:" - }, - "abCard.BusinessFaxNumber": { - "message": "Fax do traballo:" - }, - "abCard.CarPhoneNumber": { - "message": "Teléfono do coche:" - }, - "abCard.CompanyMainPhone": { - "message": "Teléfono principal do traballo:" - }, - "abCard.Email3Address": { - "message": "Correo electrónico alternativo:" - }, - "abCard.Home2PhoneNumber": { - "message": "Teléfono de casa alternativo:" - }, - "abCard.ManagerName": { - "message": "Supervisor:" - }, - "abCard.MiddleName": { - "message": "Segundo nome:" - }, - "abCard.OtherAddress": { - "message": "Enderezo:" - }, - "abCard.OtherCity": { - "message": "Cidade:" - }, - "abCard.OtherCountry": { - "message": "País:" - }, - "abCard.OtherState": { - "message": "Estado:" - }, - "abCard.OtherZip": { - "message": "Código postal:" - }, - "abCard.RadioPhoneNumber": { - "message": "Radioteléfóno:" - }, - "abCard.Spouse": { - "message": "Cónxuxe:" - }, - "abCard.header.eas": { - "message": "Outros campos (EAS)" - }, - "abCard.header.homenumbers": { - "message": "Números adicionais de casa:" - }, - "abCard.header.messaging": { - "message": "Mensaxería:" - }, - "abCard.header.otheraddress": { - "message": "Outros enderezos (EAS)" - }, - "abCard.header.othernumbers": { - "message": "Números adicionais:" - }, - "abCard.header.people": { - "message": "Persoas:" - }, - "abCard.header.worknumbers": { - "message": "Números adicionais do traballo:" - }, - "acl.readonly": { - "message": "Acceso só de lectura ao servidor (reverter cambios locais)" - }, - "acl.readwrite": { - "message": "Leer e escribir no servidor" - }, - "add.description": { - "message": "Por favor, selecciona unha das opcións de configuración do servidor e insire os detalles solicitados. " - }, - "add.name": { - "message": "Nome da conta:" - }, - "add.ok": { - "message": "Engadir conta" - }, - "add.password": { - "message": "Contrasinal:" - }, - "add.server": { - "message": "Configuración do servidor:" - }, - "add.shortdescription": { - "message": "Información da conta" - }, - "add.title": { - "message": "Engadindo unha conta Exchange ActiveSync a TbSync" - }, - "add.url": { - "message": "Enderezo do servidor:" - }, - "add.urldescription": { - "message": "Debería de ser suficiente con proporcionar só o enderezo básico do servidor (por exemplo, correo.dominio.gal). Con todo, tamén é posible facilitar o URL completo (por exemplo, https://correo.dominio.gal/Servidor-Microsoft-ActiveSync)." - }, - "add.user": { - "message": "Nome de usuario (enderezo de correo electrónico):" - }, - "autocomplete.serverdirectory": { - "message": "directorio global de servidores" - }, - "autodiscover.Failed": { - "message": "Fallou o Autodiscover para o usuario <##user##>. Ou ben proporcionaches unhas credenciais erróneas ou ben o teu provedor de ActiveSync ten un problema temporal, ou ben non admite o Autodiscover." - }, - "autodiscover.NeedEmail": { - "message": "Autodiscover precisa dun enderezo de correo electónico válido como nome de usuario." - }, - "autodiscover.Ok": { - "message": "Autodiscover completouse correctamente; agora podes revisar os axustes opcionais e establecer a conexión de sincronización." - }, - "autodiscover.Querying": { - "message": "Buscando os axustes…" - }, - "config.auto": { - "message": "Configuración do servidor de ActiveSync (Autodiscover)" - }, - "config.custom": { - "message": "Configuración do servidor de ActiveSync" - }, - "deletefolder.confirm": { - "message": "Queres ELIMINAR DEFINITIVAMENTE o cartafol “##replace.1##” da papeleira?" - }, - "deletefolder.menuentry": { - "message": "Eliminar definitivamente o cartafol “##replace.1##” da papeleira" - }, - "deletefolder.notallowed": { - "message": "Por favor, cancela a subscrición ao cartafol “##replace.1##” antes de intentar eliminalo da papeleira." - }, - "extensionDescription": { - "message": "Engade soporte a TbSync para a sincronización de contas de Exchange ActiveSync (contactos, tarefas e calendarios)." - }, - "extensionName": { - "message": "Provedor de Exchange ActiveSync" - }, - "helplink.BadItemSkipped": { - "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped" - }, - "helplink.global.clientdenied": { - "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F" - }, - "helplink.security": { - "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F" - }, - "manager.tabs.accountsettings": { - "message": "Axustes da conta" - }, - "manager.tabs.outOfOffice": { - "message": "Resposta automática" - }, - "manager.tabs.syncsettings": { - "message": "Opcións" - }, - "newaccount.add_auto": { - "message": "Axustes de Autodiscover e engadir conta" - }, - "newaccount.add_custom": { - "message": "Engadir conta" - }, - "pref.AccountName": { - "message": "Descrición" - }, - "pref.ActiveSyncVersion": { - "message": "Versión de ActiveSync" - }, - "pref.DeviceId": { - "message": "ID de dispositivo de ActiveSync" - }, - "pref.ServerName": { - "message": "Enderezo do servidor" - }, - "pref.ServerNameDescription": { - "message": "por exemplo, correo.dominio.gal" - }, - "pref.ShowTrashedFolders": { - "message": "Amosar cartafois atopados na papeleira" - }, - "pref.UserName": { - "message": "Nome de usuario" - }, - "pref.UserNameDescription": { - "message": "O nome de usuario adoita ser o enderezo de correo electrónico da túa conta." - }, - "pref.autodetect": { - "message": "mellor dispoñible" - }, - "pref.birthday": { - "message": "Enviar información do aniversario" - }, - "pref.calendaroptions": { - "message": "Opcións do calendario" - }, - "pref.contactoptions": { - "message": "Opcións dos contactos" - }, - "pref.displayoverride": { - "message": "Substituír o nome amosado por «Nome» + «Segundo nome»" - }, - "pref.generaloptions": { - "message": "Opcións xerais" - }, - "pref.provision": { - "message": "Forzar aprovisionamento (requirido por Kerio)" - }, - "pref.seperator.comma": { - "message": "Coma" - }, - "pref.seperator.description": { - "message": "Separador de campo de enderezo en varias liñas." - }, - "pref.seperator.linebreak": { - "message": "Salto de liña" - }, - "pref.synclimit.1month": { - "message": "desde hai 4 semanas" - }, - "pref.synclimit.2weeks": { - "message": "desde hai 2 semanas" - }, - "pref.synclimit.3month": { - "message": "desde hai 3 meses" - }, - "pref.synclimit.6month": { - "message": "desde hai 6 meses" - }, - "pref.synclimit.all": { - "message": "todo" - }, - "pref.synclimit.description": { - "message": "Período de sincronización: " - }, - "pref.usehttps": { - "message": "Usar conexión segura (conectar mediante https)" - }, - "recyclebin": { - "message": "Papeleira" - }, - "servertype.auto": { - "message": "Configuración automática" - }, - "servertype.custom": { - "message": "Configuración personalizada" - }, - "servertype.description.auto": { - "message": "É posible detectar a configuración de moitos servidores ActiveSync con só proporcionar o teu enderezo de correo electrónico." - }, - "servertype.description.custom": { - "message": "Configura a conta proporciando manualmente o enderezo do servidor ao que queres conectar." - }, - "servertype.description.office365": { - "message": "As contas conectadas a Office 365 utilizan un proceso de autenticación moderno, chamado OAuth 2.0, que tamén admite autenticación multifactor (MFA)." - }, - "servertype.office365": { - "message": "Microsoft Office 365" - }, - "servertype.unlock": { - "message": "Fai dobre clic para desbloquear todos os axustes predefinidos do servidor." - }, - "status.401": { - "message": "Non foi posible autenticarse, comproba o nome de usuario e o contrasinal (erro HTTP 401)." - }, - "status.403": { - "message": "O servidor rexeitou a conexión (prohibida) (erro HTTP 403)." - }, - "status.404": { - "message": "Usuario non atopado (erro HTTP 404)." - }, - "status.449": { - "message": "O servidor solicita aprovisionamento (erro HTTP 449)." - }, - "status.500": { - "message": "Erro descoñecido do servidor (erro HTTP 500)." - }, - "status.503": { - "message": "Servicio non dispoñible (erro HTTP 503)." - }, - "status.BadItemSkipped": { - "message": "Omitido obxecto incorrecto: ##replace.1##" - }, - "status.FolderDelete.3": { - "message": "Non é posible eliminar un cartafol do sistema (estado 3)" - }, - "status.FolderDelete.4": { - "message": "O cartafol non existe (estado 4), resincronizando" - }, - "status.FolderDelete.6": { - "message": "O comando non se completou, produciuse un erro no servidor (estado 6)" - }, - "status.FolderDelete.9": { - "message": "Chave de sincronización non válida (estado 9), resincronizando" - }, - "status.FolderSync.9": { - "message": "Chave de sincronización non válida (estado 9), resincronizando" - }, - "status.InvalidServerOptions": { - "message": "El servidor non proporciona información sobre as versións de ActiveSync compatibles. Está EAS bloqueado para este usuario ou para este cliente (TbSync)? Podes intentar establecer a versión de ActiveSync manualmente." - }, - "status.OK": { - "message": "OK" - }, - "status.ServerRejectedRequest": { - "message": "O servidor de EAS rexeitou a última petición." - }, - "status.ServerRejectedSomeItems": { - "message": "O servidor de EAS non aceptou ##replace.1## elementos." - }, - "status.Sync.12": { - "message": "Cambiou a xerarquía de cartafois (estado 12), resincronizando" - }, - "status.Sync.3": { - "message": "Chave de sincronización non válida (estado 3), resincronizando" - }, - "status.Sync.4": { - "message": "Solicitude mal formada (estado 4)" - }, - "status.Sync.5": { - "message": "Problemas temporais do servidor ou elemento non válido (estado 5)" - }, - "status.Sync.6": { - "message": "Elemento non válido (estado 6)" - }, - "status.Sync.8": { - "message": "Obxecto non atopado (estado 8)" - }, - "status.aborted": { - "message": "Sen sincronizar" - }, - "status.disabled": { - "message": "Desactivado" - }, - "status.empty-response": { - "message": "O servidor envía unha resposta baleira non esperada." - }, - "status.forbiddenCalendarItemInTasksFolder": { - "message": "Elemento do calendario prohibido nun cartafol de tarefas (por favor, reorganiza)" - }, - "status.forbiddenTasksItemInCalendarFolder": { - "message": "Elemento de tarefas prohibido nun cartafol do calendario (por favor, reorganiza)" - }, - "status.global.101": { - "message": "A solicitude contén WBXML pero non puido ser descodificado a XML (erro EAS 101)." - }, - "status.global.102": { - "message": "A solicitude contén WBXML pero non puido ser descodificado a XML (erro EAS 102)." - }, - "status.global.103": { - "message": "O XML proporcionado na solicitude non cumple os requirimentos do protocolo (erro EAS 103)." - }, - "status.global.110": { - "message": "O servidor informou dun erro interno e non deberías reconectar de inmediato. Desactivouse a sincronización periódica automática durante 30 minutos (erro EAS 110)." - }, - "status.global.clientdenied": { - "message": "O servidor EAS notifica <##replace.2##> (estado ##replace.1##) e non permite que TbSync acceda á túa conta." - }, - "status.httperror": { - "message": "Erro de comunicación (estado HTTP ##replace.1##)." - }, - "status.invalid": { - "message": "Resposta do servidor non válida (corrompida)." - }, - "status.malformed-xml": { - "message": "Non se puido analizar o XML. Revisa o rexistro de eventos para dispor de máis detalles." - }, - "status.modified": { - "message": "Modificacións locais" - }, - "status.network": { - "message": "Non se puido conectar ao servidor (##replace.1##)." - }, - "status.networkerror": { - "message": "Non se puido conectar ao servidor." - }, - "status.nosupportedeasversion": { - "message": "O servidor non é compatible con ActiveSync v2.5 ou v14.0 (só ##replace.1##). TbSync non funcionará con este servidor de ActiveSync." - }, - "status.notargets": { - "message": "Sincronización interrompida porque no se puideron crear os destinos da sincronización." - }, - "status.notsupportedeasversion": { - "message": "O servidor non é compatible con ActiveSync v##replace.1## (só ##replace.2##)." - }, - "status.notsyncronized": { - "message": "É preciso sincronizar a conta: hai algún un elemento sen sincronizar." - }, - "status.nouserhost": { - "message": "Falta o nome de usuario ou o servidor. Por favor, proporciona eses datos." - }, - "status.pending": { - "message": "Agardando pola sincronización" - }, - "status.policy.2": { - "message": "Non hai ningunha directiva para este cliente. Contacta co administrador do servidor ou desactiva o aprovisionamento desta conta." - }, - "status.policy.3": { - "message": "Valor de PolicyType descoñecido. Contacta co administrador do servidor ou desactiva o aprovisionamento desta conta." - }, - "status.policy.4": { - "message": "Os datos de directivas do servidor están danados (posiblemente manipulados). Contacta co administrador do servidor ou desactiva o aprovisionamento desta conta." - }, - "status.policy.5": { - "message": "O cliente está a recoñecer a chave de directiva incorrecta. Contacta co administrador do servidor ou desactiva o aprovisionamento desta conta." - }, - "status.provision": { - "message": "O aprovisionamento fallou co estado <##replace.1##>" - }, - "status.response-contains-no-data": { - "message": "A resposta do servidor non contén datos." - }, - "status.resync-loop": { - "message": "Produciuse un erro que non se puido corrixir volvendo a sincronizar a conta. Desactiva a conta e inténtao outra vez (erro: bucle de resincronización)" - }, - "status.security": { - "message": "No se puido establecer unha conexión segura. Estás a usar un certificado autofirmado, ou que non é de confianza, sen importarlo a Thunderbird? (##replace.1##)" - }, - "status.skipped": { - "message": "Aínda non soportado, omitido" - }, - "status.syncing": { - "message": "Sincronizando" - }, - "status.timeout": { - "message": "Tempo de comunicación esgotado." - }, - "status.wbxml-parse-error": { - "message": "O servidor envía unha resposta ilexible." - }, - "status.wbxmlerror": { - "message": "Erro ao sincronizar. O servidor respondeu co estado <##replace.1##>." - }, - "status.wbxmlmissingfield": { - "message": "Violación do protocolo de ActiveSync: falta o campo obrigatorio <##replace.1##> na respuesta do servidor." - }, - "syncstate.accountdone": { - "message": "Conta rematada" - }, - "syncstate.done": { - "message": "Preparando o seguinte elemento para a sincronización" - }, - "syncstate.eval.response.autodiscover": { - "message": "Procesando os axustes do servidor actualizados" - }, - "syncstate.eval.response.deletefolder": { - "message": "Cartafol eliminado" - }, - "syncstate.eval.response.estimate": { - "message": "Procesando a estimación do cambio" - }, - "syncstate.eval.response.folders": { - "message": "Procesando a lista de cartafois actualizada" - }, - "syncstate.eval.response.localchanges": { - "message": "Procesando o recoñecemento de cambios locais" - }, - "syncstate.eval.response.localdeletes": { - "message": "Procesando o recoñecemento de eliminacións locais" - }, - "syncstate.eval.response.options": { - "message": "Procesando as opcións do servidor" - }, - "syncstate.eval.response.provision": { - "message": "Procesando o aprovisionamento" - }, - "syncstate.eval.response.remotechanges": { - "message": "Procesando os cambios remotos" - }, - "syncstate.eval.response.revertlocalchanges": { - "message": "Revertendo os cambios locais" - }, - "syncstate.eval.response.setdeviceinfo": { - "message": "Enviando información do dispositivo" - }, - "syncstate.eval.response.synckey": { - "message": "Procesando SyncKey" - }, - "syncstate.prepare.request.autodiscover": { - "message": "Solicitando axustes actualizados do servidor" - }, - "syncstate.prepare.request.deletefolder": { - "message": "Preparando a elimanción do cartafol" - }, - "syncstate.prepare.request.estimate": { - "message": "Solicitando a estimación dos cambios" - }, - "syncstate.prepare.request.folders": { - "message": "Enviando a actualización da lista de cartafois" - }, - "syncstate.prepare.request.localchanges": { - "message": "Enviando os cambios locais" - }, - "syncstate.prepare.request.localdeletes": { - "message": "Enviando as eliminacións locais" - }, - "syncstate.prepare.request.options": { - "message": "Solicitando as opcións do servidor" - }, - "syncstate.prepare.request.provision": { - "message": "Solicitando o aprovisionamento" - }, - "syncstate.prepare.request.remotechanges": { - "message": "Solicitando os cambios remotos" - }, - "syncstate.prepare.request.revertlocalchanges": { - "message": "Recolectando os cambios locais" - }, - "syncstate.prepare.request.setdeviceinfo": { - "message": "Enviando información do dispositivo" - }, - "syncstate.prepare.request.synckey": { - "message": "Solicitando SyncKey" - }, - "syncstate.preparing": { - "message": "Preparando o seguinte elemento para a sincronización" - }, - "syncstate.send.request.autodiscover": { - "message": "Agardando polos axustes actualizados do servidor" - }, - "syncstate.send.request.deletefolder": { - "message": "Agardando pola eliminación do cartafol" - }, - "syncstate.send.request.estimate": { - "message": "Agardando pola estimación de cambios" - }, - "syncstate.send.request.folders": { - "message": "Agardando pola actualización da lista de cartafois" - }, - "syncstate.send.request.localchanges": { - "message": "Agardando polo recoñecemento de cambios locais" - }, - "syncstate.send.request.localdeletes": { - "message": "Agardando polo recoñecemento de eliminacións locais" - }, - "syncstate.send.request.options": { - "message": "Agardando polas opcións do servidor" - }, - "syncstate.send.request.provision": { - "message": "Agardando polo aprovisionamento" - }, - "syncstate.send.request.remotechanges": { - "message": "Agardando polos cambios remotos" - }, - "syncstate.send.request.revertlocalchanges": { - "message": "Agardando polas versións máis recentes" - }, - "syncstate.send.request.setdeviceinfo": { - "message": "Enviando información do dispositivo" - }, - "syncstate.send.request.synckey": { - "message": "Agardando por SyncKey" - }, - "syncstate.syncing": { - "message": "Iniciar sincronización" - } -} +{ + "abCard.Anniversary": { + "message": "Aniversario:" + }, + "abCard.AssistantName": { + "message": "Asistente:" + }, + "abCard.AssistantPhoneNumber": { + "message": "Teléfono do asistente:" + }, + "abCard.Business2PhoneNumber": { + "message": "Teléfono alternativo do traballo:" + }, + "abCard.BusinessFaxNumber": { + "message": "Fax do traballo:" + }, + "abCard.CarPhoneNumber": { + "message": "Teléfono do coche:" + }, + "abCard.CompanyMainPhone": { + "message": "Teléfono principal do traballo:" + }, + "abCard.Email3Address": { + "message": "Correo electrónico alternativo:" + }, + "abCard.Home2PhoneNumber": { + "message": "Teléfono de casa alternativo:" + }, + "abCard.ManagerName": { + "message": "Supervisor:" + }, + "abCard.MiddleName": { + "message": "Segundo nome:" + }, + "abCard.OtherAddress": { + "message": "Enderezo:" + }, + "abCard.OtherCity": { + "message": "Cidade:" + }, + "abCard.OtherCountry": { + "message": "País:" + }, + "abCard.OtherState": { + "message": "Estado:" + }, + "abCard.OtherZip": { + "message": "Código postal:" + }, + "abCard.RadioPhoneNumber": { + "message": "Radioteléfóno:" + }, + "abCard.Spouse": { + "message": "Cónxuxe:" + }, + "abCard.header.eas": { + "message": "Outros campos (EAS)" + }, + "abCard.header.homenumbers": { + "message": "Números adicionais de casa:" + }, + "abCard.header.messaging": { + "message": "Mensaxería:" + }, + "abCard.header.otheraddress": { + "message": "Outros enderezos (EAS)" + }, + "abCard.header.othernumbers": { + "message": "Números adicionais:" + }, + "abCard.header.people": { + "message": "Persoas:" + }, + "abCard.header.worknumbers": { + "message": "Números adicionais do traballo:" + }, + "acl.readonly": { + "message": "Acceso só de lectura ao servidor (reverter cambios locais)" + }, + "acl.readwrite": { + "message": "Leer e escribir no servidor" + }, + "add.description": { + "message": "Por favor, selecciona unha das opcións de configuración do servidor e insire os detalles solicitados. " + }, + "add.name": { + "message": "Nome da conta:" + }, + "add.ok": { + "message": "Engadir conta" + }, + "add.password": { + "message": "Contrasinal:" + }, + "add.server": { + "message": "Configuración do servidor:" + }, + "add.shortdescription": { + "message": "Información da conta" + }, + "add.title": { + "message": "Engadindo unha conta Exchange ActiveSync a TbSync" + }, + "add.url": { + "message": "Enderezo do servidor:" + }, + "add.urldescription": { + "message": "Debería de ser suficiente con proporcionar só o enderezo básico do servidor (por exemplo, correo.dominio.gal). Con todo, tamén é posible facilitar o URL completo (por exemplo, https://correo.dominio.gal/Servidor-Microsoft-ActiveSync)." + }, + "add.user": { + "message": "Nome de usuario (enderezo de correo electrónico):" + }, + "autocomplete.serverdirectory": { + "message": "directorio global de servidores" + }, + "autodiscover.Failed": { + "message": "Fallou o Autodiscover para o usuario <##user##>. Ou ben proporcionaches unhas credenciais erróneas ou ben o teu provedor de ActiveSync ten un problema temporal, ou ben non admite o Autodiscover." + }, + "autodiscover.NeedEmail": { + "message": "Autodiscover precisa dun enderezo de correo electónico válido como nome de usuario." + }, + "autodiscover.Ok": { + "message": "Autodiscover completouse correctamente; agora podes revisar os axustes opcionais e establecer a conexión de sincronización." + }, + "autodiscover.Querying": { + "message": "Buscando os axustes…" + }, + "config.auto": { + "message": "Configuración do servidor de ActiveSync (Autodiscover)" + }, + "config.custom": { + "message": "Configuración do servidor de ActiveSync" + }, + "deletefolder.confirm": { + "message": "Queres ELIMINAR DEFINITIVAMENTE o cartafol “##replace.1##” da papeleira?" + }, + "deletefolder.menuentry": { + "message": "Eliminar definitivamente o cartafol “##replace.1##” da papeleira" + }, + "deletefolder.notallowed": { + "message": "Por favor, cancela a subscrición ao cartafol “##replace.1##” antes de intentar eliminalo da papeleira." + }, + "extensionDescription": { + "message": "Engade soporte a TbSync para a sincronización de contas de Exchange ActiveSync (contactos, tarefas e calendarios)." + }, + "extensionName": { + "message": "Provedor de Exchange ActiveSync" + }, + "helplink.BadItemSkipped": { + "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped" + }, + "helplink.global.clientdenied": { + "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F" + }, + "helplink.security": { + "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F" + }, + "manager.tabs.accountsettings": { + "message": "Axustes da conta" + }, + "manager.tabs.outOfOffice": { + "message": "Resposta automática" + }, + "manager.tabs.syncsettings": { + "message": "Opcións" + }, + "newaccount.add_auto": { + "message": "Axustes de Autodiscover e engadir conta" + }, + "newaccount.add_custom": { + "message": "Engadir conta" + }, + "pref.AccountName": { + "message": "Descrición" + }, + "pref.ActiveSyncVersion": { + "message": "Versión de ActiveSync" + }, + "pref.DeviceId": { + "message": "ID de dispositivo de ActiveSync" + }, + "pref.ServerName": { + "message": "Enderezo do servidor" + }, + "pref.ServerNameDescription": { + "message": "por exemplo, correo.dominio.gal" + }, + "pref.ShowTrashedFolders": { + "message": "Amosar cartafois atopados na papeleira" + }, + "pref.UserName": { + "message": "Nome de usuario" + }, + "pref.UserNameDescription": { + "message": "O nome de usuario adoita ser o enderezo de correo electrónico da túa conta." + }, + "pref.autodetect": { + "message": "mellor dispoñible" + }, + "pref.birthday": { + "message": "Enviar información do aniversario" + }, + "pref.calendaroptions": { + "message": "Opcións do calendario" + }, + "pref.contactoptions": { + "message": "Opcións dos contactos" + }, + "pref.displayoverride": { + "message": "Substituír o nome amosado por «Nome» + «Segundo nome»" + }, + "pref.generaloptions": { + "message": "Opcións xerais" + }, + "pref.provision": { + "message": "Forzar aprovisionamento (requirido por Kerio)" + }, + "pref.seperator.comma": { + "message": "Coma" + }, + "pref.seperator.description": { + "message": "Separador de campo de enderezo en varias liñas." + }, + "pref.seperator.linebreak": { + "message": "Salto de liña" + }, + "pref.synclimit.1month": { + "message": "desde hai 4 semanas" + }, + "pref.synclimit.2weeks": { + "message": "desde hai 2 semanas" + }, + "pref.synclimit.3month": { + "message": "desde hai 3 meses" + }, + "pref.synclimit.6month": { + "message": "desde hai 6 meses" + }, + "pref.synclimit.all": { + "message": "todo" + }, + "pref.synclimit.description": { + "message": "Período de sincronización: " + }, + "pref.usehttps": { + "message": "Usar conexión segura (conectar mediante https)" + }, + "recyclebin": { + "message": "Papeleira" + }, + "servertype.auto": { + "message": "Configuración automática" + }, + "servertype.custom": { + "message": "Configuración personalizada" + }, + "servertype.description.auto": { + "message": "É posible detectar a configuración de moitos servidores ActiveSync con só proporcionar o teu enderezo de correo electrónico." + }, + "servertype.description.custom": { + "message": "Configura a conta proporciando manualmente o enderezo do servidor ao que queres conectar." + }, + "servertype.description.office365": { + "message": "As contas conectadas a Office 365 utilizan un proceso de autenticación moderno, chamado OAuth 2.0, que tamén admite autenticación multifactor (MFA)." + }, + "servertype.office365": { + "message": "Microsoft Office 365" + }, + "servertype.unlock": { + "message": "Fai dobre clic para desbloquear todos os axustes predefinidos do servidor." + }, + "status.401": { + "message": "Non foi posible autenticarse, comproba o nome de usuario e o contrasinal (erro HTTP 401)." + }, + "status.403": { + "message": "O servidor rexeitou a conexión (prohibida) (erro HTTP 403)." + }, + "status.404": { + "message": "Usuario non atopado (erro HTTP 404)." + }, + "status.449": { + "message": "O servidor solicita aprovisionamento (erro HTTP 449)." + }, + "status.500": { + "message": "Erro descoñecido do servidor (erro HTTP 500)." + }, + "status.503": { + "message": "Servicio non dispoñible (erro HTTP 503)." + }, + "status.BadItemSkipped": { + "message": "Omitido obxecto incorrecto: ##replace.1##" + }, + "status.FolderDelete.3": { + "message": "Non é posible eliminar un cartafol do sistema (estado 3)" + }, + "status.FolderDelete.4": { + "message": "O cartafol non existe (estado 4), resincronizando" + }, + "status.FolderDelete.6": { + "message": "O comando non se completou, produciuse un erro no servidor (estado 6)" + }, + "status.FolderDelete.9": { + "message": "Chave de sincronización non válida (estado 9), resincronizando" + }, + "status.FolderSync.9": { + "message": "Chave de sincronización non válida (estado 9), resincronizando" + }, + "status.InvalidServerOptions": { + "message": "El servidor non proporciona información sobre as versións de ActiveSync compatibles. Está EAS bloqueado para este usuario ou para este cliente (TbSync)? Podes intentar establecer a versión de ActiveSync manualmente." + }, + "status.OK": { + "message": "OK" + }, + "status.ServerRejectedRequest": { + "message": "O servidor de EAS rexeitou a última petición." + }, + "status.ServerRejectedSomeItems": { + "message": "O servidor de EAS non aceptou ##replace.1## elementos." + }, + "status.Sync.12": { + "message": "Cambiou a xerarquía de cartafois (estado 12), resincronizando" + }, + "status.Sync.3": { + "message": "Chave de sincronización non válida (estado 3), resincronizando" + }, + "status.Sync.4": { + "message": "Solicitude mal formada (estado 4)" + }, + "status.Sync.5": { + "message": "Problemas temporais do servidor ou elemento non válido (estado 5)" + }, + "status.Sync.6": { + "message": "Elemento non válido (estado 6)" + }, + "status.Sync.8": { + "message": "Obxecto non atopado (estado 8)" + }, + "status.aborted": { + "message": "Sen sincronizar" + }, + "status.disabled": { + "message": "Desactivado" + }, + "status.empty-response": { + "message": "O servidor envía unha resposta baleira non esperada." + }, + "status.forbiddenCalendarItemInTasksFolder": { + "message": "Elemento do calendario prohibido nun cartafol de tarefas (por favor, reorganiza)" + }, + "status.forbiddenTasksItemInCalendarFolder": { + "message": "Elemento de tarefas prohibido nun cartafol do calendario (por favor, reorganiza)" + }, + "status.global.101": { + "message": "A solicitude contén WBXML pero non puido ser descodificado a XML (erro EAS 101)." + }, + "status.global.102": { + "message": "A solicitude contén WBXML pero non puido ser descodificado a XML (erro EAS 102)." + }, + "status.global.103": { + "message": "O XML proporcionado na solicitude non cumple os requirimentos do protocolo (erro EAS 103)." + }, + "status.global.110": { + "message": "O servidor informou dun erro interno e non deberías reconectar de inmediato. Desactivouse a sincronización periódica automática durante 30 minutos (erro EAS 110)." + }, + "status.global.clientdenied": { + "message": "O servidor EAS notifica <##replace.2##> (estado ##replace.1##) e non permite que TbSync acceda á túa conta." + }, + "status.httperror": { + "message": "Erro de comunicación (estado HTTP ##replace.1##)." + }, + "status.invalid": { + "message": "Resposta do servidor non válida (corrompida)." + }, + "status.malformed-xml": { + "message": "Non se puido analizar o XML. Revisa o rexistro de eventos para dispor de máis detalles." + }, + "status.modified": { + "message": "Modificacións locais" + }, + "status.network": { + "message": "Non se puido conectar ao servidor (##replace.1##)." + }, + "status.networkerror": { + "message": "Non se puido conectar ao servidor." + }, + "status.nosupportedeasversion": { + "message": "O servidor non é compatible con ActiveSync v2.5 ou v14.0 (só ##replace.1##). TbSync non funcionará con este servidor de ActiveSync." + }, + "status.notargets": { + "message": "Sincronización interrompida porque no se puideron crear os destinos da sincronización." + }, + "status.notsupportedeasversion": { + "message": "O servidor non é compatible con ActiveSync v##replace.1## (só ##replace.2##)." + }, + "status.notsyncronized": { + "message": "É preciso sincronizar a conta: hai algún un elemento sen sincronizar." + }, + "status.nouserhost": { + "message": "Falta o nome de usuario ou o servidor. Por favor, proporciona eses datos." + }, + "status.pending": { + "message": "Agardando pola sincronización" + }, + "status.policy.2": { + "message": "Non hai ningunha directiva para este cliente. Contacta co administrador do servidor ou desactiva o aprovisionamento desta conta." + }, + "status.policy.3": { + "message": "Valor de PolicyType descoñecido. Contacta co administrador do servidor ou desactiva o aprovisionamento desta conta." + }, + "status.policy.4": { + "message": "Os datos de directivas do servidor están danados (posiblemente manipulados). Contacta co administrador do servidor ou desactiva o aprovisionamento desta conta." + }, + "status.policy.5": { + "message": "O cliente está a recoñecer a chave de directiva incorrecta. Contacta co administrador do servidor ou desactiva o aprovisionamento desta conta." + }, + "status.provision": { + "message": "O aprovisionamento fallou co estado <##replace.1##>" + }, + "status.response-contains-no-data": { + "message": "A resposta do servidor non contén datos." + }, + "status.resync-loop": { + "message": "Produciuse un erro que non se puido corrixir volvendo a sincronizar a conta. Desactiva a conta e inténtao outra vez (erro: bucle de resincronización)" + }, + "status.security": { + "message": "No se puido establecer unha conexión segura. Estás a usar un certificado autofirmado, ou que non é de confianza, sen importarlo a Thunderbird? (##replace.1##)" + }, + "status.skipped": { + "message": "Aínda non soportado, omitido" + }, + "status.syncing": { + "message": "Sincronizando" + }, + "status.timeout": { + "message": "Tempo de comunicación esgotado." + }, + "status.wbxml-parse-error": { + "message": "O servidor envía unha resposta ilexible." + }, + "status.wbxmlerror": { + "message": "Erro ao sincronizar. O servidor respondeu co estado <##replace.1##>." + }, + "status.wbxmlmissingfield": { + "message": "Violación do protocolo de ActiveSync: falta o campo obrigatorio <##replace.1##> na respuesta do servidor." + }, + "syncstate.accountdone": { + "message": "Conta rematada" + }, + "syncstate.done": { + "message": "Preparando o seguinte elemento para a sincronización" + }, + "syncstate.eval.response.autodiscover": { + "message": "Procesando os axustes do servidor actualizados" + }, + "syncstate.eval.response.deletefolder": { + "message": "Cartafol eliminado" + }, + "syncstate.eval.response.estimate": { + "message": "Procesando a estimación do cambio" + }, + "syncstate.eval.response.folders": { + "message": "Procesando a lista de cartafois actualizada" + }, + "syncstate.eval.response.localchanges": { + "message": "Procesando o recoñecemento de cambios locais" + }, + "syncstate.eval.response.localdeletes": { + "message": "Procesando o recoñecemento de eliminacións locais" + }, + "syncstate.eval.response.options": { + "message": "Procesando as opcións do servidor" + }, + "syncstate.eval.response.provision": { + "message": "Procesando o aprovisionamento" + }, + "syncstate.eval.response.remotechanges": { + "message": "Procesando os cambios remotos" + }, + "syncstate.eval.response.revertlocalchanges": { + "message": "Revertendo os cambios locais" + }, + "syncstate.eval.response.setdeviceinfo": { + "message": "Enviando información do dispositivo" + }, + "syncstate.eval.response.synckey": { + "message": "Procesando SyncKey" + }, + "syncstate.prepare.request.autodiscover": { + "message": "Solicitando axustes actualizados do servidor" + }, + "syncstate.prepare.request.deletefolder": { + "message": "Preparando a elimanción do cartafol" + }, + "syncstate.prepare.request.estimate": { + "message": "Solicitando a estimación dos cambios" + }, + "syncstate.prepare.request.folders": { + "message": "Enviando a actualización da lista de cartafois" + }, + "syncstate.prepare.request.localchanges": { + "message": "Enviando os cambios locais" + }, + "syncstate.prepare.request.localdeletes": { + "message": "Enviando as eliminacións locais" + }, + "syncstate.prepare.request.options": { + "message": "Solicitando as opcións do servidor" + }, + "syncstate.prepare.request.provision": { + "message": "Solicitando o aprovisionamento" + }, + "syncstate.prepare.request.remotechanges": { + "message": "Solicitando os cambios remotos" + }, + "syncstate.prepare.request.revertlocalchanges": { + "message": "Recolectando os cambios locais" + }, + "syncstate.prepare.request.setdeviceinfo": { + "message": "Enviando información do dispositivo" + }, + "syncstate.prepare.request.synckey": { + "message": "Solicitando SyncKey" + }, + "syncstate.preparing": { + "message": "Preparando o seguinte elemento para a sincronización" + }, + "syncstate.send.request.autodiscover": { + "message": "Agardando polos axustes actualizados do servidor" + }, + "syncstate.send.request.deletefolder": { + "message": "Agardando pola eliminación do cartafol" + }, + "syncstate.send.request.estimate": { + "message": "Agardando pola estimación de cambios" + }, + "syncstate.send.request.folders": { + "message": "Agardando pola actualización da lista de cartafois" + }, + "syncstate.send.request.localchanges": { + "message": "Agardando polo recoñecemento de cambios locais" + }, + "syncstate.send.request.localdeletes": { + "message": "Agardando polo recoñecemento de eliminacións locais" + }, + "syncstate.send.request.options": { + "message": "Agardando polas opcións do servidor" + }, + "syncstate.send.request.provision": { + "message": "Agardando polo aprovisionamento" + }, + "syncstate.send.request.remotechanges": { + "message": "Agardando polos cambios remotos" + }, + "syncstate.send.request.revertlocalchanges": { + "message": "Agardando polas versións máis recentes" + }, + "syncstate.send.request.setdeviceinfo": { + "message": "Enviando información do dispositivo" + }, + "syncstate.send.request.synckey": { + "message": "Agardando por SyncKey" + }, + "syncstate.syncing": { + "message": "Iniciar sincronización" + } +} diff -Nru eas4tbsync-4.11/_locales/hu/messages.json eas4tbsync-4.17/_locales/hu/messages.json --- eas4tbsync-4.11/_locales/hu/messages.json 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/_locales/hu/messages.json 2025-05-15 11:21:18.000000000 +0000 @@ -1,566 +1,566 @@ -{ - "abCard.Anniversary": { - "message": "Évforduló:" - }, - "abCard.AssistantName": { - "message": "Asszisztens:" - }, - "abCard.AssistantPhoneNumber": { - "message": "Asszisztensi telefon:" - }, - "abCard.Business2PhoneNumber": { - "message": "2. munkahelyi telefon:" - }, - "abCard.BusinessFaxNumber": { - "message": "Munkahelyi fax:" - }, - "abCard.CarPhoneNumber": { - "message": "Autóstelefon:" - }, - "abCard.CompanyMainPhone": { - "message": "Fő munkahelyi telefon:" - }, - "abCard.Email3Address": { - "message": "Másodlagos e-mail:" - }, - "abCard.Home2PhoneNumber": { - "message": "2. otthoni telefon:" - }, - "abCard.ManagerName": { - "message": "Vezető:" - }, - "abCard.MiddleName": { - "message": "Második keresztnév:" - }, - "abCard.OtherAddress": { - "message": "Cím:" - }, - "abCard.OtherCity": { - "message": "Város:" - }, - "abCard.OtherCountry": { - "message": "Ország:" - }, - "abCard.OtherState": { - "message": "Állam/tartomány:" - }, - "abCard.OtherZip": { - "message": "Irányítószám:" - }, - "abCard.RadioPhoneNumber": { - "message": "Rádió-távbeszélő:" - }, - "abCard.Spouse": { - "message": "Házastárs:" - }, - "abCard.header.eas": { - "message": "Egyéb mezők (EAS)" - }, - "abCard.header.homenumbers": { - "message": "További otthoni számok:" - }, - "abCard.header.messaging": { - "message": "Üzenetek:" - }, - "abCard.header.otheraddress": { - "message": "Egyéb cím (EAS)" - }, - "abCard.header.othernumbers": { - "message": "További számok:" - }, - "abCard.header.people": { - "message": "Emberek:" - }, - "abCard.header.worknumbers": { - "message": "További munkahelyi számok:" - }, - "acl.readonly": { - "message": "Csak olvasható hozzáférés (helyi változások visszavonása)" - }, - "acl.readwrite": { - "message": "Olvasás és írás a kiszolgálón" - }, - "add.description": { - "message": "Válasszon az elérhető kiszolgálóbeállítások közül, és adja meg a kért részleteket. " - }, - "add.name": { - "message": "Felhasználónév:" - }, - "add.ok": { - "message": "Fiók hozzáadása" - }, - "add.password": { - "message": "Jelszó:" - }, - "add.server": { - "message": "Kiszolgálóbeállítások:" - }, - "add.shortdescription": { - "message": "Fiókadatok" - }, - "add.title": { - "message": "Exchange ActiveSync-fiók hozzáadása a TbSynchez" - }, - "add.url": { - "message": "Kiszolgáló címe:" - }, - "add.urldescription": { - "message": "Elégséges, ha csak az alap kiszolgálócímet adja meg (például: posta.kiszolgálód.hu). De a teljes URL-t is megadhatja (például: https://posta.kiszolgálód.hu/Microsoft-Server-ActiveSync)." - }, - "add.user": { - "message": "Felhasználónév (e-mail-cím):" - }, - "autocomplete.serverdirectory": { - "message": "globális kiszolgálójegyzék" - }, - "autodiscover.Failed": { - "message": "A(z) <##user##> felhasználó automatikus felderítése sikertelen. Vagy hibásak voltak a megadott hitelesítő adatok, vagy az ActiveSync szolgáltató ideiglenes problémákat tapasztal, vagy nem támogatja az automatikus felderítést." - }, - "autodiscover.NeedEmail": { - "message": "Az önműködő felismerésnek érvényes e-mail címnek kell lennie felhasználói névként." - }, - "autodiscover.Ok": { - "message": "Az önműködő felderítés sikeresen befejeződött, most ellenőrizheti az választható beállításokat és létrehozhatja az összehangolási kapcsolatot." - }, - "autodiscover.Querying": { - "message": "Beállítások keresése…" - }, - "config.auto": { - "message": "Az ActiveSync kiszolgáló beállítások (önműködő észlelés)" - }, - "config.custom": { - "message": "Az ActiveSync kiszolgáló beállítások" - }, - "deletefolder.confirm": { - "message": "Tényleg azt szeretné, hogy a(z) „##replace.1##” mappa véglegesen törölje a kukát?" - }, - "deletefolder.menuentry": { - "message": "„##replace.1##” mappa kuka ürítése" - }, - "deletefolder.notallowed": { - "message": "Kérjük, törölje le a(z) „##replace.1##” mappát, mielőtt megpróbálnánk kuka ürítése." - }, - "extensionDescription": { - "message": "Az Exchange ActiveSync-fiókok szinkronizálásának támogatása a TbSyncben (névjegyek, feladatok és naptárak)." - }, - "extensionName": { - "message": "Exchange ActiveSync-szolgáltató" - }, - "helplink.BadItemSkipped": { - "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped" - }, - "helplink.global.clientdenied": { - "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F" - }, - "helplink.security": { - "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F" - }, - "manager.tabs.accountsettings": { - "message": "Fiókbeállítások" - }, - "manager.tabs.outOfOffice": { - "message": "Automatikus válasz" - }, - "manager.tabs.syncsettings": { - "message": "Beállítások" - }, - "newaccount.add_auto": { - "message": "Automatikus felfedezés beállításai és fiók hozzáadása" - }, - "newaccount.add_custom": { - "message": "Fiók hozzáadása" - }, - "pref.AccountName": { - "message": "Leírás" - }, - "pref.ActiveSyncVersion": { - "message": "ActiveSync verzió" - }, - "pref.DeviceId": { - "message": "ActiveSync eszközazonosító" - }, - "pref.ServerName": { - "message": "Kiszolgáló címe" - }, - "pref.ServerNameDescription": { - "message": "például: posta.kiszolgálód.hu" - }, - "pref.ShowTrashedFolders": { - "message": "A kukában található mappák megjelenítése" - }, - "pref.UserName": { - "message": "Felhasználónév" - }, - "pref.UserNameDescription": { - "message": "A felhasználónév általában a fiókja e-mail-címe." - }, - "pref.autodetect": { - "message": "az elérhető legjobb" - }, - "pref.birthday": { - "message": "Születésnapi információk küldése" - }, - "pref.calendaroptions": { - "message": "Naptár beállításai" - }, - "pref.contactoptions": { - "message": "Névjegyzék beállításai" - }, - "pref.displayoverride": { - "message": "Megjelenítési név felülbírálása ezzel: „keresztnév” + „második keresztnév”" - }, - "pref.generaloptions": { - "message": "Általános beállítások" - }, - "pref.provision": { - "message": "Lekötés megkövetelése (a Kerio követelménye)" - }, - "pref.seperator.comma": { - "message": "Vessző" - }, - "pref.seperator.description": { - "message": "A többsoros címmező elválasztója." - }, - "pref.seperator.linebreak": { - "message": "Sortörés" - }, - "pref.synclimit.1month": { - "message": "4 héttel ezelőtt" - }, - "pref.synclimit.2weeks": { - "message": "2 héttel ezelőtt" - }, - "pref.synclimit.3month": { - "message": "3 hónappal ezelőtt" - }, - "pref.synclimit.6month": { - "message": "6 hónappal ezelőtt" - }, - "pref.synclimit.all": { - "message": "mindent" - }, - "pref.synclimit.description": { - "message": "Szinkronizálási időszak: " - }, - "pref.usehttps": { - "message": "Biztonságos kapcsolat használata (kapcsolódás https-n keresztül)" - }, - "recyclebin": { - "message": "Kuka" - }, - "servertype.auto": { - "message": "Automatikus beállítás" - }, - "servertype.custom": { - "message": "Egyéni beállítás" - }, - "servertype.description.auto": { - "message": "Számos ActiveSync-kiszolgáló beállítása automatikusan felfedezhető pusztán az e-mail-címe megadásával." - }, - "servertype.description.custom": { - "message": "Fiók beállítása a használandó kiszolgáló címének kézi megadásával." - }, - "servertype.description.office365": { - "message": "Az Office 365-höz kapcsolódó fiókok az OAuth 2.0 nevű modern hitelesítési folyamatot használják, amely támogatja a többfaktoros hitelesítést (MFA) is." - }, - "servertype.office365": { - "message": "Microsoft Office 365" - }, - "servertype.unlock": { - "message": "Kattintson duplán az összes előre megadott kiszolgálóbeállítás feloldásához." - }, - "status.401": { - "message": "A hitelesítés nem sikerült, ellenőrizze a felhasználónevet és a jelszót (401-es HTTP-hiba)." - }, - "status.403": { - "message": "A kiszolgáló elutasította a kapcsolatot (403-as HTTP-hiba)." - }, - "status.404": { - "message": "A felhasználó nem található (404-es HTTP-hiba)." - }, - "status.449": { - "message": "A kiszolgáló lekötést két (449-es HTTP-hiba)." - }, - "status.500": { - "message": "Ismeretlen kiszolgálóhiba (500-as HTTP-hiba)." - }, - "status.503": { - "message": "A szolgáltatás nem elérhető (503-ás HTTP-hiba)." - }, - "status.BadItemSkipped": { - "message": "Hibás elem kihagyva: ##replace.1##" - }, - "status.FolderDelete.3": { - "message": "Nem lehet törölni egy rendszermappát (3-as állapot)" - }, - "status.FolderDelete.4": { - "message": "A mappa nem létezik (4-es állapot), újraszinkronizálás" - }, - "status.FolderDelete.6": { - "message": "A parancs nem fejezhető be, hiba történt a kiszolgálón (6-os állapot)" - }, - "status.FolderDelete.9": { - "message": "?? Invalid synchronization key (status 9), resyncing ??" - }, - "status.FolderSync.9": { - "message": "?? Invalid synchronization key (status 9), resyncing ??" - }, - "status.InvalidServerOptions": { - "message": "A kiszolgáló nem nyújt felvilágosítást a támogatott ActiveSync verziókról. EAS akadályozva van ez a felhasználó vagy az ügyfél (Thunderbird-összehangolás) számára? Megpróbálhatja kézzel beállítani az ActiveSync verziót." - }, - "status.OK": { - "message": "OK" - }, - "status.ServerRejectedRequest": { - "message": "Az EAS-kiszolgáló elutasította az utolsó kérést." - }, - "status.ServerRejectedSomeItems": { - "message": "Az EAS-kiszolgáló nem fogadta el a(z) ##replace.1## elemeket." - }, - "status.Sync.12": { - "message": "A mappahierarchia megváltozott (12-es állapot), újraszinkronizálás" - }, - "status.Sync.3": { - "message": "Érvénytelen szinkronizálási kulcs (3-as állapot), újraszinkronizálás" - }, - "status.Sync.4": { - "message": "Rosszul formázott kérés (4-es állapot)" - }, - "status.Sync.5": { - "message": "Ideiglenes kiszolgálóprobléma vagy érvénytelen elem (5-ös állapot)" - }, - "status.Sync.6": { - "message": "Érvénytelen elem (6-os állapot)" - }, - "status.Sync.8": { - "message": "Az objektum nem található (8-as állapot)" - }, - "status.aborted": { - "message": "Nincs szinkronizálva" - }, - "status.disabled": { - "message": "Letiltva" - }, - "status.empty-response": { - "message": "A kiszolgáló váratlan üres választ küldött." - }, - "status.forbiddenCalendarItemInTasksFolder": { - "message": "Tiltott naptárelem a feladatok mappában (rendezze újra)" - }, - "status.forbiddenTasksItemInCalendarFolder": { - "message": "Tiltott feladatelem a naptár mappában (rendezze újra)" - }, - "status.global.101": { - "message": "A kérés WBXML-t tartalmaz, de nem sikerült XML-be dekódolni (101-es EAS-hiba)." - }, - "status.global.102": { - "message": "A kérés WBXML-t tartalmaz, de nem sikerült XML-be dekódolni (102-es EAS-hiba)." - }, - "status.global.103": { - "message": "A kérésben megadott XML nem követi a protokoll követelményeit (103-as EAS-hiba)." - }, - "status.global.110": { - "message": "A kiszolgáló belső hibát jelentett, és nem szabad azonnal újrapróbálkozni. Az automatikus szinkronizálás 30 percre felfüggesztésre került (110-es EAS hiba)." - }, - "status.global.clientdenied": { - "message": "Az EAS-kiszolgáló ezt jelenti: <##replace.2##> (állapot: ##replace.1##), és nem engedélyezi a TbSync számára a fiókja elérését." - }, - "status.httperror": { - "message": "Kommunikációs hiba (HTTP állapot: ##replace.1##)." - }, - "status.invalid": { - "message": "Érvénytelen kiszolgálóválasz (szemét)." - }, - "status.malformed-xml": { - "message": "Az XML feldolgozása nem sikerült. Ellenőrizze az eseménynaplót a részletekért." - }, - "status.modified": { - "message": "Helyi módosítások" - }, - "status.network": { - "message": "Nem sikerült kapcsolódni a kiszolgálóhoz (##replace.1##)." - }, - "status.networkerror": { - "message": "Nem sikerült kapcsolódni a kiszolgálóhoz." - }, - "status.nosupportedeasversion": { - "message": "A kiszolgáló nem támogatja az ActiveSync v2.5-öt vagy a v14.0-t (csak ezt: ##replace.1##). A TbSync nem fog működni ezzel az ActiveSync-kiszolgálóval." - }, - "status.notargets": { - "message": "A szinkronizálás megszakítása, mert a szinkronizálási célokat nem lehetett létrehozni." - }, - "status.notsupportedeasversion": { - "message": "A kiszolgáló nem támogatja a kiválasztott ActiveSync ##replace.1## verziót (csak ezt: ##replace.2##)." - }, - "status.notsyncronized": { - "message": "A fiókot szinkronizálni kell, legalább egy elem nincs szinkronizálva." - }, - "status.nouserhost": { - "message": "Hiányzó felhasználónév vagy kiszolgáló. Adja meg ezeket az értékeket." - }, - "status.pending": { - "message": "Várakozás a szinkronizálásra" - }, - "status.policy.2": { - "message": "Nincs házirend ehhez a klienshez. Vegye fel a kapcsolatot a kiszolgáló rendszergazdájával, vagy tiltsa le a fiók lekötését." - }, - "status.policy.3": { - "message": "Ismeretlen házirendtípus érték. Vegye fel a kapcsolatot a kiszolgáló rendszergazdájával, vagy tiltsa le a fiók lekötését." - }, - "status.policy.4": { - "message": "A kiszolgáló házirendadatai sérültek (esetleg meghamisították). Vegye fel a kapcsolatot a kiszolgáló rendszergazdájával, vagy tiltsa le a fiók lekötését." - }, - "status.policy.5": { - "message": "A kliens nyugtázza a hibás házirendkulcsot. Vegye fel a kapcsolatot a kiszolgáló rendszergazdájával, vagy tiltsa le a fiók lekötését." - }, - "status.provision": { - "message": "A lekötés sikertelen, állapot: <##replace.1##>" - }, - "status.response-contains-no-data": { - "message": "A kiszolgáló válasza nem tartalmaz adatokat." - }, - "status.resync-loop": { - "message": "Hiba történt, amelyből nem sikerült helyreállni a fiók újraszinkronizálásával. Tiltsa le a fiókot, és próbálja meg újra. (Hiba: állandó újraszinkronizálás)" - }, - "status.security": { - "message": "A biztonságos kapcsolat létrehozása nem sikerült. Önaláírt vagy más, nem megbízható tanúsítványt importált a Thunderbirdbe? (##replace.1##)" - }, - "status.skipped": { - "message": "Még nem támogatott, kihagyva" - }, - "status.syncing": { - "message": "Szinkronizálás" - }, - "status.timeout": { - "message": "Kommunikációs időtúllépés." - }, - "status.wbxml-parse-error": { - "message": "A kiszolgáló olvashatatlan választ küld." - }, - "status.wbxmlerror": { - "message": "A szinkronizálás sikertelen. A kiszolgáló a következő állapottal válaszolt: <##replace.1##>." - }, - "status.wbxmlmissingfield": { - "message": "ActiveSync protokollsértés: A(z) <##replace.1##> kötelező mező hiányzik a kiszolgáló válaszából." - }, - "syncstate.accountdone": { - "message": "Fiók kész" - }, - "syncstate.done": { - "message": "A következő elem előkészítése szinkronizálásra" - }, - "syncstate.eval.response.autodiscover": { - "message": "Frissített kiszolgálóbeállítások feldolgozása" - }, - "syncstate.eval.response.deletefolder": { - "message": "A mappa törölve" - }, - "syncstate.eval.response.estimate": { - "message": "Változásbecslés feldolgozása" - }, - "syncstate.eval.response.folders": { - "message": "A mappalista frissítés feldolgozása" - }, - "syncstate.eval.response.localchanges": { - "message": "A helyi változások nyugtázásának feldolgozása" - }, - "syncstate.eval.response.localdeletes": { - "message": "A helyi törlések nyugtázásának feldolgozása" - }, - "syncstate.eval.response.options": { - "message": "A kiszolgáló beállításainak feldolgozása" - }, - "syncstate.eval.response.provision": { - "message": "Lekötés feldolgozása" - }, - "syncstate.eval.response.remotechanges": { - "message": "A távoli módosítások feldolgozása" - }, - "syncstate.eval.response.revertlocalchanges": { - "message": "A helyi változások visszaállítása" - }, - "syncstate.eval.response.setdeviceinfo": { - "message": "Eszközinformációk küldése" - }, - "syncstate.eval.response.synckey": { - "message": "Szinkronizálási kulcs feldolgozása" - }, - "syncstate.prepare.request.autodiscover": { - "message": "Frissített kiszolgálóbeállítások kérése" - }, - "syncstate.prepare.request.deletefolder": { - "message": "Felkészülés a mappa törlésére" - }, - "syncstate.prepare.request.estimate": { - "message": "Változásbecslés kérése" - }, - "syncstate.prepare.request.folders": { - "message": "Mappalista-frissítés elküldése" - }, - "syncstate.prepare.request.localchanges": { - "message": "Helyi változások küldése" - }, - "syncstate.prepare.request.localdeletes": { - "message": "Helyi törlések küldése" - }, - "syncstate.prepare.request.options": { - "message": "A kiszolgálóbeállítások kérése" - }, - "syncstate.prepare.request.provision": { - "message": "Lekötés kérése" - }, - "syncstate.prepare.request.remotechanges": { - "message": "Távoli módosítások kérése" - }, - "syncstate.prepare.request.revertlocalchanges": { - "message": "Helyi változások összegyűjtése" - }, - "syncstate.prepare.request.setdeviceinfo": { - "message": "Eszközinformációk küldése" - }, - "syncstate.prepare.request.synckey": { - "message": "Szinkronizálási kulcs kérése" - }, - "syncstate.preparing": { - "message": "A következő elem előkészítése szinkronizálásra" - }, - "syncstate.send.request.autodiscover": { - "message": "Várakozás a frissített kiszolgálóbeállításokra" - }, - "syncstate.send.request.deletefolder": { - "message": "Várakozás a mappa törlésére" - }, - "syncstate.send.request.estimate": { - "message": "Várakozás a változásbecslésre" - }, - "syncstate.send.request.folders": { - "message": "Várakozás a mappalista-frissítésre" - }, - "syncstate.send.request.localchanges": { - "message": "Várakozás a helyi változások elismerésére" - }, - "syncstate.send.request.localdeletes": { - "message": "Várakozás a helyi törlések nyugtázására" - }, - "syncstate.send.request.options": { - "message": "Várakozás a kiszolgálóbeállításokra" - }, - "syncstate.send.request.provision": { - "message": "Várakozás a lekötésre" - }, - "syncstate.send.request.remotechanges": { - "message": "Várakozás a távoli módosításokra" - }, - "syncstate.send.request.revertlocalchanges": { - "message": "Várakozás a legfrissebb verziókra" - }, - "syncstate.send.request.setdeviceinfo": { - "message": "Eszközinformációk küldése" - }, - "syncstate.send.request.synckey": { - "message": "Várakozás a szinkronizálási kulcsra" - }, - "syncstate.syncing": { - "message": "Szinkronizálás előkészítése" - } -} +{ + "abCard.Anniversary": { + "message": "Évforduló:" + }, + "abCard.AssistantName": { + "message": "Asszisztens:" + }, + "abCard.AssistantPhoneNumber": { + "message": "Asszisztensi telefon:" + }, + "abCard.Business2PhoneNumber": { + "message": "2. munkahelyi telefon:" + }, + "abCard.BusinessFaxNumber": { + "message": "Munkahelyi fax:" + }, + "abCard.CarPhoneNumber": { + "message": "Autóstelefon:" + }, + "abCard.CompanyMainPhone": { + "message": "Fő munkahelyi telefon:" + }, + "abCard.Email3Address": { + "message": "Másodlagos e-mail:" + }, + "abCard.Home2PhoneNumber": { + "message": "2. otthoni telefon:" + }, + "abCard.ManagerName": { + "message": "Vezető:" + }, + "abCard.MiddleName": { + "message": "Második keresztnév:" + }, + "abCard.OtherAddress": { + "message": "Cím:" + }, + "abCard.OtherCity": { + "message": "Város:" + }, + "abCard.OtherCountry": { + "message": "Ország:" + }, + "abCard.OtherState": { + "message": "Állam/tartomány:" + }, + "abCard.OtherZip": { + "message": "Irányítószám:" + }, + "abCard.RadioPhoneNumber": { + "message": "Rádió-távbeszélő:" + }, + "abCard.Spouse": { + "message": "Házastárs:" + }, + "abCard.header.eas": { + "message": "Egyéb mezők (EAS)" + }, + "abCard.header.homenumbers": { + "message": "További otthoni számok:" + }, + "abCard.header.messaging": { + "message": "Üzenetek:" + }, + "abCard.header.otheraddress": { + "message": "Egyéb cím (EAS)" + }, + "abCard.header.othernumbers": { + "message": "További számok:" + }, + "abCard.header.people": { + "message": "Emberek:" + }, + "abCard.header.worknumbers": { + "message": "További munkahelyi számok:" + }, + "acl.readonly": { + "message": "Csak olvasható hozzáférés (helyi változások visszavonása)" + }, + "acl.readwrite": { + "message": "Olvasás és írás a kiszolgálón" + }, + "add.description": { + "message": "Válasszon az elérhető kiszolgálóbeállítások közül, és adja meg a kért részleteket. " + }, + "add.name": { + "message": "Felhasználónév:" + }, + "add.ok": { + "message": "Fiók hozzáadása" + }, + "add.password": { + "message": "Jelszó:" + }, + "add.server": { + "message": "Kiszolgálóbeállítások:" + }, + "add.shortdescription": { + "message": "Fiókadatok" + }, + "add.title": { + "message": "Exchange ActiveSync-fiók hozzáadása a TbSynchez" + }, + "add.url": { + "message": "Kiszolgáló címe:" + }, + "add.urldescription": { + "message": "Elégséges, ha csak az alap kiszolgálócímet adja meg (például: posta.kiszolgálód.hu). De a teljes URL-t is megadhatja (például: https://posta.kiszolgálód.hu/Microsoft-Server-ActiveSync)." + }, + "add.user": { + "message": "Felhasználónév (e-mail-cím):" + }, + "autocomplete.serverdirectory": { + "message": "globális kiszolgálójegyzék" + }, + "autodiscover.Failed": { + "message": "A(z) <##user##> felhasználó automatikus felderítése sikertelen. Vagy hibásak voltak a megadott hitelesítő adatok, vagy az ActiveSync szolgáltató ideiglenes problémákat tapasztal, vagy nem támogatja az automatikus felderítést." + }, + "autodiscover.NeedEmail": { + "message": "Az önműködő felismerésnek érvényes e-mail címnek kell lennie felhasználói névként." + }, + "autodiscover.Ok": { + "message": "Az önműködő felderítés sikeresen befejeződött, most ellenőrizheti az választható beállításokat és létrehozhatja az összehangolási kapcsolatot." + }, + "autodiscover.Querying": { + "message": "Beállítások keresése…" + }, + "config.auto": { + "message": "Az ActiveSync kiszolgáló beállítások (önműködő észlelés)" + }, + "config.custom": { + "message": "Az ActiveSync kiszolgáló beállítások" + }, + "deletefolder.confirm": { + "message": "Tényleg azt szeretné, hogy a(z) „##replace.1##” mappa véglegesen törölje a kukát?" + }, + "deletefolder.menuentry": { + "message": "„##replace.1##” mappa kuka ürítése" + }, + "deletefolder.notallowed": { + "message": "Kérjük, törölje le a(z) „##replace.1##” mappát, mielőtt megpróbálnánk kuka ürítése." + }, + "extensionDescription": { + "message": "Az Exchange ActiveSync-fiókok szinkronizálásának támogatása a TbSyncben (névjegyek, feladatok és naptárak)." + }, + "extensionName": { + "message": "Exchange ActiveSync-szolgáltató" + }, + "helplink.BadItemSkipped": { + "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped" + }, + "helplink.global.clientdenied": { + "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F" + }, + "helplink.security": { + "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F" + }, + "manager.tabs.accountsettings": { + "message": "Fiókbeállítások" + }, + "manager.tabs.outOfOffice": { + "message": "Automatikus válasz" + }, + "manager.tabs.syncsettings": { + "message": "Beállítások" + }, + "newaccount.add_auto": { + "message": "Automatikus felfedezés beállításai és fiók hozzáadása" + }, + "newaccount.add_custom": { + "message": "Fiók hozzáadása" + }, + "pref.AccountName": { + "message": "Leírás" + }, + "pref.ActiveSyncVersion": { + "message": "ActiveSync verzió" + }, + "pref.DeviceId": { + "message": "ActiveSync eszközazonosító" + }, + "pref.ServerName": { + "message": "Kiszolgáló címe" + }, + "pref.ServerNameDescription": { + "message": "például: posta.kiszolgálód.hu" + }, + "pref.ShowTrashedFolders": { + "message": "A kukában található mappák megjelenítése" + }, + "pref.UserName": { + "message": "Felhasználónév" + }, + "pref.UserNameDescription": { + "message": "A felhasználónév általában a fiókja e-mail-címe." + }, + "pref.autodetect": { + "message": "az elérhető legjobb" + }, + "pref.birthday": { + "message": "Születésnapi információk küldése" + }, + "pref.calendaroptions": { + "message": "Naptár beállításai" + }, + "pref.contactoptions": { + "message": "Névjegyzék beállításai" + }, + "pref.displayoverride": { + "message": "Megjelenítési név felülbírálása ezzel: „keresztnév” + „második keresztnév”" + }, + "pref.generaloptions": { + "message": "Általános beállítások" + }, + "pref.provision": { + "message": "Lekötés megkövetelése (a Kerio követelménye)" + }, + "pref.seperator.comma": { + "message": "Vessző" + }, + "pref.seperator.description": { + "message": "A többsoros címmező elválasztója." + }, + "pref.seperator.linebreak": { + "message": "Sortörés" + }, + "pref.synclimit.1month": { + "message": "4 héttel ezelőtt" + }, + "pref.synclimit.2weeks": { + "message": "2 héttel ezelőtt" + }, + "pref.synclimit.3month": { + "message": "3 hónappal ezelőtt" + }, + "pref.synclimit.6month": { + "message": "6 hónappal ezelőtt" + }, + "pref.synclimit.all": { + "message": "mindent" + }, + "pref.synclimit.description": { + "message": "Szinkronizálási időszak: " + }, + "pref.usehttps": { + "message": "Biztonságos kapcsolat használata (kapcsolódás https-n keresztül)" + }, + "recyclebin": { + "message": "Kuka" + }, + "servertype.auto": { + "message": "Automatikus beállítás" + }, + "servertype.custom": { + "message": "Egyéni beállítás" + }, + "servertype.description.auto": { + "message": "Számos ActiveSync-kiszolgáló beállítása automatikusan felfedezhető pusztán az e-mail-címe megadásával." + }, + "servertype.description.custom": { + "message": "Fiók beállítása a használandó kiszolgáló címének kézi megadásával." + }, + "servertype.description.office365": { + "message": "Az Office 365-höz kapcsolódó fiókok az OAuth 2.0 nevű modern hitelesítési folyamatot használják, amely támogatja a többfaktoros hitelesítést (MFA) is." + }, + "servertype.office365": { + "message": "Microsoft Office 365" + }, + "servertype.unlock": { + "message": "Kattintson duplán az összes előre megadott kiszolgálóbeállítás feloldásához." + }, + "status.401": { + "message": "A hitelesítés nem sikerült, ellenőrizze a felhasználónevet és a jelszót (401-es HTTP-hiba)." + }, + "status.403": { + "message": "A kiszolgáló elutasította a kapcsolatot (403-as HTTP-hiba)." + }, + "status.404": { + "message": "A felhasználó nem található (404-es HTTP-hiba)." + }, + "status.449": { + "message": "A kiszolgáló lekötést két (449-es HTTP-hiba)." + }, + "status.500": { + "message": "Ismeretlen kiszolgálóhiba (500-as HTTP-hiba)." + }, + "status.503": { + "message": "A szolgáltatás nem elérhető (503-ás HTTP-hiba)." + }, + "status.BadItemSkipped": { + "message": "Hibás elem kihagyva: ##replace.1##" + }, + "status.FolderDelete.3": { + "message": "Nem lehet törölni egy rendszermappát (3-as állapot)" + }, + "status.FolderDelete.4": { + "message": "A mappa nem létezik (4-es állapot), újraszinkronizálás" + }, + "status.FolderDelete.6": { + "message": "A parancs nem fejezhető be, hiba történt a kiszolgálón (6-os állapot)" + }, + "status.FolderDelete.9": { + "message": "?? Invalid synchronization key (status 9), resyncing ??" + }, + "status.FolderSync.9": { + "message": "?? Invalid synchronization key (status 9), resyncing ??" + }, + "status.InvalidServerOptions": { + "message": "A kiszolgáló nem nyújt felvilágosítást a támogatott ActiveSync verziókról. EAS akadályozva van ez a felhasználó vagy az ügyfél (Thunderbird-összehangolás) számára? Megpróbálhatja kézzel beállítani az ActiveSync verziót." + }, + "status.OK": { + "message": "OK" + }, + "status.ServerRejectedRequest": { + "message": "Az EAS-kiszolgáló elutasította az utolsó kérést." + }, + "status.ServerRejectedSomeItems": { + "message": "Az EAS-kiszolgáló nem fogadta el a(z) ##replace.1## elemeket." + }, + "status.Sync.12": { + "message": "A mappahierarchia megváltozott (12-es állapot), újraszinkronizálás" + }, + "status.Sync.3": { + "message": "Érvénytelen szinkronizálási kulcs (3-as állapot), újraszinkronizálás" + }, + "status.Sync.4": { + "message": "Rosszul formázott kérés (4-es állapot)" + }, + "status.Sync.5": { + "message": "Ideiglenes kiszolgálóprobléma vagy érvénytelen elem (5-ös állapot)" + }, + "status.Sync.6": { + "message": "Érvénytelen elem (6-os állapot)" + }, + "status.Sync.8": { + "message": "Az objektum nem található (8-as állapot)" + }, + "status.aborted": { + "message": "Nincs szinkronizálva" + }, + "status.disabled": { + "message": "Letiltva" + }, + "status.empty-response": { + "message": "A kiszolgáló váratlan üres választ küldött." + }, + "status.forbiddenCalendarItemInTasksFolder": { + "message": "Tiltott naptárelem a feladatok mappában (rendezze újra)" + }, + "status.forbiddenTasksItemInCalendarFolder": { + "message": "Tiltott feladatelem a naptár mappában (rendezze újra)" + }, + "status.global.101": { + "message": "A kérés WBXML-t tartalmaz, de nem sikerült XML-be dekódolni (101-es EAS-hiba)." + }, + "status.global.102": { + "message": "A kérés WBXML-t tartalmaz, de nem sikerült XML-be dekódolni (102-es EAS-hiba)." + }, + "status.global.103": { + "message": "A kérésben megadott XML nem követi a protokoll követelményeit (103-as EAS-hiba)." + }, + "status.global.110": { + "message": "A kiszolgáló belső hibát jelentett, és nem szabad azonnal újrapróbálkozni. Az automatikus szinkronizálás 30 percre felfüggesztésre került (110-es EAS hiba)." + }, + "status.global.clientdenied": { + "message": "Az EAS-kiszolgáló ezt jelenti: <##replace.2##> (állapot: ##replace.1##), és nem engedélyezi a TbSync számára a fiókja elérését." + }, + "status.httperror": { + "message": "Kommunikációs hiba (HTTP állapot: ##replace.1##)." + }, + "status.invalid": { + "message": "Érvénytelen kiszolgálóválasz (szemét)." + }, + "status.malformed-xml": { + "message": "Az XML feldolgozása nem sikerült. Ellenőrizze az eseménynaplót a részletekért." + }, + "status.modified": { + "message": "Helyi módosítások" + }, + "status.network": { + "message": "Nem sikerült kapcsolódni a kiszolgálóhoz (##replace.1##)." + }, + "status.networkerror": { + "message": "Nem sikerült kapcsolódni a kiszolgálóhoz." + }, + "status.nosupportedeasversion": { + "message": "A kiszolgáló nem támogatja az ActiveSync v2.5-öt vagy a v14.0-t (csak ezt: ##replace.1##). A TbSync nem fog működni ezzel az ActiveSync-kiszolgálóval." + }, + "status.notargets": { + "message": "A szinkronizálás megszakítása, mert a szinkronizálási célokat nem lehetett létrehozni." + }, + "status.notsupportedeasversion": { + "message": "A kiszolgáló nem támogatja a kiválasztott ActiveSync ##replace.1## verziót (csak ezt: ##replace.2##)." + }, + "status.notsyncronized": { + "message": "A fiókot szinkronizálni kell, legalább egy elem nincs szinkronizálva." + }, + "status.nouserhost": { + "message": "Hiányzó felhasználónév vagy kiszolgáló. Adja meg ezeket az értékeket." + }, + "status.pending": { + "message": "Várakozás a szinkronizálásra" + }, + "status.policy.2": { + "message": "Nincs házirend ehhez a klienshez. Vegye fel a kapcsolatot a kiszolgáló rendszergazdájával, vagy tiltsa le a fiók lekötését." + }, + "status.policy.3": { + "message": "Ismeretlen házirendtípus érték. Vegye fel a kapcsolatot a kiszolgáló rendszergazdájával, vagy tiltsa le a fiók lekötését." + }, + "status.policy.4": { + "message": "A kiszolgáló házirendadatai sérültek (esetleg meghamisították). Vegye fel a kapcsolatot a kiszolgáló rendszergazdájával, vagy tiltsa le a fiók lekötését." + }, + "status.policy.5": { + "message": "A kliens nyugtázza a hibás házirendkulcsot. Vegye fel a kapcsolatot a kiszolgáló rendszergazdájával, vagy tiltsa le a fiók lekötését." + }, + "status.provision": { + "message": "A lekötés sikertelen, állapot: <##replace.1##>" + }, + "status.response-contains-no-data": { + "message": "A kiszolgáló válasza nem tartalmaz adatokat." + }, + "status.resync-loop": { + "message": "Hiba történt, amelyből nem sikerült helyreállni a fiók újraszinkronizálásával. Tiltsa le a fiókot, és próbálja meg újra. (Hiba: állandó újraszinkronizálás)" + }, + "status.security": { + "message": "A biztonságos kapcsolat létrehozása nem sikerült. Önaláírt vagy más, nem megbízható tanúsítványt importált a Thunderbirdbe? (##replace.1##)" + }, + "status.skipped": { + "message": "Még nem támogatott, kihagyva" + }, + "status.syncing": { + "message": "Szinkronizálás" + }, + "status.timeout": { + "message": "Kommunikációs időtúllépés." + }, + "status.wbxml-parse-error": { + "message": "A kiszolgáló olvashatatlan választ küld." + }, + "status.wbxmlerror": { + "message": "A szinkronizálás sikertelen. A kiszolgáló a következő állapottal válaszolt: <##replace.1##>." + }, + "status.wbxmlmissingfield": { + "message": "ActiveSync protokollsértés: A(z) <##replace.1##> kötelező mező hiányzik a kiszolgáló válaszából." + }, + "syncstate.accountdone": { + "message": "Fiók kész" + }, + "syncstate.done": { + "message": "A következő elem előkészítése szinkronizálásra" + }, + "syncstate.eval.response.autodiscover": { + "message": "Frissített kiszolgálóbeállítások feldolgozása" + }, + "syncstate.eval.response.deletefolder": { + "message": "A mappa törölve" + }, + "syncstate.eval.response.estimate": { + "message": "Változásbecslés feldolgozása" + }, + "syncstate.eval.response.folders": { + "message": "A mappalista frissítés feldolgozása" + }, + "syncstate.eval.response.localchanges": { + "message": "A helyi változások nyugtázásának feldolgozása" + }, + "syncstate.eval.response.localdeletes": { + "message": "A helyi törlések nyugtázásának feldolgozása" + }, + "syncstate.eval.response.options": { + "message": "A kiszolgáló beállításainak feldolgozása" + }, + "syncstate.eval.response.provision": { + "message": "Lekötés feldolgozása" + }, + "syncstate.eval.response.remotechanges": { + "message": "A távoli módosítások feldolgozása" + }, + "syncstate.eval.response.revertlocalchanges": { + "message": "A helyi változások visszaállítása" + }, + "syncstate.eval.response.setdeviceinfo": { + "message": "Eszközinformációk küldése" + }, + "syncstate.eval.response.synckey": { + "message": "Szinkronizálási kulcs feldolgozása" + }, + "syncstate.prepare.request.autodiscover": { + "message": "Frissített kiszolgálóbeállítások kérése" + }, + "syncstate.prepare.request.deletefolder": { + "message": "Felkészülés a mappa törlésére" + }, + "syncstate.prepare.request.estimate": { + "message": "Változásbecslés kérése" + }, + "syncstate.prepare.request.folders": { + "message": "Mappalista-frissítés elküldése" + }, + "syncstate.prepare.request.localchanges": { + "message": "Helyi változások küldése" + }, + "syncstate.prepare.request.localdeletes": { + "message": "Helyi törlések küldése" + }, + "syncstate.prepare.request.options": { + "message": "A kiszolgálóbeállítások kérése" + }, + "syncstate.prepare.request.provision": { + "message": "Lekötés kérése" + }, + "syncstate.prepare.request.remotechanges": { + "message": "Távoli módosítások kérése" + }, + "syncstate.prepare.request.revertlocalchanges": { + "message": "Helyi változások összegyűjtése" + }, + "syncstate.prepare.request.setdeviceinfo": { + "message": "Eszközinformációk küldése" + }, + "syncstate.prepare.request.synckey": { + "message": "Szinkronizálási kulcs kérése" + }, + "syncstate.preparing": { + "message": "A következő elem előkészítése szinkronizálásra" + }, + "syncstate.send.request.autodiscover": { + "message": "Várakozás a frissített kiszolgálóbeállításokra" + }, + "syncstate.send.request.deletefolder": { + "message": "Várakozás a mappa törlésére" + }, + "syncstate.send.request.estimate": { + "message": "Várakozás a változásbecslésre" + }, + "syncstate.send.request.folders": { + "message": "Várakozás a mappalista-frissítésre" + }, + "syncstate.send.request.localchanges": { + "message": "Várakozás a helyi változások elismerésére" + }, + "syncstate.send.request.localdeletes": { + "message": "Várakozás a helyi törlések nyugtázására" + }, + "syncstate.send.request.options": { + "message": "Várakozás a kiszolgálóbeállításokra" + }, + "syncstate.send.request.provision": { + "message": "Várakozás a lekötésre" + }, + "syncstate.send.request.remotechanges": { + "message": "Várakozás a távoli módosításokra" + }, + "syncstate.send.request.revertlocalchanges": { + "message": "Várakozás a legfrissebb verziókra" + }, + "syncstate.send.request.setdeviceinfo": { + "message": "Eszközinformációk küldése" + }, + "syncstate.send.request.synckey": { + "message": "Várakozás a szinkronizálási kulcsra" + }, + "syncstate.syncing": { + "message": "Szinkronizálás előkészítése" + } +} diff -Nru eas4tbsync-4.11/_locales/it/messages.json eas4tbsync-4.17/_locales/it/messages.json --- eas4tbsync-4.11/_locales/it/messages.json 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/_locales/it/messages.json 2025-05-15 11:21:18.000000000 +0000 @@ -1,566 +1,566 @@ -{ - "abCard.Anniversary": { - "message": "Anniversario:" - }, - "abCard.AssistantName": { - "message": "Assistente:" - }, - "abCard.AssistantPhoneNumber": { - "message": "Telefono assistente:" - }, - "abCard.Business2PhoneNumber": { - "message": "Secondo telefono ufficio:" - }, - "abCard.BusinessFaxNumber": { - "message": "Fax ufficio:" - }, - "abCard.CarPhoneNumber": { - "message": "Telefono auto:" - }, - "abCard.CompanyMainPhone": { - "message": "Telefono lavoro principale:" - }, - "abCard.Email3Address": { - "message": "Indirizzo di posta elettronica alternativo:" - }, - "abCard.Home2PhoneNumber": { - "message": "Secondo telefono casa:" - }, - "abCard.ManagerName": { - "message": "Supervisore:" - }, - "abCard.MiddleName": { - "message": "Secondo nome:" - }, - "abCard.OtherAddress": { - "message": "Indirizzo:" - }, - "abCard.OtherCity": { - "message": "Città:" - }, - "abCard.OtherCountry": { - "message": "Paese:" - }, - "abCard.OtherState": { - "message": "Stato:" - }, - "abCard.OtherZip": { - "message": "CAP:" - }, - "abCard.RadioPhoneNumber": { - "message": "Telefono radio:" - }, - "abCard.Spouse": { - "message": "Coniuge:" - }, - "abCard.header.eas": { - "message": "Altri campi (EAS)" - }, - "abCard.header.homenumbers": { - "message": "Numeri casa aggiuntivi:" - }, - "abCard.header.messaging": { - "message": "Messaggeria:" - }, - "abCard.header.otheraddress": { - "message": "Altro indirizzo (EAS)" - }, - "abCard.header.othernumbers": { - "message": "Numeri aggiuntivi:" - }, - "abCard.header.people": { - "message": "Persone:" - }, - "abCard.header.worknumbers": { - "message": "Numeri lavoro aggiuntivi:" - }, - "acl.readonly": { - "message": "Accesso al server in sola lettura (ripristina le modifiche locali)" - }, - "acl.readwrite": { - "message": "Leggi e scrivi sul server" - }, - "add.description": { - "message": "Selezionare una delle opzioni configurazione server disponibili e immettere i dettagli richiesti. " - }, - "add.name": { - "message": "Nome account:" - }, - "add.ok": { - "message": "Aggiungi account" - }, - "add.password": { - "message": "Password:" - }, - "add.server": { - "message": "Configurazione server:" - }, - "add.shortdescription": { - "message": "Informazioni sul conto" - }, - "add.title": { - "message": "Aggiunta account Exchange ActiveSync a TbSync" - }, - "add.url": { - "message": "Indirizzo server:" - }, - "add.urldescription": { - "message": "Dovrebbe essere sufficiente fornire solo il nome del server (ad es. mail.yourserver.com), ma è anche possibile fornire l'URL completo (ad es. https://mail.yourserver.com/Microsoft-Server-ActiveSync)." - }, - "add.user": { - "message": "Nome utente (indirizzo di posta elettronica):" - }, - "autocomplete.serverdirectory": { - "message": "directory globale del server" - }, - "autodiscover.Failed": { - "message": "Rilevamento automatico non riuscito per l'utente <##user##>. Le credenziali fornite sono errate o il proprio provider ActiveSync ha un problema temporaneo o non supporta il rilevamento automatico impostazioni." - }, - "autodiscover.NeedEmail": { - "message": "Il rilevamento automatico impostazioni richiede che venga specificato un indirizzo di posta elettronica valido come nome utente." - }, - "autodiscover.Ok": { - "message": "Rilevamento automatico impostazioni completato con successo, è ora possibile verificare le impostazioni facoltative e stabilire la connessione per la sincronizzazione." - }, - "autodiscover.Querying": { - "message": "Rilevamento impostazioni in corso..." - }, - "config.auto": { - "message": "Configurazione server ActiveSync (rilevamento automatico)" - }, - "config.custom": { - "message": "Configurazione server ActiveSync" - }, - "deletefolder.confirm": { - "message": "ELIMINARE PERMANENTEMENTE la cartella '##replace.1##' dal Cestino?" - }, - "deletefolder.menuentry": { - "message": "Elimina permanentemente la cartella '##replace.1##' dal Cestino" - }, - "deletefolder.notallowed": { - "message": "Annullare la sottoscrizione alla cartella '##replace.1##' prima di provare a eliminarla dal Cestino." - }, - "extensionDescription": { - "message": "Aggiunge il supporto per la sincronizzazione di account Exchange ActiveSync (contatti, attività e calendari) a TbSync." - }, - "extensionName": { - "message": "Provider Exchange ActiveSync" - }, - "helplink.BadItemSkipped": { - "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped" - }, - "helplink.global.clientdenied": { - "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F" - }, - "helplink.security": { - "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F" - }, - "manager.tabs.accountsettings": { - "message": "Impostazioni account" - }, - "manager.tabs.outOfOffice": { - "message": "Risponditore automatico" - }, - "manager.tabs.syncsettings": { - "message": "Opzioni" - }, - "newaccount.add_auto": { - "message": "Rileva automaticamente impostazioni e aggiungi account" - }, - "newaccount.add_custom": { - "message": "Aggiungi account" - }, - "pref.AccountName": { - "message": "Nome account" - }, - "pref.ActiveSyncVersion": { - "message": "Versione ActiveSync" - }, - "pref.DeviceId": { - "message": "ID dispositivo ActiveSync" - }, - "pref.ServerName": { - "message": "Indirizzo server" - }, - "pref.ServerNameDescription": { - "message": "ad es. mail.yourserver.com" - }, - "pref.ShowTrashedFolders": { - "message": "Visualizza le cartelle trovate nel Cestino" - }, - "pref.UserName": { - "message": "Nome utente" - }, - "pref.UserNameDescription": { - "message": "Il nome utente è solitamente l'indirizzo di posta elettronica del proprio account." - }, - "pref.autodetect": { - "message": "miglior opzione disponibile" - }, - "pref.birthday": { - "message": "Invia informazioni di compleanno" - }, - "pref.calendaroptions": { - "message": "Opzioni del calendario" - }, - "pref.contactoptions": { - "message": "Opzioni di contatto" - }, - "pref.displayoverride": { - "message": "Ignora il Nome visualizzato e mostra Nome + Cognome" - }, - "pref.generaloptions": { - "message": "Opzioni generali" - }, - "pref.provision": { - "message": "Forza provisioning (opzione richiesta per Kerio)" - }, - "pref.seperator.comma": { - "message": "Virgola" - }, - "pref.seperator.description": { - "message": "Separatore per i campi indirizzo multiriga." - }, - "pref.seperator.linebreak": { - "message": "Separatore riga" - }, - "pref.synclimit.1month": { - "message": "di 4 settimane fa" - }, - "pref.synclimit.2weeks": { - "message": "di 2 settimane fa" - }, - "pref.synclimit.3month": { - "message": "di 3 mesi fa" - }, - "pref.synclimit.6month": { - "message": "di 6 mesi fa" - }, - "pref.synclimit.all": { - "message": "tutto" - }, - "pref.synclimit.description": { - "message": "Periodo di sincronizzazione:" - }, - "pref.usehttps": { - "message": "Utilizza connessione sicura (connettiti tramite HTTPS)" - }, - "recyclebin": { - "message": "Cestino" - }, - "servertype.auto": { - "message": "Configurazione automatica" - }, - "servertype.custom": { - "message": "Configurazione personalizzata" - }, - "servertype.description.auto": { - "message": "Per molti server ActiveSync la configurazione può essere trovata fornendo solo l'indirizzo di posta elettronica." - }, - "servertype.description.custom": { - "message": "Imposta l'account fornendo manualmente l'indirizzo del server a cui connettersi." - }, - "servertype.description.office365": { - "message": "Gli account connessi a Office 365 utilizzano un processo di autenticazione moderno denominato OAuth 2.0 che supporta anche l'autenticazione a più fattori (MFA)." - }, - "servertype.office365": { - "message": "Microsoft Office 365" - }, - "servertype.unlock": { - "message": "Cliccare due volte per sbloccare tutte le impostazioni server predefinite." - }, - "status.401": { - "message": "Impossibile autenticarsi, controllare nome utente e password." - }, - "status.403": { - "message": "Il server ha rifiutato la connessione (vietato)." - }, - "status.404": { - "message": "Utente non trovato (errore HTTP 404)." - }, - "status.449": { - "message": "Il server richiede il provisioning." - }, - "status.500": { - "message": "Errore server sconosciuto (errore HTTP 500)." - }, - "status.503": { - "message": "Servizio non disponibile." - }, - "status.BadItemSkipped": { - "message": "Oggetto errato saltato: ##replace.1##" - }, - "status.FolderDelete.3": { - "message": "Impossibile eliminare una cartella di sistema." - }, - "status.FolderDelete.4": { - "message": "?? Folder does not exist (status 4), resyncing ??" - }, - "status.FolderDelete.6": { - "message": "Impossibile completare il comando, si è verificato un errore sul server." - }, - "status.FolderDelete.9": { - "message": "?? Invalid synchronization key (status 9), resyncing ??" - }, - "status.FolderSync.9": { - "message": "?? Invalid synchronization key (status 9), resyncing ??" - }, - "status.InvalidServerOptions": { - "message": "Il server non fornisce informazioni sulle versioni di ActiveSync supportate. EAS è bloccato per questo utente o questo client (TbSync)? È possibile provare a impostare manualmente la versione di ActiveSync." - }, - "status.OK": { - "message": "OK" - }, - "status.ServerRejectedRequest": { - "message": "Il server EAS ha rifiutato l'ultima richiesta." - }, - "status.ServerRejectedSomeItems": { - "message": "Il server EAS non ha accettato ##replace.1## elementi." - }, - "status.Sync.12": { - "message": "?? Folder hierarchy changed (status 12), resyncing ??" - }, - "status.Sync.3": { - "message": "?? Invalid synchronization key (status 3), resyncing ??" - }, - "status.Sync.4": { - "message": "?? Malformed request (status 4) ??" - }, - "status.Sync.5": { - "message": "?? Temporary server issues or invalid item (status 5) ??" - }, - "status.Sync.6": { - "message": "?? Invalid item (status 6) ??" - }, - "status.Sync.8": { - "message": "?? Object not found (status 8) ??" - }, - "status.aborted": { - "message": "Non sincronizzato" - }, - "status.disabled": { - "message": "L'account non è abilitato, la sincronizzazione è disabilitata." - }, - "status.empty-response": { - "message": "Il server invia una risposta vuota inaspettata." - }, - "status.forbiddenCalendarItemInTasksFolder": { - "message": "?? Forbidden calendar item in a task folder (please resort) ??" - }, - "status.forbiddenTasksItemInCalendarFolder": { - "message": "?? Forbidden task item in a calendar folder (please resort) ??" - }, - "status.global.101": { - "message": "La richiesta contiene WBXML ma non è possibile decodificarlo in XML (errore 101)." - }, - "status.global.102": { - "message": "La richiesta contiene WBXML ma non è possibile decodificarlo in XML (errore 102)." - }, - "status.global.103": { - "message": "L'XML fornito nella richiesta non rispetta i requisiti del protocollo (errore 103)." - }, - "status.global.110": { - "message": "Il server ha segnalato un errore interno e non dovremmo riprovare immediatamente. La sincronizzazione periodica automatica è stata disattivata per 30 minuti (errore EAS 110)." - }, - "status.global.clientdenied": { - "message": "Il server EAS segnala <##replace.2##> (stato ##replace.1##) e non consente a TbSync l'accesso al proprio account." - }, - "status.httperror": { - "message": "Errore di comunicazione (stato HTTP ##replace.1##)." - }, - "status.invalid": { - "message": "Risposta del server non valida (inutile)." - }, - "status.malformed-xml": { - "message": "Impossibile analizzare XML. Controllare il registro eventi per i dettagli." - }, - "status.modified": { - "message": "Modifiche locali presenti" - }, - "status.network": { - "message": "Impossibile collegarsi al server (##replace.1##)." - }, - "status.networkerror": { - "message": "Impossibile connettersi al server." - }, - "status.nosupportedeasversion": { - "message": "Il server non supporta ActiveSync v2.5 o v14.0 (solo ##replace.1##). TbSync non funzionerà con questo server ActiveSync." - }, - "status.notargets": { - "message": "Interruzione sincronizzazione in corso: non è possibile creare le destinazioni sincronizzazione." - }, - "status.notsupportedeasversion": { - "message": "Il server non supporta la versione di ActiveSync selezionata ##replace.1## (solo ##replace.2##)." - }, - "status.notsyncronized": { - "message": "L'account deve essere sincronizzato, almeno un elemento non è sincronizzato." - }, - "status.nouserhost": { - "message": "Nome utente e/o server mancanti. Fornire tali valori." - }, - "status.pending": { - "message": "In attesa di sincronizzazione" - }, - "status.policy.2": { - "message": "Non esiste alcuna policy per questo client. Contattare l'amministratore del proprio server o disabilitare il provisioning per questo account." - }, - "status.policy.3": { - "message": "Valore PolicyType sconosciuto. Contattare l'amministratore del proprio server o disabilitare il provisioning per questo account." - }, - "status.policy.4": { - "message": "I dati di policy sul server sono corrotti (forse alterati). Contattare l'amministratore del proprio server o disabilitare il provisioning per questo account." - }, - "status.policy.5": { - "message": "Il client sta riconoscendo una policy con nome errato. Contattare l'amministratore del proprio server o disabilitare il provisioning per questo account." - }, - "status.provision": { - "message": "Provisioning non riuscito: stato <##replace.1##>" - }, - "status.response-contains-no-data": { - "message": "La risposta dal server non contiene dati." - }, - "status.resync-loop": { - "message": "Si è verificato un errore che non è stato possibile correggere eseguendo una nuova sincronizzazione dell'account. Disabilitare l'account e riprovare. (Errore: ciclo di risincronizzazione)" - }, - "status.security": { - "message": "Impossibile stabilire una connessione sicura. Si sta utilizzando un certificato autofirmato o non affidabile senza averlo importato in Thunderbird? (##replace.1##)" - }, - "status.skipped": { - "message": "Non ancora supportato, omesso" - }, - "status.syncing": { - "message": "Sincronizzazione in corso" - }, - "status.timeout": { - "message": "Timeout durante la comunicazione." - }, - "status.wbxml-parse-error": { - "message": "Il server invia una risposta illeggibile." - }, - "status.wbxmlerror": { - "message": "Sincronizzazione non riuscita. Il server ha risposto con lo stato <##replace.1##>." - }, - "status.wbxmlmissingfield": { - "message": "Violazione protocollo ActiveSync: il campo obbligatorio <##replace.1##> manca dalla risposta del server." - }, - "syncstate.accountdone": { - "message": "Sincronizzazione account completata" - }, - "syncstate.done": { - "message": "Preparazione prossimo elemento per la sincronizzazione in corso" - }, - "syncstate.eval.response.autodiscover": { - "message": "Elaborazione impostazioni server aggiornate in corso" - }, - "syncstate.eval.response.deletefolder": { - "message": "Cartella eliminata" - }, - "syncstate.eval.response.estimate": { - "message": "Elaborazione stima modifiche in corso" - }, - "syncstate.eval.response.folders": { - "message": "Elaborazione aggiornamenti elenco cartelle in corso" - }, - "syncstate.eval.response.localchanges": { - "message": "Elaborazione riconoscimento modifiche locali in corso" - }, - "syncstate.eval.response.localdeletes": { - "message": "Elaborazione riconoscimento eliminazioni locali in corso" - }, - "syncstate.eval.response.options": { - "message": "Elaborazione opzioni server in corso" - }, - "syncstate.eval.response.provision": { - "message": "Elaborazione provisioning in corso" - }, - "syncstate.eval.response.remotechanges": { - "message": "Elaborazione modifiche remote in corso" - }, - "syncstate.eval.response.revertlocalchanges": { - "message": "Annullamento modifiche locali in corso" - }, - "syncstate.eval.response.setdeviceinfo": { - "message": "Invio informazioni dispositivo in corso" - }, - "syncstate.eval.response.synckey": { - "message": "Elaborazione chiave di sincronizzazione in corso" - }, - "syncstate.prepare.request.autodiscover": { - "message": "Richiesta impostazioni server aggiornate in corso" - }, - "syncstate.prepare.request.deletefolder": { - "message": "Preparazione eliminazione cartella in corso" - }, - "syncstate.prepare.request.estimate": { - "message": "Richiesta stima modifiche in corso" - }, - "syncstate.prepare.request.folders": { - "message": "Invio aggiornamenti elenco cartelle in corso" - }, - "syncstate.prepare.request.localchanges": { - "message": "Invio modifiche locali in corso" - }, - "syncstate.prepare.request.localdeletes": { - "message": "Invio eliminazioni locali in corso" - }, - "syncstate.prepare.request.options": { - "message": "Richiesta opzioni server in corso" - }, - "syncstate.prepare.request.provision": { - "message": "Richiesta provisioning in corso" - }, - "syncstate.prepare.request.remotechanges": { - "message": "Richiesta modifiche remote in corso" - }, - "syncstate.prepare.request.revertlocalchanges": { - "message": "Raccolta modifiche locali in corso" - }, - "syncstate.prepare.request.setdeviceinfo": { - "message": "Invio informazioni dispositivo in corso" - }, - "syncstate.prepare.request.synckey": { - "message": "Richiesta chiave di sincronizzazione in corso" - }, - "syncstate.preparing": { - "message": "Preparazione prossimo elemento per la sincronizzazione in corso" - }, - "syncstate.send.request.autodiscover": { - "message": "In attesa delle impostazioni server aggiornate" - }, - "syncstate.send.request.deletefolder": { - "message": "In attesa dell'eliminazione della cartella" - }, - "syncstate.send.request.estimate": { - "message": "In attesa della stima modifiche" - }, - "syncstate.send.request.folders": { - "message": "In attesa degli aggiornamenti elenco cartelle" - }, - "syncstate.send.request.localchanges": { - "message": "In attesa del riconoscimento delle modifiche locali" - }, - "syncstate.send.request.localdeletes": { - "message": "In attesa del riconoscimento delle eliminazioni locali" - }, - "syncstate.send.request.options": { - "message": "In attesa delle opzioni server" - }, - "syncstate.send.request.provision": { - "message": "In attesa del provisioning" - }, - "syncstate.send.request.remotechanges": { - "message": "In attesa delle modifiche remote" - }, - "syncstate.send.request.revertlocalchanges": { - "message": "In attesa delle versioni più recenti" - }, - "syncstate.send.request.setdeviceinfo": { - "message": "Invio informazioni dispositivo in corso" - }, - "syncstate.send.request.synckey": { - "message": "In attesa della chiave di sincronizzazione" - }, - "syncstate.syncing": { - "message": "Inizializzazione sincronizzazione in corso" - } -} +{ + "abCard.Anniversary": { + "message": "Anniversario:" + }, + "abCard.AssistantName": { + "message": "Assistente:" + }, + "abCard.AssistantPhoneNumber": { + "message": "Telefono assistente:" + }, + "abCard.Business2PhoneNumber": { + "message": "Secondo telefono ufficio:" + }, + "abCard.BusinessFaxNumber": { + "message": "Fax ufficio:" + }, + "abCard.CarPhoneNumber": { + "message": "Telefono auto:" + }, + "abCard.CompanyMainPhone": { + "message": "Telefono lavoro principale:" + }, + "abCard.Email3Address": { + "message": "Indirizzo di posta elettronica alternativo:" + }, + "abCard.Home2PhoneNumber": { + "message": "Secondo telefono casa:" + }, + "abCard.ManagerName": { + "message": "Supervisore:" + }, + "abCard.MiddleName": { + "message": "Secondo nome:" + }, + "abCard.OtherAddress": { + "message": "Indirizzo:" + }, + "abCard.OtherCity": { + "message": "Città:" + }, + "abCard.OtherCountry": { + "message": "Paese:" + }, + "abCard.OtherState": { + "message": "Stato:" + }, + "abCard.OtherZip": { + "message": "CAP:" + }, + "abCard.RadioPhoneNumber": { + "message": "Telefono radio:" + }, + "abCard.Spouse": { + "message": "Coniuge:" + }, + "abCard.header.eas": { + "message": "Altri campi (EAS)" + }, + "abCard.header.homenumbers": { + "message": "Numeri casa aggiuntivi:" + }, + "abCard.header.messaging": { + "message": "Messaggeria:" + }, + "abCard.header.otheraddress": { + "message": "Altro indirizzo (EAS)" + }, + "abCard.header.othernumbers": { + "message": "Numeri aggiuntivi:" + }, + "abCard.header.people": { + "message": "Persone:" + }, + "abCard.header.worknumbers": { + "message": "Numeri lavoro aggiuntivi:" + }, + "acl.readonly": { + "message": "Accesso al server in sola lettura (ripristina le modifiche locali)" + }, + "acl.readwrite": { + "message": "Leggi e scrivi sul server" + }, + "add.description": { + "message": "Selezionare una delle opzioni configurazione server disponibili e immettere i dettagli richiesti. " + }, + "add.name": { + "message": "Nome account:" + }, + "add.ok": { + "message": "Aggiungi account" + }, + "add.password": { + "message": "Password:" + }, + "add.server": { + "message": "Configurazione server:" + }, + "add.shortdescription": { + "message": "Informazioni sul conto" + }, + "add.title": { + "message": "Aggiunta account Exchange ActiveSync a TbSync" + }, + "add.url": { + "message": "Indirizzo server:" + }, + "add.urldescription": { + "message": "Dovrebbe essere sufficiente fornire solo il nome del server (ad es. mail.yourserver.com), ma è anche possibile fornire l'URL completo (ad es. https://mail.yourserver.com/Microsoft-Server-ActiveSync)." + }, + "add.user": { + "message": "Nome utente (indirizzo di posta elettronica):" + }, + "autocomplete.serverdirectory": { + "message": "directory globale del server" + }, + "autodiscover.Failed": { + "message": "Rilevamento automatico non riuscito per l'utente <##user##>. Le credenziali fornite sono errate o il proprio provider ActiveSync ha un problema temporaneo o non supporta il rilevamento automatico impostazioni." + }, + "autodiscover.NeedEmail": { + "message": "Il rilevamento automatico impostazioni richiede che venga specificato un indirizzo di posta elettronica valido come nome utente." + }, + "autodiscover.Ok": { + "message": "Rilevamento automatico impostazioni completato con successo, è ora possibile verificare le impostazioni facoltative e stabilire la connessione per la sincronizzazione." + }, + "autodiscover.Querying": { + "message": "Rilevamento impostazioni in corso..." + }, + "config.auto": { + "message": "Configurazione server ActiveSync (rilevamento automatico)" + }, + "config.custom": { + "message": "Configurazione server ActiveSync" + }, + "deletefolder.confirm": { + "message": "ELIMINARE PERMANENTEMENTE la cartella '##replace.1##' dal Cestino?" + }, + "deletefolder.menuentry": { + "message": "Elimina permanentemente la cartella '##replace.1##' dal Cestino" + }, + "deletefolder.notallowed": { + "message": "Annullare la sottoscrizione alla cartella '##replace.1##' prima di provare a eliminarla dal Cestino." + }, + "extensionDescription": { + "message": "Aggiunge il supporto per la sincronizzazione di account Exchange ActiveSync (contatti, attività e calendari) a TbSync." + }, + "extensionName": { + "message": "Provider Exchange ActiveSync" + }, + "helplink.BadItemSkipped": { + "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped" + }, + "helplink.global.clientdenied": { + "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F" + }, + "helplink.security": { + "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F" + }, + "manager.tabs.accountsettings": { + "message": "Impostazioni account" + }, + "manager.tabs.outOfOffice": { + "message": "Risponditore automatico" + }, + "manager.tabs.syncsettings": { + "message": "Opzioni" + }, + "newaccount.add_auto": { + "message": "Rileva automaticamente impostazioni e aggiungi account" + }, + "newaccount.add_custom": { + "message": "Aggiungi account" + }, + "pref.AccountName": { + "message": "Nome account" + }, + "pref.ActiveSyncVersion": { + "message": "Versione ActiveSync" + }, + "pref.DeviceId": { + "message": "ID dispositivo ActiveSync" + }, + "pref.ServerName": { + "message": "Indirizzo server" + }, + "pref.ServerNameDescription": { + "message": "ad es. mail.yourserver.com" + }, + "pref.ShowTrashedFolders": { + "message": "Visualizza le cartelle trovate nel Cestino" + }, + "pref.UserName": { + "message": "Nome utente" + }, + "pref.UserNameDescription": { + "message": "Il nome utente è solitamente l'indirizzo di posta elettronica del proprio account." + }, + "pref.autodetect": { + "message": "miglior opzione disponibile" + }, + "pref.birthday": { + "message": "Invia informazioni di compleanno" + }, + "pref.calendaroptions": { + "message": "Opzioni del calendario" + }, + "pref.contactoptions": { + "message": "Opzioni di contatto" + }, + "pref.displayoverride": { + "message": "Ignora il Nome visualizzato e mostra Nome + Cognome" + }, + "pref.generaloptions": { + "message": "Opzioni generali" + }, + "pref.provision": { + "message": "Forza provisioning (opzione richiesta per Kerio)" + }, + "pref.seperator.comma": { + "message": "Virgola" + }, + "pref.seperator.description": { + "message": "Separatore per i campi indirizzo multiriga." + }, + "pref.seperator.linebreak": { + "message": "Separatore riga" + }, + "pref.synclimit.1month": { + "message": "di 4 settimane fa" + }, + "pref.synclimit.2weeks": { + "message": "di 2 settimane fa" + }, + "pref.synclimit.3month": { + "message": "di 3 mesi fa" + }, + "pref.synclimit.6month": { + "message": "di 6 mesi fa" + }, + "pref.synclimit.all": { + "message": "tutto" + }, + "pref.synclimit.description": { + "message": "Periodo di sincronizzazione:" + }, + "pref.usehttps": { + "message": "Utilizza connessione sicura (connettiti tramite HTTPS)" + }, + "recyclebin": { + "message": "Cestino" + }, + "servertype.auto": { + "message": "Configurazione automatica" + }, + "servertype.custom": { + "message": "Configurazione personalizzata" + }, + "servertype.description.auto": { + "message": "Per molti server ActiveSync la configurazione può essere trovata fornendo solo l'indirizzo di posta elettronica." + }, + "servertype.description.custom": { + "message": "Imposta l'account fornendo manualmente l'indirizzo del server a cui connettersi." + }, + "servertype.description.office365": { + "message": "Gli account connessi a Office 365 utilizzano un processo di autenticazione moderno denominato OAuth 2.0 che supporta anche l'autenticazione a più fattori (MFA)." + }, + "servertype.office365": { + "message": "Microsoft Office 365" + }, + "servertype.unlock": { + "message": "Cliccare due volte per sbloccare tutte le impostazioni server predefinite." + }, + "status.401": { + "message": "Impossibile autenticarsi, controllare nome utente e password." + }, + "status.403": { + "message": "Il server ha rifiutato la connessione (vietato)." + }, + "status.404": { + "message": "Utente non trovato (errore HTTP 404)." + }, + "status.449": { + "message": "Il server richiede il provisioning." + }, + "status.500": { + "message": "Errore server sconosciuto (errore HTTP 500)." + }, + "status.503": { + "message": "Servizio non disponibile." + }, + "status.BadItemSkipped": { + "message": "Oggetto errato saltato: ##replace.1##" + }, + "status.FolderDelete.3": { + "message": "Impossibile eliminare una cartella di sistema." + }, + "status.FolderDelete.4": { + "message": "?? Folder does not exist (status 4), resyncing ??" + }, + "status.FolderDelete.6": { + "message": "Impossibile completare il comando, si è verificato un errore sul server." + }, + "status.FolderDelete.9": { + "message": "?? Invalid synchronization key (status 9), resyncing ??" + }, + "status.FolderSync.9": { + "message": "?? Invalid synchronization key (status 9), resyncing ??" + }, + "status.InvalidServerOptions": { + "message": "Il server non fornisce informazioni sulle versioni di ActiveSync supportate. EAS è bloccato per questo utente o questo client (TbSync)? È possibile provare a impostare manualmente la versione di ActiveSync." + }, + "status.OK": { + "message": "OK" + }, + "status.ServerRejectedRequest": { + "message": "Il server EAS ha rifiutato l'ultima richiesta." + }, + "status.ServerRejectedSomeItems": { + "message": "Il server EAS non ha accettato ##replace.1## elementi." + }, + "status.Sync.12": { + "message": "?? Folder hierarchy changed (status 12), resyncing ??" + }, + "status.Sync.3": { + "message": "?? Invalid synchronization key (status 3), resyncing ??" + }, + "status.Sync.4": { + "message": "?? Malformed request (status 4) ??" + }, + "status.Sync.5": { + "message": "?? Temporary server issues or invalid item (status 5) ??" + }, + "status.Sync.6": { + "message": "?? Invalid item (status 6) ??" + }, + "status.Sync.8": { + "message": "?? Object not found (status 8) ??" + }, + "status.aborted": { + "message": "Non sincronizzato" + }, + "status.disabled": { + "message": "L'account non è abilitato, la sincronizzazione è disabilitata." + }, + "status.empty-response": { + "message": "Il server invia una risposta vuota inaspettata." + }, + "status.forbiddenCalendarItemInTasksFolder": { + "message": "?? Forbidden calendar item in a task folder (please resort) ??" + }, + "status.forbiddenTasksItemInCalendarFolder": { + "message": "?? Forbidden task item in a calendar folder (please resort) ??" + }, + "status.global.101": { + "message": "La richiesta contiene WBXML ma non è possibile decodificarlo in XML (errore 101)." + }, + "status.global.102": { + "message": "La richiesta contiene WBXML ma non è possibile decodificarlo in XML (errore 102)." + }, + "status.global.103": { + "message": "L'XML fornito nella richiesta non rispetta i requisiti del protocollo (errore 103)." + }, + "status.global.110": { + "message": "Il server ha segnalato un errore interno e non dovremmo riprovare immediatamente. La sincronizzazione periodica automatica è stata disattivata per 30 minuti (errore EAS 110)." + }, + "status.global.clientdenied": { + "message": "Il server EAS segnala <##replace.2##> (stato ##replace.1##) e non consente a TbSync l'accesso al proprio account." + }, + "status.httperror": { + "message": "Errore di comunicazione (stato HTTP ##replace.1##)." + }, + "status.invalid": { + "message": "Risposta del server non valida (inutile)." + }, + "status.malformed-xml": { + "message": "Impossibile analizzare XML. Controllare il registro eventi per i dettagli." + }, + "status.modified": { + "message": "Modifiche locali presenti" + }, + "status.network": { + "message": "Impossibile collegarsi al server (##replace.1##)." + }, + "status.networkerror": { + "message": "Impossibile connettersi al server." + }, + "status.nosupportedeasversion": { + "message": "Il server non supporta ActiveSync v2.5 o v14.0 (solo ##replace.1##). TbSync non funzionerà con questo server ActiveSync." + }, + "status.notargets": { + "message": "Interruzione sincronizzazione in corso: non è possibile creare le destinazioni sincronizzazione." + }, + "status.notsupportedeasversion": { + "message": "Il server non supporta la versione di ActiveSync selezionata ##replace.1## (solo ##replace.2##)." + }, + "status.notsyncronized": { + "message": "L'account deve essere sincronizzato, almeno un elemento non è sincronizzato." + }, + "status.nouserhost": { + "message": "Nome utente e/o server mancanti. Fornire tali valori." + }, + "status.pending": { + "message": "In attesa di sincronizzazione" + }, + "status.policy.2": { + "message": "Non esiste alcuna policy per questo client. Contattare l'amministratore del proprio server o disabilitare il provisioning per questo account." + }, + "status.policy.3": { + "message": "Valore PolicyType sconosciuto. Contattare l'amministratore del proprio server o disabilitare il provisioning per questo account." + }, + "status.policy.4": { + "message": "I dati di policy sul server sono corrotti (forse alterati). Contattare l'amministratore del proprio server o disabilitare il provisioning per questo account." + }, + "status.policy.5": { + "message": "Il client sta riconoscendo una policy con nome errato. Contattare l'amministratore del proprio server o disabilitare il provisioning per questo account." + }, + "status.provision": { + "message": "Provisioning non riuscito: stato <##replace.1##>" + }, + "status.response-contains-no-data": { + "message": "La risposta dal server non contiene dati." + }, + "status.resync-loop": { + "message": "Si è verificato un errore che non è stato possibile correggere eseguendo una nuova sincronizzazione dell'account. Disabilitare l'account e riprovare. (Errore: ciclo di risincronizzazione)" + }, + "status.security": { + "message": "Impossibile stabilire una connessione sicura. Si sta utilizzando un certificato autofirmato o non affidabile senza averlo importato in Thunderbird? (##replace.1##)" + }, + "status.skipped": { + "message": "Non ancora supportato, omesso" + }, + "status.syncing": { + "message": "Sincronizzazione in corso" + }, + "status.timeout": { + "message": "Timeout durante la comunicazione." + }, + "status.wbxml-parse-error": { + "message": "Il server invia una risposta illeggibile." + }, + "status.wbxmlerror": { + "message": "Sincronizzazione non riuscita. Il server ha risposto con lo stato <##replace.1##>." + }, + "status.wbxmlmissingfield": { + "message": "Violazione protocollo ActiveSync: il campo obbligatorio <##replace.1##> manca dalla risposta del server." + }, + "syncstate.accountdone": { + "message": "Sincronizzazione account completata" + }, + "syncstate.done": { + "message": "Preparazione prossimo elemento per la sincronizzazione in corso" + }, + "syncstate.eval.response.autodiscover": { + "message": "Elaborazione impostazioni server aggiornate in corso" + }, + "syncstate.eval.response.deletefolder": { + "message": "Cartella eliminata" + }, + "syncstate.eval.response.estimate": { + "message": "Elaborazione stima modifiche in corso" + }, + "syncstate.eval.response.folders": { + "message": "Elaborazione aggiornamenti elenco cartelle in corso" + }, + "syncstate.eval.response.localchanges": { + "message": "Elaborazione riconoscimento modifiche locali in corso" + }, + "syncstate.eval.response.localdeletes": { + "message": "Elaborazione riconoscimento eliminazioni locali in corso" + }, + "syncstate.eval.response.options": { + "message": "Elaborazione opzioni server in corso" + }, + "syncstate.eval.response.provision": { + "message": "Elaborazione provisioning in corso" + }, + "syncstate.eval.response.remotechanges": { + "message": "Elaborazione modifiche remote in corso" + }, + "syncstate.eval.response.revertlocalchanges": { + "message": "Annullamento modifiche locali in corso" + }, + "syncstate.eval.response.setdeviceinfo": { + "message": "Invio informazioni dispositivo in corso" + }, + "syncstate.eval.response.synckey": { + "message": "Elaborazione chiave di sincronizzazione in corso" + }, + "syncstate.prepare.request.autodiscover": { + "message": "Richiesta impostazioni server aggiornate in corso" + }, + "syncstate.prepare.request.deletefolder": { + "message": "Preparazione eliminazione cartella in corso" + }, + "syncstate.prepare.request.estimate": { + "message": "Richiesta stima modifiche in corso" + }, + "syncstate.prepare.request.folders": { + "message": "Invio aggiornamenti elenco cartelle in corso" + }, + "syncstate.prepare.request.localchanges": { + "message": "Invio modifiche locali in corso" + }, + "syncstate.prepare.request.localdeletes": { + "message": "Invio eliminazioni locali in corso" + }, + "syncstate.prepare.request.options": { + "message": "Richiesta opzioni server in corso" + }, + "syncstate.prepare.request.provision": { + "message": "Richiesta provisioning in corso" + }, + "syncstate.prepare.request.remotechanges": { + "message": "Richiesta modifiche remote in corso" + }, + "syncstate.prepare.request.revertlocalchanges": { + "message": "Raccolta modifiche locali in corso" + }, + "syncstate.prepare.request.setdeviceinfo": { + "message": "Invio informazioni dispositivo in corso" + }, + "syncstate.prepare.request.synckey": { + "message": "Richiesta chiave di sincronizzazione in corso" + }, + "syncstate.preparing": { + "message": "Preparazione prossimo elemento per la sincronizzazione in corso" + }, + "syncstate.send.request.autodiscover": { + "message": "In attesa delle impostazioni server aggiornate" + }, + "syncstate.send.request.deletefolder": { + "message": "In attesa dell'eliminazione della cartella" + }, + "syncstate.send.request.estimate": { + "message": "In attesa della stima modifiche" + }, + "syncstate.send.request.folders": { + "message": "In attesa degli aggiornamenti elenco cartelle" + }, + "syncstate.send.request.localchanges": { + "message": "In attesa del riconoscimento delle modifiche locali" + }, + "syncstate.send.request.localdeletes": { + "message": "In attesa del riconoscimento delle eliminazioni locali" + }, + "syncstate.send.request.options": { + "message": "In attesa delle opzioni server" + }, + "syncstate.send.request.provision": { + "message": "In attesa del provisioning" + }, + "syncstate.send.request.remotechanges": { + "message": "In attesa delle modifiche remote" + }, + "syncstate.send.request.revertlocalchanges": { + "message": "In attesa delle versioni più recenti" + }, + "syncstate.send.request.setdeviceinfo": { + "message": "Invio informazioni dispositivo in corso" + }, + "syncstate.send.request.synckey": { + "message": "In attesa della chiave di sincronizzazione" + }, + "syncstate.syncing": { + "message": "Inizializzazione sincronizzazione in corso" + } +} diff -Nru eas4tbsync-4.11/_locales/ja/messages.json eas4tbsync-4.17/_locales/ja/messages.json --- eas4tbsync-4.11/_locales/ja/messages.json 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/_locales/ja/messages.json 2025-05-15 11:21:18.000000000 +0000 @@ -1,566 +1,566 @@ -{ - "abCard.Anniversary": { - "message": "記念日:" - }, - "abCard.AssistantName": { - "message": "アシスタント:" - }, - "abCard.AssistantPhoneNumber": { - "message": "アシスタントの電話番号:" - }, - "abCard.Business2PhoneNumber": { - "message": "勤務先電話番号 2:" - }, - "abCard.BusinessFaxNumber": { - "message": "勤務先 FAX:" - }, - "abCard.CarPhoneNumber": { - "message": "自動車電話番号:" - }, - "abCard.CompanyMainPhone": { - "message": "勤務先電話番号:" - }, - "abCard.Email3Address": { - "message": "電子メール 2:" - }, - "abCard.Home2PhoneNumber": { - "message": "自宅電話番号 2:" - }, - "abCard.ManagerName": { - "message": "マネージャー:" - }, - "abCard.MiddleName": { - "message": "ミドルネーム:" - }, - "abCard.OtherAddress": { - "message": "住所:" - }, - "abCard.OtherCity": { - "message": "町:" - }, - "abCard.OtherCountry": { - "message": "国:" - }, - "abCard.OtherState": { - "message": "都道府県:" - }, - "abCard.OtherZip": { - "message": "郵便番号:" - }, - "abCard.RadioPhoneNumber": { - "message": "無線電話の番号:" - }, - "abCard.Spouse": { - "message": "配偶者/パートナー:" - }, - "abCard.header.eas": { - "message": "その他の項目 (EAS)" - }, - "abCard.header.homenumbers": { - "message": "自宅電話番号 3:" - }, - "abCard.header.messaging": { - "message": "メッセージング:" - }, - "abCard.header.otheraddress": { - "message": "その他のアドレス (EAS)" - }, - "abCard.header.othernumbers": { - "message": "追加の電話番号:" - }, - "abCard.header.people": { - "message": "People:" - }, - "abCard.header.worknumbers": { - "message": "勤務先電話番号 3:" - }, - "acl.readonly": { - "message": "Read-only server access (revert local changes)" - }, - "acl.readwrite": { - "message": "Read from and write to server" - }, - "add.description": { - "message": "利用可能なサーバー構成オプションのいずれかを選択し、要求された詳細を入力してください。 " - }, - "add.name": { - "message": "アカウント名:" - }, - "add.ok": { - "message": "アカウントを追加" - }, - "add.password": { - "message": "パスワード:" - }, - "add.server": { - "message": "サーバー設定:" - }, - "add.shortdescription": { - "message": "アカウント情報" - }, - "add.title": { - "message": "Adding an Exchange ActiveSync account to TbSync" - }, - "add.url": { - "message": "サーバー アドレス:" - }, - "add.urldescription": { - "message": "基本的なサーバーアドレスだけを提供するだけで十分です (例: mail.yourserver.com)。 ただし、完全な URL を提供することもできます (例: https://mail.yourserver.com/Microsoft-Server-ActiveSync)。" - }, - "add.user": { - "message": "ユーザー名 (電子メールアドレス):" - }, - "autocomplete.serverdirectory": { - "message": "global server directory" - }, - "autodiscover.Failed": { - "message": "ユーザー <##user##> の自動検出に失敗しました。指定された資格情報が間違っているか、ActiveSyncプロバイダに一時的な問題があるか、自動検出をサポートしていません。" - }, - "autodiscover.NeedEmail": { - "message": "自動検出にはユーザー名として有効なメールアドレスが必要です。" - }, - "autodiscover.Ok": { - "message": "Autodiscover completed successfully, you can now check the optional settings and establish the synchronization connection." - }, - "autodiscover.Querying": { - "message": "設定を検索中…" - }, - "config.auto": { - "message": "ActiveSync サーバー設定 (自動検出)" - }, - "config.custom": { - "message": "ActiveSync サーバー設定" - }, - "deletefolder.confirm": { - "message": "本当にごみ箱からフォルダ '## replace.1 ##' を完全に削除しますか?" - }, - "deletefolder.menuentry": { - "message": "ごみ箱からフォルダ '## replace.1 ##' を完全に削除" - }, - "deletefolder.notallowed": { - "message": "ゴミ箱から削除する前に、フォルダ “##replace.1##” の登録を解除してください。" - }, - "extensionDescription": { - "message": "TbSync に Exchange ActiveSync アカウントの同期サポートを追加します (連絡先、タスクとカレンダー)。" - }, - "extensionName": { - "message": "Exchange ActiveSync 用プロバイダ" - }, - "helplink.BadItemSkipped": { - "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped" - }, - "helplink.global.clientdenied": { - "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F" - }, - "helplink.security": { - "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F" - }, - "manager.tabs.accountsettings": { - "message": "アカウント設定" - }, - "manager.tabs.outOfOffice": { - "message": "Auto responder" - }, - "manager.tabs.syncsettings": { - "message": "オプション" - }, - "newaccount.add_auto": { - "message": "設定を自動検出してアカウントを追加" - }, - "newaccount.add_custom": { - "message": "アカウントを追加" - }, - "pref.AccountName": { - "message": "説明" - }, - "pref.ActiveSyncVersion": { - "message": "ActiveSync バージョン" - }, - "pref.DeviceId": { - "message": "ActiveSync デバイス ID" - }, - "pref.ServerName": { - "message": "サーバー アドレス" - }, - "pref.ServerNameDescription": { - "message": "例: mail.yourserver.com" - }, - "pref.ShowTrashedFolders": { - "message": "Show folders found in trash" - }, - "pref.UserName": { - "message": "ユーザー名" - }, - "pref.UserNameDescription": { - "message": "ユーザー名は通常、あなたのアカウントの電子メールアドレスです。" - }, - "pref.autodetect": { - "message": "利用可能な最新のバージョン" - }, - "pref.birthday": { - "message": "Send birthday information" - }, - "pref.calendaroptions": { - "message": "カレンダー設定" - }, - "pref.contactoptions": { - "message": "連絡先設定" - }, - "pref.displayoverride": { - "message": "表示名を「名」+「姓」で上書き" - }, - "pref.generaloptions": { - "message": "一般設定" - }, - "pref.provision": { - "message": "プロビジョニングを強制 (Kerio で必要)" - }, - "pref.seperator.comma": { - "message": "カンマ" - }, - "pref.seperator.description": { - "message": "Separator for multiline address field." - }, - "pref.seperator.linebreak": { - "message": "改行" - }, - "pref.synclimit.1month": { - "message": "4 週間前まで" - }, - "pref.synclimit.2weeks": { - "message": "2 週間前まで" - }, - "pref.synclimit.3month": { - "message": "3 ヶ月前まで" - }, - "pref.synclimit.6month": { - "message": "6 ヶ月前まで" - }, - "pref.synclimit.all": { - "message": "全て" - }, - "pref.synclimit.description": { - "message": "同期する期間: " - }, - "pref.usehttps": { - "message": "安全な接続を利用する (https を使用して接続)" - }, - "recyclebin": { - "message": "ごみ箱" - }, - "servertype.auto": { - "message": "自動設定" - }, - "servertype.custom": { - "message": "カスタム設定" - }, - "servertype.description.auto": { - "message": "多くの ActiveSync サーバーの構成は、電子メールアドレスを提供するだけで検出できます。" - }, - "servertype.description.custom": { - "message": "接続するサーバーのアドレスを手動で入力することにより、アカウントを設定します。" - }, - "servertype.description.office365": { - "message": "Office 365に接続されたアカウントは、OAuth 2.0 と呼ばれる最新の認証プロセスを使用します。これは、Multi-Factor-Authentication (MFA、多要素認証) もサポートしています。" - }, - "servertype.office365": { - "message": "Microsoft Office 365" - }, - "servertype.unlock": { - "message": "Double click to unlock all predefined server settings." - }, - "status.401": { - "message": "認証できません。ユーザー名とパスワードを確認してください (HTTP エラー 401)。" - }, - "status.403": { - "message": "サーバーが接続を拒否しました (禁止) (HTTP エラー 403)。" - }, - "status.404": { - "message": "ユーザーが見つかりません (HTTP エラー 404)。" - }, - "status.449": { - "message": "サーバーがプロビジョニングを要求しています (HTTP エラー 449)。" - }, - "status.500": { - "message": "不明なサーバー エラー (HTTP エラー 500)。" - }, - "status.503": { - "message": "サービスが利用できません (HTTP エラー 503)。" - }, - "status.BadItemSkipped": { - "message": "不良アイテムがスキップされました: ##replace.1##" - }, - "status.FolderDelete.3": { - "message": "システムフォルダを削除できません (ステータス 3)" - }, - "status.FolderDelete.4": { - "message": "フォルダが見つかりません (ステータス 4)。再同期中" - }, - "status.FolderDelete.6": { - "message": "コマンドを完了できません。サーバーでエラーが発生しました (ステータス 6)" - }, - "status.FolderDelete.9": { - "message": "Invalid synchronization key (status 9), resyncing" - }, - "status.FolderSync.9": { - "message": "Invalid synchronization key (status 9), resyncing" - }, - "status.InvalidServerOptions": { - "message": "The server does not provide information about the supported ActiveSync versions. Is EAS blocked for this user or this client (TbSync)? You could try to set the ActiveSync version manually." - }, - "status.OK": { - "message": "OK" - }, - "status.ServerRejectedRequest": { - "message": "The EAS Server rejected the last request." - }, - "status.ServerRejectedSomeItems": { - "message": "The EAS server did not accept ##replace.1## elements." - }, - "status.Sync.12": { - "message": "フォルダの階層構造が変更されました (ステータス 12)。再同期中" - }, - "status.Sync.3": { - "message": "Invalid synchronization key (status 3), resyncing" - }, - "status.Sync.4": { - "message": "不正なリクエストです (ステータス 4)" - }, - "status.Sync.5": { - "message": "一時的なサーバーの問題、または無効なアイテムです (ステータス 5)" - }, - "status.Sync.6": { - "message": "無効なアイテムです (ステータス 6)" - }, - "status.Sync.8": { - "message": "オブジェクトが見つかりません (ステータス 8)" - }, - "status.aborted": { - "message": "同期されていません" - }, - "status.disabled": { - "message": "無効" - }, - "status.empty-response": { - "message": "Server sends unexpected empty response." - }, - "status.forbiddenCalendarItemInTasksFolder": { - "message": "Forbidden calendar item in a task folder (please resort)" - }, - "status.forbiddenTasksItemInCalendarFolder": { - "message": "Forbidden task item in a calendar folder (please resort)" - }, - "status.global.101": { - "message": "The request contains WBXML but it could not be decoded into XML (EAS Error 101)." - }, - "status.global.102": { - "message": "The request contains WBXML but it could not be decoded into XML (EAS Error 102)." - }, - "status.global.103": { - "message": "The XML provided in the request does not follow the protocol requirements (EAS Error 103)." - }, - "status.global.110": { - "message": "The server reported an internal error and we should not retry immediately. Automatic periodic sync has been disabled for 30 minutes (EAS Error 110)." - }, - "status.global.clientdenied": { - "message": "EAS サーバーは <## replace.2 ##> (ステータス ## replace.1 ##) を報告し、TbSync がアカウントにアクセスすることを許可しませんでした。" - }, - "status.httperror": { - "message": "コミュニケーション エラー (HTTP ステータス ##replace.1##)。" - }, - "status.invalid": { - "message": "Invalid server response (junk)." - }, - "status.malformed-xml": { - "message": "XML を解析できません。詳細はイベントログをご確認ください。" - }, - "status.modified": { - "message": "ローカルの変更" - }, - "status.network": { - "message": "サーバーに接続できません (##replace.1##)。" - }, - "status.networkerror": { - "message": "サーバーに接続できません。" - }, - "status.nosupportedeasversion": { - "message": "サーバーは ActiveSync v2.5 または v14.0 をサポートしていません (##replace.1## のみ)。TbSync は、この ActiveSync サーバーでは機能しません。" - }, - "status.notargets": { - "message": "Aborting Sync, because sync targets could not be created." - }, - "status.notsupportedeasversion": { - "message": "サーバーは選択された ActiveSync v##replace.1## をサポートしていません (##replace.2## のみ)。" - }, - "status.notsyncronized": { - "message": "Account needs to be synchronized, at least one item is out of sync." - }, - "status.nouserhost": { - "message": "Missing username and/or server. Please provide those values." - }, - "status.pending": { - "message": "同期待ち" - }, - "status.policy.2": { - "message": "There is no policy for this client. Contact your server administrator or disable provisioning for this account." - }, - "status.policy.3": { - "message": "Unknown PolicyType value. Contact your server administrator or disable provisioning for this account." - }, - "status.policy.4": { - "message": "The policy data on the server is corrupted (possibly tampered with). Contact your server administrator or disable provisioning for this account." - }, - "status.policy.5": { - "message": "The client is acknowledging the wrong policy key. Contact your server administrator or disable provisioning for this account." - }, - "status.provision": { - "message": "Provisioning failed with status <##replace.1##>" - }, - "status.response-contains-no-data": { - "message": "Response from the server contains no data." - }, - "status.resync-loop": { - "message": "There was an error from which we could not recover by resyncing the account. Please disable the account and try again. (Error: resync loop)" - }, - "status.security": { - "message": "安全な接続を確立できませんでした。Thunderbird にインポートせずに、自己署名証明書または信頼できない証明書を使用していますか? (##replace.1##)" - }, - "status.skipped": { - "message": "サポートされていません。スキップします。" - }, - "status.syncing": { - "message": "同期中" - }, - "status.timeout": { - "message": "接続がタイムアウトしました。" - }, - "status.wbxml-parse-error": { - "message": "Server sends unreadable response." - }, - "status.wbxmlerror": { - "message": "Sync failed. Server responded with status <##replace.1##>." - }, - "status.wbxmlmissingfield": { - "message": "ActiveSync プロトコル違反: 必須フィールド <##replace.1##> がサーバー応答から見つかりません。" - }, - "syncstate.accountdone": { - "message": "Finished account" - }, - "syncstate.done": { - "message": "Preparing next item for synchronization" - }, - "syncstate.eval.response.autodiscover": { - "message": "Processing updated server settings" - }, - "syncstate.eval.response.deletefolder": { - "message": "Folder deleted" - }, - "syncstate.eval.response.estimate": { - "message": "Processing change estimate" - }, - "syncstate.eval.response.folders": { - "message": "Processing folder list update" - }, - "syncstate.eval.response.localchanges": { - "message": "Processing acknowledgment of local changes" - }, - "syncstate.eval.response.localdeletes": { - "message": "Processing acknowledgment of local deletes" - }, - "syncstate.eval.response.options": { - "message": "Processing server options" - }, - "syncstate.eval.response.provision": { - "message": "Processing provision" - }, - "syncstate.eval.response.remotechanges": { - "message": "Processing remote changes" - }, - "syncstate.eval.response.revertlocalchanges": { - "message": "Reverting local changes" - }, - "syncstate.eval.response.setdeviceinfo": { - "message": "デバイス情報を送信中" - }, - "syncstate.eval.response.synckey": { - "message": "Processing SyncKey" - }, - "syncstate.prepare.request.autodiscover": { - "message": "Requesting updated server settings" - }, - "syncstate.prepare.request.deletefolder": { - "message": "フォルダ削除の準備中" - }, - "syncstate.prepare.request.estimate": { - "message": "Requesting change estimate" - }, - "syncstate.prepare.request.folders": { - "message": "フォルダリストの更新を送信中" - }, - "syncstate.prepare.request.localchanges": { - "message": "ローカルの変更を送信中" - }, - "syncstate.prepare.request.localdeletes": { - "message": "ローカルの削除を送信中" - }, - "syncstate.prepare.request.options": { - "message": "Requesting server options" - }, - "syncstate.prepare.request.provision": { - "message": "Requesting provision" - }, - "syncstate.prepare.request.remotechanges": { - "message": "Requesting remote changes" - }, - "syncstate.prepare.request.revertlocalchanges": { - "message": "ローカルの変更を収集中" - }, - "syncstate.prepare.request.setdeviceinfo": { - "message": "デバイス情報を送信中" - }, - "syncstate.prepare.request.synckey": { - "message": "同期キーをリクエスト中" - }, - "syncstate.preparing": { - "message": "Preparing next item for synchronization" - }, - "syncstate.send.request.autodiscover": { - "message": "Waiting for updated server settings" - }, - "syncstate.send.request.deletefolder": { - "message": "フォルダが削除されるのを待機中" - }, - "syncstate.send.request.estimate": { - "message": "Waiting for change estimate" - }, - "syncstate.send.request.folders": { - "message": "フォルダリストの更新を待機中" - }, - "syncstate.send.request.localchanges": { - "message": "ローカルの変更の承認を待機中" - }, - "syncstate.send.request.localdeletes": { - "message": "ローカルの削除の承認を待機中" - }, - "syncstate.send.request.options": { - "message": "Waiting for server options" - }, - "syncstate.send.request.provision": { - "message": "Waiting for provision" - }, - "syncstate.send.request.remotechanges": { - "message": "リモートの変更を待機中" - }, - "syncstate.send.request.revertlocalchanges": { - "message": "Waiting for most recent versions" - }, - "syncstate.send.request.setdeviceinfo": { - "message": "デバイス情報を送信中" - }, - "syncstate.send.request.synckey": { - "message": "同期キーを待機中" - }, - "syncstate.syncing": { - "message": "同期を初期化中" - } -} +{ + "abCard.Anniversary": { + "message": "記念日:" + }, + "abCard.AssistantName": { + "message": "アシスタント:" + }, + "abCard.AssistantPhoneNumber": { + "message": "アシスタントの電話番号:" + }, + "abCard.Business2PhoneNumber": { + "message": "勤務先電話番号 2:" + }, + "abCard.BusinessFaxNumber": { + "message": "勤務先 FAX:" + }, + "abCard.CarPhoneNumber": { + "message": "自動車電話番号:" + }, + "abCard.CompanyMainPhone": { + "message": "勤務先電話番号:" + }, + "abCard.Email3Address": { + "message": "電子メール 2:" + }, + "abCard.Home2PhoneNumber": { + "message": "自宅電話番号 2:" + }, + "abCard.ManagerName": { + "message": "マネージャー:" + }, + "abCard.MiddleName": { + "message": "ミドルネーム:" + }, + "abCard.OtherAddress": { + "message": "住所:" + }, + "abCard.OtherCity": { + "message": "町:" + }, + "abCard.OtherCountry": { + "message": "国:" + }, + "abCard.OtherState": { + "message": "都道府県:" + }, + "abCard.OtherZip": { + "message": "郵便番号:" + }, + "abCard.RadioPhoneNumber": { + "message": "無線電話の番号:" + }, + "abCard.Spouse": { + "message": "配偶者/パートナー:" + }, + "abCard.header.eas": { + "message": "その他の項目 (EAS)" + }, + "abCard.header.homenumbers": { + "message": "自宅電話番号 3:" + }, + "abCard.header.messaging": { + "message": "メッセージング:" + }, + "abCard.header.otheraddress": { + "message": "その他のアドレス (EAS)" + }, + "abCard.header.othernumbers": { + "message": "追加の電話番号:" + }, + "abCard.header.people": { + "message": "People:" + }, + "abCard.header.worknumbers": { + "message": "勤務先電話番号 3:" + }, + "acl.readonly": { + "message": "Read-only server access (revert local changes)" + }, + "acl.readwrite": { + "message": "Read from and write to server" + }, + "add.description": { + "message": "利用可能なサーバー構成オプションのいずれかを選択し、要求された詳細を入力してください。 " + }, + "add.name": { + "message": "アカウント名:" + }, + "add.ok": { + "message": "アカウントを追加" + }, + "add.password": { + "message": "パスワード:" + }, + "add.server": { + "message": "サーバー設定:" + }, + "add.shortdescription": { + "message": "アカウント情報" + }, + "add.title": { + "message": "Adding an Exchange ActiveSync account to TbSync" + }, + "add.url": { + "message": "サーバー アドレス:" + }, + "add.urldescription": { + "message": "基本的なサーバーアドレスだけを提供するだけで十分です (例: mail.yourserver.com)。 ただし、完全な URL を提供することもできます (例: https://mail.yourserver.com/Microsoft-Server-ActiveSync)。" + }, + "add.user": { + "message": "ユーザー名 (電子メールアドレス):" + }, + "autocomplete.serverdirectory": { + "message": "global server directory" + }, + "autodiscover.Failed": { + "message": "ユーザー <##user##> の自動検出に失敗しました。指定された資格情報が間違っているか、ActiveSyncプロバイダに一時的な問題があるか、自動検出をサポートしていません。" + }, + "autodiscover.NeedEmail": { + "message": "自動検出にはユーザー名として有効なメールアドレスが必要です。" + }, + "autodiscover.Ok": { + "message": "Autodiscover completed successfully, you can now check the optional settings and establish the synchronization connection." + }, + "autodiscover.Querying": { + "message": "設定を検索中…" + }, + "config.auto": { + "message": "ActiveSync サーバー設定 (自動検出)" + }, + "config.custom": { + "message": "ActiveSync サーバー設定" + }, + "deletefolder.confirm": { + "message": "本当にごみ箱からフォルダ '## replace.1 ##' を完全に削除しますか?" + }, + "deletefolder.menuentry": { + "message": "ごみ箱からフォルダ '## replace.1 ##' を完全に削除" + }, + "deletefolder.notallowed": { + "message": "ゴミ箱から削除する前に、フォルダ “##replace.1##” の登録を解除してください。" + }, + "extensionDescription": { + "message": "TbSync に Exchange ActiveSync アカウントの同期サポートを追加します (連絡先、タスクとカレンダー)。" + }, + "extensionName": { + "message": "Exchange ActiveSync 用プロバイダ" + }, + "helplink.BadItemSkipped": { + "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped" + }, + "helplink.global.clientdenied": { + "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F" + }, + "helplink.security": { + "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F" + }, + "manager.tabs.accountsettings": { + "message": "アカウント設定" + }, + "manager.tabs.outOfOffice": { + "message": "Auto responder" + }, + "manager.tabs.syncsettings": { + "message": "オプション" + }, + "newaccount.add_auto": { + "message": "設定を自動検出してアカウントを追加" + }, + "newaccount.add_custom": { + "message": "アカウントを追加" + }, + "pref.AccountName": { + "message": "説明" + }, + "pref.ActiveSyncVersion": { + "message": "ActiveSync バージョン" + }, + "pref.DeviceId": { + "message": "ActiveSync デバイス ID" + }, + "pref.ServerName": { + "message": "サーバー アドレス" + }, + "pref.ServerNameDescription": { + "message": "例: mail.yourserver.com" + }, + "pref.ShowTrashedFolders": { + "message": "Show folders found in trash" + }, + "pref.UserName": { + "message": "ユーザー名" + }, + "pref.UserNameDescription": { + "message": "ユーザー名は通常、あなたのアカウントの電子メールアドレスです。" + }, + "pref.autodetect": { + "message": "利用可能な最新のバージョン" + }, + "pref.birthday": { + "message": "Send birthday information" + }, + "pref.calendaroptions": { + "message": "カレンダー設定" + }, + "pref.contactoptions": { + "message": "連絡先設定" + }, + "pref.displayoverride": { + "message": "表示名を「名」+「姓」で上書き" + }, + "pref.generaloptions": { + "message": "一般設定" + }, + "pref.provision": { + "message": "プロビジョニングを強制 (Kerio で必要)" + }, + "pref.seperator.comma": { + "message": "カンマ" + }, + "pref.seperator.description": { + "message": "Separator for multiline address field." + }, + "pref.seperator.linebreak": { + "message": "改行" + }, + "pref.synclimit.1month": { + "message": "4 週間前まで" + }, + "pref.synclimit.2weeks": { + "message": "2 週間前まで" + }, + "pref.synclimit.3month": { + "message": "3 ヶ月前まで" + }, + "pref.synclimit.6month": { + "message": "6 ヶ月前まで" + }, + "pref.synclimit.all": { + "message": "全て" + }, + "pref.synclimit.description": { + "message": "同期する期間: " + }, + "pref.usehttps": { + "message": "安全な接続を利用する (https を使用して接続)" + }, + "recyclebin": { + "message": "ごみ箱" + }, + "servertype.auto": { + "message": "自動設定" + }, + "servertype.custom": { + "message": "カスタム設定" + }, + "servertype.description.auto": { + "message": "多くの ActiveSync サーバーの構成は、電子メールアドレスを提供するだけで検出できます。" + }, + "servertype.description.custom": { + "message": "接続するサーバーのアドレスを手動で入力することにより、アカウントを設定します。" + }, + "servertype.description.office365": { + "message": "Office 365に接続されたアカウントは、OAuth 2.0 と呼ばれる最新の認証プロセスを使用します。これは、Multi-Factor-Authentication (MFA、多要素認証) もサポートしています。" + }, + "servertype.office365": { + "message": "Microsoft Office 365" + }, + "servertype.unlock": { + "message": "Double click to unlock all predefined server settings." + }, + "status.401": { + "message": "認証できません。ユーザー名とパスワードを確認してください (HTTP エラー 401)。" + }, + "status.403": { + "message": "サーバーが接続を拒否しました (禁止) (HTTP エラー 403)。" + }, + "status.404": { + "message": "ユーザーが見つかりません (HTTP エラー 404)。" + }, + "status.449": { + "message": "サーバーがプロビジョニングを要求しています (HTTP エラー 449)。" + }, + "status.500": { + "message": "不明なサーバー エラー (HTTP エラー 500)。" + }, + "status.503": { + "message": "サービスが利用できません (HTTP エラー 503)。" + }, + "status.BadItemSkipped": { + "message": "不良アイテムがスキップされました: ##replace.1##" + }, + "status.FolderDelete.3": { + "message": "システムフォルダを削除できません (ステータス 3)" + }, + "status.FolderDelete.4": { + "message": "フォルダが見つかりません (ステータス 4)。再同期中" + }, + "status.FolderDelete.6": { + "message": "コマンドを完了できません。サーバーでエラーが発生しました (ステータス 6)" + }, + "status.FolderDelete.9": { + "message": "Invalid synchronization key (status 9), resyncing" + }, + "status.FolderSync.9": { + "message": "Invalid synchronization key (status 9), resyncing" + }, + "status.InvalidServerOptions": { + "message": "The server does not provide information about the supported ActiveSync versions. Is EAS blocked for this user or this client (TbSync)? You could try to set the ActiveSync version manually." + }, + "status.OK": { + "message": "OK" + }, + "status.ServerRejectedRequest": { + "message": "The EAS Server rejected the last request." + }, + "status.ServerRejectedSomeItems": { + "message": "The EAS server did not accept ##replace.1## elements." + }, + "status.Sync.12": { + "message": "フォルダの階層構造が変更されました (ステータス 12)。再同期中" + }, + "status.Sync.3": { + "message": "Invalid synchronization key (status 3), resyncing" + }, + "status.Sync.4": { + "message": "不正なリクエストです (ステータス 4)" + }, + "status.Sync.5": { + "message": "一時的なサーバーの問題、または無効なアイテムです (ステータス 5)" + }, + "status.Sync.6": { + "message": "無効なアイテムです (ステータス 6)" + }, + "status.Sync.8": { + "message": "オブジェクトが見つかりません (ステータス 8)" + }, + "status.aborted": { + "message": "同期されていません" + }, + "status.disabled": { + "message": "無効" + }, + "status.empty-response": { + "message": "Server sends unexpected empty response." + }, + "status.forbiddenCalendarItemInTasksFolder": { + "message": "Forbidden calendar item in a task folder (please resort)" + }, + "status.forbiddenTasksItemInCalendarFolder": { + "message": "Forbidden task item in a calendar folder (please resort)" + }, + "status.global.101": { + "message": "The request contains WBXML but it could not be decoded into XML (EAS Error 101)." + }, + "status.global.102": { + "message": "The request contains WBXML but it could not be decoded into XML (EAS Error 102)." + }, + "status.global.103": { + "message": "The XML provided in the request does not follow the protocol requirements (EAS Error 103)." + }, + "status.global.110": { + "message": "The server reported an internal error and we should not retry immediately. Automatic periodic sync has been disabled for 30 minutes (EAS Error 110)." + }, + "status.global.clientdenied": { + "message": "EAS サーバーは <## replace.2 ##> (ステータス ## replace.1 ##) を報告し、TbSync がアカウントにアクセスすることを許可しませんでした。" + }, + "status.httperror": { + "message": "コミュニケーション エラー (HTTP ステータス ##replace.1##)。" + }, + "status.invalid": { + "message": "Invalid server response (junk)." + }, + "status.malformed-xml": { + "message": "XML を解析できません。詳細はイベントログをご確認ください。" + }, + "status.modified": { + "message": "ローカルの変更" + }, + "status.network": { + "message": "サーバーに接続できません (##replace.1##)。" + }, + "status.networkerror": { + "message": "サーバーに接続できません。" + }, + "status.nosupportedeasversion": { + "message": "サーバーは ActiveSync v2.5 または v14.0 をサポートしていません (##replace.1## のみ)。TbSync は、この ActiveSync サーバーでは機能しません。" + }, + "status.notargets": { + "message": "Aborting Sync, because sync targets could not be created." + }, + "status.notsupportedeasversion": { + "message": "サーバーは選択された ActiveSync v##replace.1## をサポートしていません (##replace.2## のみ)。" + }, + "status.notsyncronized": { + "message": "Account needs to be synchronized, at least one item is out of sync." + }, + "status.nouserhost": { + "message": "Missing username and/or server. Please provide those values." + }, + "status.pending": { + "message": "同期待ち" + }, + "status.policy.2": { + "message": "There is no policy for this client. Contact your server administrator or disable provisioning for this account." + }, + "status.policy.3": { + "message": "Unknown PolicyType value. Contact your server administrator or disable provisioning for this account." + }, + "status.policy.4": { + "message": "The policy data on the server is corrupted (possibly tampered with). Contact your server administrator or disable provisioning for this account." + }, + "status.policy.5": { + "message": "The client is acknowledging the wrong policy key. Contact your server administrator or disable provisioning for this account." + }, + "status.provision": { + "message": "Provisioning failed with status <##replace.1##>" + }, + "status.response-contains-no-data": { + "message": "Response from the server contains no data." + }, + "status.resync-loop": { + "message": "There was an error from which we could not recover by resyncing the account. Please disable the account and try again. (Error: resync loop)" + }, + "status.security": { + "message": "安全な接続を確立できませんでした。Thunderbird にインポートせずに、自己署名証明書または信頼できない証明書を使用していますか? (##replace.1##)" + }, + "status.skipped": { + "message": "サポートされていません。スキップします。" + }, + "status.syncing": { + "message": "同期中" + }, + "status.timeout": { + "message": "接続がタイムアウトしました。" + }, + "status.wbxml-parse-error": { + "message": "Server sends unreadable response." + }, + "status.wbxmlerror": { + "message": "Sync failed. Server responded with status <##replace.1##>." + }, + "status.wbxmlmissingfield": { + "message": "ActiveSync プロトコル違反: 必須フィールド <##replace.1##> がサーバー応答から見つかりません。" + }, + "syncstate.accountdone": { + "message": "Finished account" + }, + "syncstate.done": { + "message": "Preparing next item for synchronization" + }, + "syncstate.eval.response.autodiscover": { + "message": "Processing updated server settings" + }, + "syncstate.eval.response.deletefolder": { + "message": "Folder deleted" + }, + "syncstate.eval.response.estimate": { + "message": "Processing change estimate" + }, + "syncstate.eval.response.folders": { + "message": "Processing folder list update" + }, + "syncstate.eval.response.localchanges": { + "message": "Processing acknowledgment of local changes" + }, + "syncstate.eval.response.localdeletes": { + "message": "Processing acknowledgment of local deletes" + }, + "syncstate.eval.response.options": { + "message": "Processing server options" + }, + "syncstate.eval.response.provision": { + "message": "Processing provision" + }, + "syncstate.eval.response.remotechanges": { + "message": "Processing remote changes" + }, + "syncstate.eval.response.revertlocalchanges": { + "message": "Reverting local changes" + }, + "syncstate.eval.response.setdeviceinfo": { + "message": "デバイス情報を送信中" + }, + "syncstate.eval.response.synckey": { + "message": "Processing SyncKey" + }, + "syncstate.prepare.request.autodiscover": { + "message": "Requesting updated server settings" + }, + "syncstate.prepare.request.deletefolder": { + "message": "フォルダ削除の準備中" + }, + "syncstate.prepare.request.estimate": { + "message": "Requesting change estimate" + }, + "syncstate.prepare.request.folders": { + "message": "フォルダリストの更新を送信中" + }, + "syncstate.prepare.request.localchanges": { + "message": "ローカルの変更を送信中" + }, + "syncstate.prepare.request.localdeletes": { + "message": "ローカルの削除を送信中" + }, + "syncstate.prepare.request.options": { + "message": "Requesting server options" + }, + "syncstate.prepare.request.provision": { + "message": "Requesting provision" + }, + "syncstate.prepare.request.remotechanges": { + "message": "Requesting remote changes" + }, + "syncstate.prepare.request.revertlocalchanges": { + "message": "ローカルの変更を収集中" + }, + "syncstate.prepare.request.setdeviceinfo": { + "message": "デバイス情報を送信中" + }, + "syncstate.prepare.request.synckey": { + "message": "同期キーをリクエスト中" + }, + "syncstate.preparing": { + "message": "Preparing next item for synchronization" + }, + "syncstate.send.request.autodiscover": { + "message": "Waiting for updated server settings" + }, + "syncstate.send.request.deletefolder": { + "message": "フォルダが削除されるのを待機中" + }, + "syncstate.send.request.estimate": { + "message": "Waiting for change estimate" + }, + "syncstate.send.request.folders": { + "message": "フォルダリストの更新を待機中" + }, + "syncstate.send.request.localchanges": { + "message": "ローカルの変更の承認を待機中" + }, + "syncstate.send.request.localdeletes": { + "message": "ローカルの削除の承認を待機中" + }, + "syncstate.send.request.options": { + "message": "Waiting for server options" + }, + "syncstate.send.request.provision": { + "message": "Waiting for provision" + }, + "syncstate.send.request.remotechanges": { + "message": "リモートの変更を待機中" + }, + "syncstate.send.request.revertlocalchanges": { + "message": "Waiting for most recent versions" + }, + "syncstate.send.request.setdeviceinfo": { + "message": "デバイス情報を送信中" + }, + "syncstate.send.request.synckey": { + "message": "同期キーを待機中" + }, + "syncstate.syncing": { + "message": "同期を初期化中" + } +} diff -Nru eas4tbsync-4.11/_locales/pl/messages.json eas4tbsync-4.17/_locales/pl/messages.json --- eas4tbsync-4.11/_locales/pl/messages.json 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/_locales/pl/messages.json 2025-05-15 11:21:20.000000000 +0000 @@ -1,566 +1,566 @@ -{ - "abCard.Anniversary": { - "message": "Rocznica:" - }, - "abCard.AssistantName": { - "message": "Asystent:" - }, - "abCard.AssistantPhoneNumber": { - "message": "Telefon Asystenta:" - }, - "abCard.Business2PhoneNumber": { - "message": "Alternatywny Telefon Służbowy:" - }, - "abCard.BusinessFaxNumber": { - "message": "Faks służbowy:" - }, - "abCard.CarPhoneNumber": { - "message": "Telefon w Aucie:" - }, - "abCard.CompanyMainPhone": { - "message": "Główny Telefon Służbowy:" - }, - "abCard.Email3Address": { - "message": "Alternatywny e-mail:" - }, - "abCard.Home2PhoneNumber": { - "message": "Alternatywny Telefon Domowy:" - }, - "abCard.ManagerName": { - "message": "Menedżer:" - }, - "abCard.MiddleName": { - "message": "Drugie imię:" - }, - "abCard.OtherAddress": { - "message": "Adres:" - }, - "abCard.OtherCity": { - "message": "Miasto:" - }, - "abCard.OtherCountry": { - "message": "Państwo:" - }, - "abCard.OtherState": { - "message": "Województwo:" - }, - "abCard.OtherZip": { - "message": "Kod pocztowy:" - }, - "abCard.RadioPhoneNumber": { - "message": "Radiotelefon:" - }, - "abCard.Spouse": { - "message": "Małżonek:" - }, - "abCard.header.eas": { - "message": "Inne Pola (EAS)" - }, - "abCard.header.homenumbers": { - "message": "Dodatkowe numery domowe:" - }, - "abCard.header.messaging": { - "message": "Komunikatory:" - }, - "abCard.header.otheraddress": { - "message": "Inne Adresy (EAS)" - }, - "abCard.header.othernumbers": { - "message": "Dodatkowe numery:" - }, - "abCard.header.people": { - "message": "Osoby:" - }, - "abCard.header.worknumbers": { - "message": "Dodatkowe numery służbowe:" - }, - "acl.readonly": { - "message": "Dostęp do serwera tylko do odczytu (cofnij zmiany lokalne)" - }, - "acl.readwrite": { - "message": "Odczytuj i zapisuj na serwer" - }, - "add.description": { - "message": "Wybierz jedną z dostępnych opcji konfiguracji serwera i wprowadź wymagane dane. " - }, - "add.name": { - "message": "Nazwa konta:" - }, - "add.ok": { - "message": "Dodaj konto" - }, - "add.password": { - "message": "Hasło:" - }, - "add.server": { - "message": "Konfiguracja serwera:" - }, - "add.shortdescription": { - "message": "Informacje o koncie" - }, - "add.title": { - "message": "Dodawanie konta Exchange ActiveSync do TbSync" - }, - "add.url": { - "message": "Adres serwera:" - }, - "add.urldescription": { - "message": "Powinno wystarczyć podanie tylko podstawowego adresu serwera (np.: mail.twojserwer.com). Jednakże możliwe jest również podanie pełnego adresu URL (np.: https://mail.twojserwer.com/Microsoft-Server-ActiveSync)." - }, - "add.user": { - "message": "Nazwa użytkownika (adres e-mail):" - }, - "autocomplete.serverdirectory": { - "message": "globalny katalog serwera" - }, - "autodiscover.Failed": { - "message": "Auto-wykrywanie dla użytkownika <##user##> nie powiodło się. Podane dane uwierzytelniające były nieprawidłowe lub dostawca ActiveSync ma tymczasowy problem lub nie obsługuje funkcji automatycznego wykrywania." - }, - "autodiscover.NeedEmail": { - "message": "Automatyczne wykrywanie potrzebuje prawidłowego adresu e-mail jako nazwy użytkownika." - }, - "autodiscover.Ok": { - "message": "Automatyczne wykrywanie zakończyło się pomyślnie, możesz teraz sprawdzić ustawienia opcjonalne i ustanowić połączenie synchronizacji." - }, - "autodiscover.Querying": { - "message": "Wyszukiwanie ustawień…" - }, - "config.auto": { - "message": "Konfiguracja serwera ActiveSync (Auto-wykrywanie)" - }, - "config.custom": { - "message": "Konfiguracja serwera ActiveSync" - }, - "deletefolder.confirm": { - "message": "Czy naprawdę chcesz TRWALE USUNĄĆ folder “##replace.1##” z kosza?" - }, - "deletefolder.menuentry": { - "message": "Trwale usuń folder “##replace.1##” z kosza" - }, - "deletefolder.notallowed": { - "message": "Anuluj subskrypcję folderu “##replace.1##” przed próbą usunięcia go z kosza." - }, - "extensionDescription": { - "message": "Dodaj obsługę synchronizacji kont Exchange ActiveSync do TbSync (kontakty, zadania i kalendarze)." - }, - "extensionName": { - "message": "Dostawca dla Exchange ActiveSync" - }, - "helplink.BadItemSkipped": { - "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped" - }, - "helplink.global.clientdenied": { - "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F" - }, - "helplink.security": { - "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F" - }, - "manager.tabs.accountsettings": { - "message": "Ustawienia konta" - }, - "manager.tabs.outOfOffice": { - "message": "Automatyczna odpowiedź" - }, - "manager.tabs.syncsettings": { - "message": "Opcje" - }, - "newaccount.add_auto": { - "message": "Wykryj automatycznie ustawienia i dodaj konto" - }, - "newaccount.add_custom": { - "message": "Dodaj konto" - }, - "pref.AccountName": { - "message": "Opis" - }, - "pref.ActiveSyncVersion": { - "message": "Wersja ActiveSync" - }, - "pref.DeviceId": { - "message": "ID urządzenia ActiveSync" - }, - "pref.ServerName": { - "message": "Adres serwera" - }, - "pref.ServerNameDescription": { - "message": "np. mail.twojserwer.com" - }, - "pref.ShowTrashedFolders": { - "message": "Pokaż foldery znalezione w koszu" - }, - "pref.UserName": { - "message": "Nazwa użytkownika" - }, - "pref.UserNameDescription": { - "message": "Nazwa użytkownika to zazwyczaj adres e-mail Twojego konta." - }, - "pref.autodetect": { - "message": "najlepsza dostępna" - }, - "pref.birthday": { - "message": "Wyślij informacje o urodzinach" - }, - "pref.calendaroptions": { - "message": "Opcje kalendarza" - }, - "pref.contactoptions": { - "message": "Opcje kontaktu" - }, - "pref.displayoverride": { - "message": "Zastąp nazwę wyświetlaną ciągiem “Imię“ + “Drugie imię”" - }, - "pref.generaloptions": { - "message": "Opcje ogólne" - }, - "pref.provision": { - "message": "Wymuś provisioning (wymagane przez Kerio)" - }, - "pref.seperator.comma": { - "message": "Przecinek" - }, - "pref.seperator.description": { - "message": "Separator pola adresu wielowierszowego." - }, - "pref.seperator.linebreak": { - "message": "Znak końca linii" - }, - "pref.synclimit.1month": { - "message": "z 4 tygodni" - }, - "pref.synclimit.2weeks": { - "message": "z 2 tygodni" - }, - "pref.synclimit.3month": { - "message": "z 3 miesięcy" - }, - "pref.synclimit.6month": { - "message": "z 6 miesięcy" - }, - "pref.synclimit.all": { - "message": "wszystko" - }, - "pref.synclimit.description": { - "message": "Okres synchronizacji: " - }, - "pref.usehttps": { - "message": "Użyj bezpiecznego połączenia (połącz przez https)" - }, - "recyclebin": { - "message": "Kosz" - }, - "servertype.auto": { - "message": "Automatyczna konfiguracja" - }, - "servertype.custom": { - "message": "Konfiguracja niestandardowa" - }, - "servertype.description.auto": { - "message": "Konfiguracja dla wielu serwerów ActiveSync może zostać odnaleziona poprzez podanie tylko adresu e-mail." - }, - "servertype.description.custom": { - "message": "Skonfiguruj konto, podając ręcznie adres serwera, z którym chcesz się połączyć." - }, - "servertype.description.office365": { - "message": "Konta połączone z Office 365 korzystają z nowoczesnego procesu uwierzytelniania o nazwie OAuth 2.0, który obsługuje również uwierzytelnianie wielopoziomowe (MFA)." - }, - "servertype.office365": { - "message": "Microsoft Office 365" - }, - "servertype.unlock": { - "message": "Kliknij dwukrotnie, aby odblokować wszystkie predefiniowane ustawienia serwera." - }, - "status.401": { - "message": "Nie można uwierzytelnić, sprawdź nazwę użytkownika i hasło (HTTP Error 401)." - }, - "status.403": { - "message": "Serwer odrzucił połączenie (zabronione) (błąd HTTP 403)." - }, - "status.404": { - "message": "Użytkownik nie znaleziony (błąd HTTP 404)." - }, - "status.449": { - "message": "Server requests provisioning (HTTP Error 449)." - }, - "status.500": { - "message": "Nieznany błąd serwera (błąd HTTP 500)." - }, - "status.503": { - "message": "Usługa niedostępna (błąd HTTP 503)." - }, - "status.BadItemSkipped": { - "message": "Błędny element pominięto: ##replace.1##" - }, - "status.FolderDelete.3": { - "message": "Nie można usunąć folderu systemowego (status 3)" - }, - "status.FolderDelete.4": { - "message": "Folder nie istnieje (status 4), ponowna synchronizacja" - }, - "status.FolderDelete.6": { - "message": "Nie można wykonać polecenia, wystąpił błąd na serwerze (status 6)" - }, - "status.FolderDelete.9": { - "message": "Nieprawidłowy klucz synchronizacji (status 9), ponowna synchronizacja" - }, - "status.FolderSync.9": { - "message": "Nieprawidłowy klucz synchronizacji (status 9), ponowna synchronizacja" - }, - "status.InvalidServerOptions": { - "message": "Serwer nie dostarcza informacji o obsługiwanych wersjach ActiveSync. Czy EAS jest zablokowany dla tego użytkownika lub tego klienta (TbSync)? Możesz spróbować ręcznie ustawić wersję ActiveSync." - }, - "status.OK": { - "message": "OK" - }, - "status.ServerRejectedRequest": { - "message": "Serwer EAS odrzucił ostatnie żądanie." - }, - "status.ServerRejectedSomeItems": { - "message": "Serwer EAS nie zaakceptował #replace.1## elementów." - }, - "status.Sync.12": { - "message": "Hierarchia folderów zmieniona (status 12), ponowna synchronizacja" - }, - "status.Sync.3": { - "message": "Nieprawidłowy klucz synchronizacji (status 3), ponowna synchronizacja" - }, - "status.Sync.4": { - "message": "Zniekształcone żądanie (status 4)" - }, - "status.Sync.5": { - "message": "Tymczasowe problemy z serwerem lub nieprawidłowy element (status 5)" - }, - "status.Sync.6": { - "message": "Nieprawidłowy element (status 6)" - }, - "status.Sync.8": { - "message": "Nie znaleziono obiektu (status 8)" - }, - "status.aborted": { - "message": "Nie zsynchronizowane" - }, - "status.disabled": { - "message": "Wyłączony" - }, - "status.empty-response": { - "message": "Serwer wysyła nieoczekiwaną pustą odpowiedź." - }, - "status.forbiddenCalendarItemInTasksFolder": { - "message": "Niedozwolony element kalendarza w folderze zadań (please resort)" - }, - "status.forbiddenTasksItemInCalendarFolder": { - "message": "Niedozwolony element zadania w folderze kalendarza (please resort)" - }, - "status.global.101": { - "message": "Żądanie zawiera WBXML, ale nie można go zdekodować do formatu XML (błąd EAS 101)." - }, - "status.global.102": { - "message": "Żądanie zawiera WBXML, ale nie można go zdekodować do formatu XML (błąd EAS 102)." - }, - "status.global.103": { - "message": "XML podany w żądaniu nie jest zgodny z wymaganiami protokołu (błąd EAS 103)." - }, - "status.global.110": { - "message": "Serwer zgłosił błąd wewnętrzny i nie powinniśmy natychmiast ponawiać próby. Automatyczna synchronizacja okresowa została wyłączona na 30 minut (błąd EAS 110)." - }, - "status.global.clientdenied": { - "message": "Serwer EAS zgłasza <##replace.2##> (status ##replace.1##) i nie zezwala TbSync na dostęp do Twojego konta." - }, - "status.httperror": { - "message": "Błąd komunikacji (status HTTP ##replace.1##)." - }, - "status.invalid": { - "message": "Niepoprawna odpowiedź serwera (śmieci)." - }, - "status.malformed-xml": { - "message": "Nie można przetworzyć XML. Sprawdź dziennik zdarzeń, aby uzyskać szczegóły." - }, - "status.modified": { - "message": "Zmiany lokalne" - }, - "status.network": { - "message": "Nie można połączyć z serwerem (##replace.1##)." - }, - "status.networkerror": { - "message": "Nie można połączyć z serwerem." - }, - "status.nosupportedeasversion": { - "message": "Serwer nie obsługuje ActiveSync v2.5 lub v14.0 (tylko ##replace.1##). TbSync nie będzie działać z tym serwerem ActiveSync." - }, - "status.notargets": { - "message": "Przerywam synchronizację, ponieważ nie można utworzyć celów synchronizacji." - }, - "status.notsupportedeasversion": { - "message": "Serwer nie wspiera wybranego ActiveSync v##replace.1## (tylko ##replace.2##)." - }, - "status.notsyncronized": { - "message": "Konto musi zostać zsynchronizowane, co najmniej jeden element nie jest zsynchronizowany." - }, - "status.nouserhost": { - "message": "Brak nazwy użytkownika i/lub serwera. Proszę podać te wartości." - }, - "status.pending": { - "message": "Oczekiwanie na synchronizację" - }, - "status.policy.2": { - "message": "Brak zasad dla tego klienta. Skontaktuj się z administratorem serwera lub wyłącz provisioning dla tego konta." - }, - "status.policy.3": { - "message": "Nieznana wartość PolicyType. Skontaktuj się z administratorem serwera lub wyłącz provisioning dla tego konta." - }, - "status.policy.4": { - "message": "Dane zasad na serwerze są uszkodzone (prawdopodobnie zmienione/sfałszowane). Skontaktuj się z administratorem serwera lub wyłącz provisioning dla tego konta." - }, - "status.policy.5": { - "message": "Klient potwierdza zły klucz zasad. Skontaktuj się z administratorem serwera lub wyłącz provisioning dla tego konta." - }, - "status.provision": { - "message": "Niepowodzenie provisioning ze statusem <##replace.1##>" - }, - "status.response-contains-no-data": { - "message": "Odpowiedź z serwera nie zawiera danych." - }, - "status.resync-loop": { - "message": "Wystąpił błąd, którego nie udało się naprawić poprzez ponowne zsynchronizowanie konta. Wyłącz konto i spróbuj ponownie. (Błąd: pętla resynchronizacji)" - }, - "status.security": { - "message": "Nie można nawiązać bezpiecznego połączenia. Czy używasz własnego podpisu lub w inny sposób niezaufanego certyfikatu bez importowania go do Thunderbirda? (##replace.1##)" - }, - "status.skipped": { - "message": "Jeszcze nie obsługiwane, pominięto" - }, - "status.syncing": { - "message": "Synchronizuję" - }, - "status.timeout": { - "message": "Przekroczony limit czasu połączenia." - }, - "status.wbxml-parse-error": { - "message": "Serwer wysyła nieczytelną odpowiedź." - }, - "status.wbxmlerror": { - "message": "Synchronizacja nie powiodła się. Serwer odpowiedział statusem <##replace.1##>." - }, - "status.wbxmlmissingfield": { - "message": "Naruszenie protokołu ActiveSync: W odpowiedzi serwera brakuje obowiązkowego pola <##replace.1##>." - }, - "syncstate.accountdone": { - "message": "Konto gotowe" - }, - "syncstate.done": { - "message": "Przygotowuję następny element do synchronizacji" - }, - "syncstate.eval.response.autodiscover": { - "message": "Przetwarzanie zaktualizowanych ustawień serwera" - }, - "syncstate.eval.response.deletefolder": { - "message": "Folder usunięty" - }, - "syncstate.eval.response.estimate": { - "message": "Przetwarzanie oszacowanych zmian" - }, - "syncstate.eval.response.folders": { - "message": "Przetwarzanie aktualizacji listy folderów" - }, - "syncstate.eval.response.localchanges": { - "message": "Przetwarzanie potwierdzenia lokalnych zmian" - }, - "syncstate.eval.response.localdeletes": { - "message": "Przetwarzanie potwierdzenia usunięcia lokalnego" - }, - "syncstate.eval.response.options": { - "message": "Przetwarzanie opcji serwera" - }, - "syncstate.eval.response.provision": { - "message": "Przetwarzanie provision" - }, - "syncstate.eval.response.remotechanges": { - "message": "Przetwarzanie zdalnych zmian" - }, - "syncstate.eval.response.revertlocalchanges": { - "message": "Wycofywanie zmian lokalnych" - }, - "syncstate.eval.response.setdeviceinfo": { - "message": "Wysyłanie informacji o urządzeniu" - }, - "syncstate.eval.response.synckey": { - "message": "Przetwarzanie SyncKey" - }, - "syncstate.prepare.request.autodiscover": { - "message": "Żądanie zaktualizowanych ustawień serwera" - }, - "syncstate.prepare.request.deletefolder": { - "message": "Przygotowanie do usunięcia folderu" - }, - "syncstate.prepare.request.estimate": { - "message": "Żądanie oszacowanych zmian" - }, - "syncstate.prepare.request.folders": { - "message": "Wysyłanie aktualizacji listy folderów" - }, - "syncstate.prepare.request.localchanges": { - "message": "Wysyłanie zmian lokalnych" - }, - "syncstate.prepare.request.localdeletes": { - "message": "Wysyłanie usuniętych lokalnie" - }, - "syncstate.prepare.request.options": { - "message": "Żądanie opcji serwera" - }, - "syncstate.prepare.request.provision": { - "message": "Żądanie provision" - }, - "syncstate.prepare.request.remotechanges": { - "message": "Żądanie zdalnych zmian" - }, - "syncstate.prepare.request.revertlocalchanges": { - "message": "Zbieranie zmian lokalnych" - }, - "syncstate.prepare.request.setdeviceinfo": { - "message": "Wysyłanie informacji o urządzeniu" - }, - "syncstate.prepare.request.synckey": { - "message": "Żądanie SyncKey" - }, - "syncstate.preparing": { - "message": "Przygotowuję następny element do synchronizacji" - }, - "syncstate.send.request.autodiscover": { - "message": "Oczekiwanie na zaktualizowane ustawienia serwera" - }, - "syncstate.send.request.deletefolder": { - "message": "Oczekiwanie na usunięcie folderu" - }, - "syncstate.send.request.estimate": { - "message": "Oczekiwanie na oszacowanie zmian" - }, - "syncstate.send.request.folders": { - "message": "Oczekiwanie na aktualizację listy folderów" - }, - "syncstate.send.request.localchanges": { - "message": "Oczekiwanie na potwierdzenie lokalnych zmian" - }, - "syncstate.send.request.localdeletes": { - "message": "Oczekiwanie na potwierdzenie usunięcia lokalnego" - }, - "syncstate.send.request.options": { - "message": "Oczekiwanie na opcje serwera" - }, - "syncstate.send.request.provision": { - "message": "Oczekiwanie na provision" - }, - "syncstate.send.request.remotechanges": { - "message": "Oczekiwanie na zdalne zmiany" - }, - "syncstate.send.request.revertlocalchanges": { - "message": "Oczekiwanie na najnowsze wersje" - }, - "syncstate.send.request.setdeviceinfo": { - "message": "Wysyłanie informacji o urządzeniu" - }, - "syncstate.send.request.synckey": { - "message": "Oczekiwanie na SyncKey" - }, - "syncstate.syncing": { - "message": "Zainicjuj synchronizację" - } -} +{ + "abCard.Anniversary": { + "message": "Rocznica:" + }, + "abCard.AssistantName": { + "message": "Asystent:" + }, + "abCard.AssistantPhoneNumber": { + "message": "Telefon Asystenta:" + }, + "abCard.Business2PhoneNumber": { + "message": "Alternatywny Telefon Służbowy:" + }, + "abCard.BusinessFaxNumber": { + "message": "Faks służbowy:" + }, + "abCard.CarPhoneNumber": { + "message": "Telefon w Aucie:" + }, + "abCard.CompanyMainPhone": { + "message": "Główny Telefon Służbowy:" + }, + "abCard.Email3Address": { + "message": "Alternatywny e-mail:" + }, + "abCard.Home2PhoneNumber": { + "message": "Alternatywny Telefon Domowy:" + }, + "abCard.ManagerName": { + "message": "Menedżer:" + }, + "abCard.MiddleName": { + "message": "Drugie imię:" + }, + "abCard.OtherAddress": { + "message": "Adres:" + }, + "abCard.OtherCity": { + "message": "Miasto:" + }, + "abCard.OtherCountry": { + "message": "Państwo:" + }, + "abCard.OtherState": { + "message": "Województwo:" + }, + "abCard.OtherZip": { + "message": "Kod pocztowy:" + }, + "abCard.RadioPhoneNumber": { + "message": "Radiotelefon:" + }, + "abCard.Spouse": { + "message": "Małżonek:" + }, + "abCard.header.eas": { + "message": "Inne Pola (EAS)" + }, + "abCard.header.homenumbers": { + "message": "Dodatkowe numery domowe:" + }, + "abCard.header.messaging": { + "message": "Komunikatory:" + }, + "abCard.header.otheraddress": { + "message": "Inne Adresy (EAS)" + }, + "abCard.header.othernumbers": { + "message": "Dodatkowe numery:" + }, + "abCard.header.people": { + "message": "Osoby:" + }, + "abCard.header.worknumbers": { + "message": "Dodatkowe numery służbowe:" + }, + "acl.readonly": { + "message": "Dostęp do serwera tylko do odczytu (cofnij zmiany lokalne)" + }, + "acl.readwrite": { + "message": "Odczytuj i zapisuj na serwer" + }, + "add.description": { + "message": "Wybierz jedną z dostępnych opcji konfiguracji serwera i wprowadź wymagane dane. " + }, + "add.name": { + "message": "Nazwa konta:" + }, + "add.ok": { + "message": "Dodaj konto" + }, + "add.password": { + "message": "Hasło:" + }, + "add.server": { + "message": "Konfiguracja serwera:" + }, + "add.shortdescription": { + "message": "Informacje o koncie" + }, + "add.title": { + "message": "Dodawanie konta Exchange ActiveSync do TbSync" + }, + "add.url": { + "message": "Adres serwera:" + }, + "add.urldescription": { + "message": "Powinno wystarczyć podanie tylko podstawowego adresu serwera (np.: mail.twojserwer.com). Jednakże możliwe jest również podanie pełnego adresu URL (np.: https://mail.twojserwer.com/Microsoft-Server-ActiveSync)." + }, + "add.user": { + "message": "Nazwa użytkownika (adres e-mail):" + }, + "autocomplete.serverdirectory": { + "message": "globalny katalog serwera" + }, + "autodiscover.Failed": { + "message": "Auto-wykrywanie dla użytkownika <##user##> nie powiodło się. Podane dane uwierzytelniające były nieprawidłowe lub dostawca ActiveSync ma tymczasowy problem lub nie obsługuje funkcji automatycznego wykrywania." + }, + "autodiscover.NeedEmail": { + "message": "Automatyczne wykrywanie potrzebuje prawidłowego adresu e-mail jako nazwy użytkownika." + }, + "autodiscover.Ok": { + "message": "Automatyczne wykrywanie zakończyło się pomyślnie, możesz teraz sprawdzić ustawienia opcjonalne i ustanowić połączenie synchronizacji." + }, + "autodiscover.Querying": { + "message": "Wyszukiwanie ustawień…" + }, + "config.auto": { + "message": "Konfiguracja serwera ActiveSync (Auto-wykrywanie)" + }, + "config.custom": { + "message": "Konfiguracja serwera ActiveSync" + }, + "deletefolder.confirm": { + "message": "Czy naprawdę chcesz TRWALE USUNĄĆ folder “##replace.1##” z kosza?" + }, + "deletefolder.menuentry": { + "message": "Trwale usuń folder “##replace.1##” z kosza" + }, + "deletefolder.notallowed": { + "message": "Anuluj subskrypcję folderu “##replace.1##” przed próbą usunięcia go z kosza." + }, + "extensionDescription": { + "message": "Dodaj obsługę synchronizacji kont Exchange ActiveSync do TbSync (kontakty, zadania i kalendarze)." + }, + "extensionName": { + "message": "Dostawca dla Exchange ActiveSync" + }, + "helplink.BadItemSkipped": { + "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped" + }, + "helplink.global.clientdenied": { + "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F" + }, + "helplink.security": { + "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F" + }, + "manager.tabs.accountsettings": { + "message": "Ustawienia konta" + }, + "manager.tabs.outOfOffice": { + "message": "Automatyczna odpowiedź" + }, + "manager.tabs.syncsettings": { + "message": "Opcje" + }, + "newaccount.add_auto": { + "message": "Wykryj automatycznie ustawienia i dodaj konto" + }, + "newaccount.add_custom": { + "message": "Dodaj konto" + }, + "pref.AccountName": { + "message": "Opis" + }, + "pref.ActiveSyncVersion": { + "message": "Wersja ActiveSync" + }, + "pref.DeviceId": { + "message": "ID urządzenia ActiveSync" + }, + "pref.ServerName": { + "message": "Adres serwera" + }, + "pref.ServerNameDescription": { + "message": "np. mail.twojserwer.com" + }, + "pref.ShowTrashedFolders": { + "message": "Pokaż foldery znalezione w koszu" + }, + "pref.UserName": { + "message": "Nazwa użytkownika" + }, + "pref.UserNameDescription": { + "message": "Nazwa użytkownika to zazwyczaj adres e-mail Twojego konta." + }, + "pref.autodetect": { + "message": "najlepsza dostępna" + }, + "pref.birthday": { + "message": "Wyślij informacje o urodzinach" + }, + "pref.calendaroptions": { + "message": "Opcje kalendarza" + }, + "pref.contactoptions": { + "message": "Opcje kontaktu" + }, + "pref.displayoverride": { + "message": "Zastąp nazwę wyświetlaną ciągiem “Imię“ + “Drugie imię”" + }, + "pref.generaloptions": { + "message": "Opcje ogólne" + }, + "pref.provision": { + "message": "Wymuś provisioning (wymagane przez Kerio)" + }, + "pref.seperator.comma": { + "message": "Przecinek" + }, + "pref.seperator.description": { + "message": "Separator pola adresu wielowierszowego." + }, + "pref.seperator.linebreak": { + "message": "Znak końca linii" + }, + "pref.synclimit.1month": { + "message": "z 4 tygodni" + }, + "pref.synclimit.2weeks": { + "message": "z 2 tygodni" + }, + "pref.synclimit.3month": { + "message": "z 3 miesięcy" + }, + "pref.synclimit.6month": { + "message": "z 6 miesięcy" + }, + "pref.synclimit.all": { + "message": "wszystko" + }, + "pref.synclimit.description": { + "message": "Okres synchronizacji: " + }, + "pref.usehttps": { + "message": "Użyj bezpiecznego połączenia (połącz przez https)" + }, + "recyclebin": { + "message": "Kosz" + }, + "servertype.auto": { + "message": "Automatyczna konfiguracja" + }, + "servertype.custom": { + "message": "Konfiguracja niestandardowa" + }, + "servertype.description.auto": { + "message": "Konfiguracja dla wielu serwerów ActiveSync może zostać odnaleziona poprzez podanie tylko adresu e-mail." + }, + "servertype.description.custom": { + "message": "Skonfiguruj konto, podając ręcznie adres serwera, z którym chcesz się połączyć." + }, + "servertype.description.office365": { + "message": "Konta połączone z Office 365 korzystają z nowoczesnego procesu uwierzytelniania o nazwie OAuth 2.0, który obsługuje również uwierzytelnianie wielopoziomowe (MFA)." + }, + "servertype.office365": { + "message": "Microsoft Office 365" + }, + "servertype.unlock": { + "message": "Kliknij dwukrotnie, aby odblokować wszystkie predefiniowane ustawienia serwera." + }, + "status.401": { + "message": "Nie można uwierzytelnić, sprawdź nazwę użytkownika i hasło (HTTP Error 401)." + }, + "status.403": { + "message": "Serwer odrzucił połączenie (zabronione) (błąd HTTP 403)." + }, + "status.404": { + "message": "Użytkownik nie znaleziony (błąd HTTP 404)." + }, + "status.449": { + "message": "Server requests provisioning (HTTP Error 449)." + }, + "status.500": { + "message": "Nieznany błąd serwera (błąd HTTP 500)." + }, + "status.503": { + "message": "Usługa niedostępna (błąd HTTP 503)." + }, + "status.BadItemSkipped": { + "message": "Błędny element pominięto: ##replace.1##" + }, + "status.FolderDelete.3": { + "message": "Nie można usunąć folderu systemowego (status 3)" + }, + "status.FolderDelete.4": { + "message": "Folder nie istnieje (status 4), ponowna synchronizacja" + }, + "status.FolderDelete.6": { + "message": "Nie można wykonać polecenia, wystąpił błąd na serwerze (status 6)" + }, + "status.FolderDelete.9": { + "message": "Nieprawidłowy klucz synchronizacji (status 9), ponowna synchronizacja" + }, + "status.FolderSync.9": { + "message": "Nieprawidłowy klucz synchronizacji (status 9), ponowna synchronizacja" + }, + "status.InvalidServerOptions": { + "message": "Serwer nie dostarcza informacji o obsługiwanych wersjach ActiveSync. Czy EAS jest zablokowany dla tego użytkownika lub tego klienta (TbSync)? Możesz spróbować ręcznie ustawić wersję ActiveSync." + }, + "status.OK": { + "message": "OK" + }, + "status.ServerRejectedRequest": { + "message": "Serwer EAS odrzucił ostatnie żądanie." + }, + "status.ServerRejectedSomeItems": { + "message": "Serwer EAS nie zaakceptował #replace.1## elementów." + }, + "status.Sync.12": { + "message": "Hierarchia folderów zmieniona (status 12), ponowna synchronizacja" + }, + "status.Sync.3": { + "message": "Nieprawidłowy klucz synchronizacji (status 3), ponowna synchronizacja" + }, + "status.Sync.4": { + "message": "Zniekształcone żądanie (status 4)" + }, + "status.Sync.5": { + "message": "Tymczasowe problemy z serwerem lub nieprawidłowy element (status 5)" + }, + "status.Sync.6": { + "message": "Nieprawidłowy element (status 6)" + }, + "status.Sync.8": { + "message": "Nie znaleziono obiektu (status 8)" + }, + "status.aborted": { + "message": "Nie zsynchronizowane" + }, + "status.disabled": { + "message": "Wyłączony" + }, + "status.empty-response": { + "message": "Serwer wysyła nieoczekiwaną pustą odpowiedź." + }, + "status.forbiddenCalendarItemInTasksFolder": { + "message": "Niedozwolony element kalendarza w folderze zadań (please resort)" + }, + "status.forbiddenTasksItemInCalendarFolder": { + "message": "Niedozwolony element zadania w folderze kalendarza (please resort)" + }, + "status.global.101": { + "message": "Żądanie zawiera WBXML, ale nie można go zdekodować do formatu XML (błąd EAS 101)." + }, + "status.global.102": { + "message": "Żądanie zawiera WBXML, ale nie można go zdekodować do formatu XML (błąd EAS 102)." + }, + "status.global.103": { + "message": "XML podany w żądaniu nie jest zgodny z wymaganiami protokołu (błąd EAS 103)." + }, + "status.global.110": { + "message": "Serwer zgłosił błąd wewnętrzny i nie powinniśmy natychmiast ponawiać próby. Automatyczna synchronizacja okresowa została wyłączona na 30 minut (błąd EAS 110)." + }, + "status.global.clientdenied": { + "message": "Serwer EAS zgłasza <##replace.2##> (status ##replace.1##) i nie zezwala TbSync na dostęp do Twojego konta." + }, + "status.httperror": { + "message": "Błąd komunikacji (status HTTP ##replace.1##)." + }, + "status.invalid": { + "message": "Niepoprawna odpowiedź serwera (śmieci)." + }, + "status.malformed-xml": { + "message": "Nie można przetworzyć XML. Sprawdź dziennik zdarzeń, aby uzyskać szczegóły." + }, + "status.modified": { + "message": "Zmiany lokalne" + }, + "status.network": { + "message": "Nie można połączyć z serwerem (##replace.1##)." + }, + "status.networkerror": { + "message": "Nie można połączyć z serwerem." + }, + "status.nosupportedeasversion": { + "message": "Serwer nie obsługuje ActiveSync v2.5 lub v14.0 (tylko ##replace.1##). TbSync nie będzie działać z tym serwerem ActiveSync." + }, + "status.notargets": { + "message": "Przerywam synchronizację, ponieważ nie można utworzyć celów synchronizacji." + }, + "status.notsupportedeasversion": { + "message": "Serwer nie wspiera wybranego ActiveSync v##replace.1## (tylko ##replace.2##)." + }, + "status.notsyncronized": { + "message": "Konto musi zostać zsynchronizowane, co najmniej jeden element nie jest zsynchronizowany." + }, + "status.nouserhost": { + "message": "Brak nazwy użytkownika i/lub serwera. Proszę podać te wartości." + }, + "status.pending": { + "message": "Oczekiwanie na synchronizację" + }, + "status.policy.2": { + "message": "Brak zasad dla tego klienta. Skontaktuj się z administratorem serwera lub wyłącz provisioning dla tego konta." + }, + "status.policy.3": { + "message": "Nieznana wartość PolicyType. Skontaktuj się z administratorem serwera lub wyłącz provisioning dla tego konta." + }, + "status.policy.4": { + "message": "Dane zasad na serwerze są uszkodzone (prawdopodobnie zmienione/sfałszowane). Skontaktuj się z administratorem serwera lub wyłącz provisioning dla tego konta." + }, + "status.policy.5": { + "message": "Klient potwierdza zły klucz zasad. Skontaktuj się z administratorem serwera lub wyłącz provisioning dla tego konta." + }, + "status.provision": { + "message": "Niepowodzenie provisioning ze statusem <##replace.1##>" + }, + "status.response-contains-no-data": { + "message": "Odpowiedź z serwera nie zawiera danych." + }, + "status.resync-loop": { + "message": "Wystąpił błąd, którego nie udało się naprawić poprzez ponowne zsynchronizowanie konta. Wyłącz konto i spróbuj ponownie. (Błąd: pętla resynchronizacji)" + }, + "status.security": { + "message": "Nie można nawiązać bezpiecznego połączenia. Czy używasz własnego podpisu lub w inny sposób niezaufanego certyfikatu bez importowania go do Thunderbirda? (##replace.1##)" + }, + "status.skipped": { + "message": "Jeszcze nie obsługiwane, pominięto" + }, + "status.syncing": { + "message": "Synchronizuję" + }, + "status.timeout": { + "message": "Przekroczony limit czasu połączenia." + }, + "status.wbxml-parse-error": { + "message": "Serwer wysyła nieczytelną odpowiedź." + }, + "status.wbxmlerror": { + "message": "Synchronizacja nie powiodła się. Serwer odpowiedział statusem <##replace.1##>." + }, + "status.wbxmlmissingfield": { + "message": "Naruszenie protokołu ActiveSync: W odpowiedzi serwera brakuje obowiązkowego pola <##replace.1##>." + }, + "syncstate.accountdone": { + "message": "Konto gotowe" + }, + "syncstate.done": { + "message": "Przygotowuję następny element do synchronizacji" + }, + "syncstate.eval.response.autodiscover": { + "message": "Przetwarzanie zaktualizowanych ustawień serwera" + }, + "syncstate.eval.response.deletefolder": { + "message": "Folder usunięty" + }, + "syncstate.eval.response.estimate": { + "message": "Przetwarzanie oszacowanych zmian" + }, + "syncstate.eval.response.folders": { + "message": "Przetwarzanie aktualizacji listy folderów" + }, + "syncstate.eval.response.localchanges": { + "message": "Przetwarzanie potwierdzenia lokalnych zmian" + }, + "syncstate.eval.response.localdeletes": { + "message": "Przetwarzanie potwierdzenia usunięcia lokalnego" + }, + "syncstate.eval.response.options": { + "message": "Przetwarzanie opcji serwera" + }, + "syncstate.eval.response.provision": { + "message": "Przetwarzanie provision" + }, + "syncstate.eval.response.remotechanges": { + "message": "Przetwarzanie zdalnych zmian" + }, + "syncstate.eval.response.revertlocalchanges": { + "message": "Wycofywanie zmian lokalnych" + }, + "syncstate.eval.response.setdeviceinfo": { + "message": "Wysyłanie informacji o urządzeniu" + }, + "syncstate.eval.response.synckey": { + "message": "Przetwarzanie SyncKey" + }, + "syncstate.prepare.request.autodiscover": { + "message": "Żądanie zaktualizowanych ustawień serwera" + }, + "syncstate.prepare.request.deletefolder": { + "message": "Przygotowanie do usunięcia folderu" + }, + "syncstate.prepare.request.estimate": { + "message": "Żądanie oszacowanych zmian" + }, + "syncstate.prepare.request.folders": { + "message": "Wysyłanie aktualizacji listy folderów" + }, + "syncstate.prepare.request.localchanges": { + "message": "Wysyłanie zmian lokalnych" + }, + "syncstate.prepare.request.localdeletes": { + "message": "Wysyłanie usuniętych lokalnie" + }, + "syncstate.prepare.request.options": { + "message": "Żądanie opcji serwera" + }, + "syncstate.prepare.request.provision": { + "message": "Żądanie provision" + }, + "syncstate.prepare.request.remotechanges": { + "message": "Żądanie zdalnych zmian" + }, + "syncstate.prepare.request.revertlocalchanges": { + "message": "Zbieranie zmian lokalnych" + }, + "syncstate.prepare.request.setdeviceinfo": { + "message": "Wysyłanie informacji o urządzeniu" + }, + "syncstate.prepare.request.synckey": { + "message": "Żądanie SyncKey" + }, + "syncstate.preparing": { + "message": "Przygotowuję następny element do synchronizacji" + }, + "syncstate.send.request.autodiscover": { + "message": "Oczekiwanie na zaktualizowane ustawienia serwera" + }, + "syncstate.send.request.deletefolder": { + "message": "Oczekiwanie na usunięcie folderu" + }, + "syncstate.send.request.estimate": { + "message": "Oczekiwanie na oszacowanie zmian" + }, + "syncstate.send.request.folders": { + "message": "Oczekiwanie na aktualizację listy folderów" + }, + "syncstate.send.request.localchanges": { + "message": "Oczekiwanie na potwierdzenie lokalnych zmian" + }, + "syncstate.send.request.localdeletes": { + "message": "Oczekiwanie na potwierdzenie usunięcia lokalnego" + }, + "syncstate.send.request.options": { + "message": "Oczekiwanie na opcje serwera" + }, + "syncstate.send.request.provision": { + "message": "Oczekiwanie na provision" + }, + "syncstate.send.request.remotechanges": { + "message": "Oczekiwanie na zdalne zmiany" + }, + "syncstate.send.request.revertlocalchanges": { + "message": "Oczekiwanie na najnowsze wersje" + }, + "syncstate.send.request.setdeviceinfo": { + "message": "Wysyłanie informacji o urządzeniu" + }, + "syncstate.send.request.synckey": { + "message": "Oczekiwanie na SyncKey" + }, + "syncstate.syncing": { + "message": "Zainicjuj synchronizację" + } +} diff -Nru eas4tbsync-4.11/_locales/pt_BR/messages.json eas4tbsync-4.17/_locales/pt_BR/messages.json --- eas4tbsync-4.11/_locales/pt_BR/messages.json 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/_locales/pt_BR/messages.json 2025-05-15 11:21:20.000000000 +0000 @@ -1,566 +1,566 @@ -{ - "abCard.Anniversary": { - "message": "Aniversário:" - }, - "abCard.AssistantName": { - "message": "Assistente:" - }, - "abCard.AssistantPhoneNumber": { - "message": "Telefone Assistente:" - }, - "abCard.Business2PhoneNumber": { - "message": "Telefone alternativo do trabalho:" - }, - "abCard.BusinessFaxNumber": { - "message": "Fax de trabalho:" - }, - "abCard.CarPhoneNumber": { - "message": "Telefone do carro:" - }, - "abCard.CompanyMainPhone": { - "message": "Telefone principal do trabalho:" - }, - "abCard.Email3Address": { - "message": "Email alternativo:" - }, - "abCard.Home2PhoneNumber": { - "message": "Telefone alternativo residencial:" - }, - "abCard.ManagerName": { - "message": "Gerenciar:" - }, - "abCard.MiddleName": { - "message": "Nome do meio:" - }, - "abCard.OtherAddress": { - "message": "Endereço:" - }, - "abCard.OtherCity": { - "message": "Cidade:" - }, - "abCard.OtherCountry": { - "message": "País:" - }, - "abCard.OtherState": { - "message": "Estado:" - }, - "abCard.OtherZip": { - "message": "CEP:" - }, - "abCard.RadioPhoneNumber": { - "message": "Telefone de rádio:" - }, - "abCard.Spouse": { - "message": "Esposa:" - }, - "abCard.header.eas": { - "message": "Outros campos (EAS)" - }, - "abCard.header.homenumbers": { - "message": "Números residenciais adicionais:" - }, - "abCard.header.messaging": { - "message": "Mensagens:" - }, - "abCard.header.otheraddress": { - "message": "Outro endereço (EAS)" - }, - "abCard.header.othernumbers": { - "message": "Números adicionais:" - }, - "abCard.header.people": { - "message": "Pessoas:" - }, - "abCard.header.worknumbers": { - "message": "Números de trabalho adicionais:" - }, - "acl.readonly": { - "message": "Acesso ao servidor somente leitura (reverter alterações locais)" - }, - "acl.readwrite": { - "message": "Ler e escrever no servidor" - }, - "add.description": { - "message": "Selecione uma das opções de configuração do servidor disponíveis e insira os detalhes solicitados." - }, - "add.name": { - "message": "Nome da conta:" - }, - "add.ok": { - "message": "Adicionar conta" - }, - "add.password": { - "message": "Senha:" - }, - "add.server": { - "message": "Configuração do servidor:" - }, - "add.shortdescription": { - "message": "Informações de conta" - }, - "add.title": { - "message": "Adicionando uma conta do Exchange ActiveSync ao TbSync" - }, - "add.url": { - "message": "Endereço do servidor:" - }, - "add.urldescription": { - "message": "Deve ser suficiente fornecer apenas o endereço básico do servidor (ex.: mail.yourserver.com). No entanto, também é possível fornecer a URL completa (ex.: https://mail.yourserver.com/Microsoft-Server-ActiveSync)." - }, - "add.user": { - "message": "Usuário:" - }, - "autocomplete.serverdirectory": { - "message": "servidor de diretório global" - }, - "autodiscover.Failed": { - "message": "Descoberta automática para usuário <##user##> falhou. As credenciais fornecidas estavam erradas ou seu provedor do ActiveSync tem um problema temporário ou não oferece suporte à descoberta automática." - }, - "autodiscover.NeedEmail": { - "message": "A descoberta automática precisa de um endereço de email válido" - }, - "autodiscover.Ok": { - "message": "Descoberta automática concluída com êxito, agora você pode verificar as configurações opcionais e estabelecer a conexão de sincronização." - }, - "autodiscover.Querying": { - "message": "Procurando por configurações..." - }, - "config.auto": { - "message": "Configuração do servidor ActiveSync (Descoberta Automática)" - }, - "config.custom": { - "message": "Configuração do servidor ActiveSync" - }, - "deletefolder.confirm": { - "message": "Você realmente deseja limpar permanentemente a pasta '##replace.1##' da lixeira?" - }, - "deletefolder.menuentry": { - "message": "Remover permanentemente a pasta '##replace.1##' da lixeira" - }, - "deletefolder.notallowed": { - "message": "Por favor, cancele a subscrição da pasta '##replace.1##' antes de tentar limpá-lo do lixo." - }, - "extensionDescription": { - "message": "Adiciona suporte para sincronizar contas do Exchange ActiveSync (contatos, tarefas e calendários) para o TbSync." - }, - "extensionName": { - "message": "Provedor Exchange ActiveSync" - }, - "helplink.BadItemSkipped": { - "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped" - }, - "helplink.global.clientdenied": { - "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F" - }, - "helplink.security": { - "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F" - }, - "manager.tabs.accountsettings": { - "message": "Configurações da conta" - }, - "manager.tabs.outOfOffice": { - "message": "Resposta automática" - }, - "manager.tabs.syncsettings": { - "message": "Opções" - }, - "newaccount.add_auto": { - "message": "Configurações de descoberta automática e adicionar conta" - }, - "newaccount.add_custom": { - "message": "Adicionar conta" - }, - "pref.AccountName": { - "message": "Nome da conta" - }, - "pref.ActiveSyncVersion": { - "message": "Versão do ActiveSync" - }, - "pref.DeviceId": { - "message": "ID Dispositivo ActiveSync" - }, - "pref.ServerName": { - "message": "Endereço do servidor" - }, - "pref.ServerNameDescription": { - "message": "ex. mail.yourserver.com" - }, - "pref.ShowTrashedFolders": { - "message": "Mostrar pastas encontradas na lixeira" - }, - "pref.UserName": { - "message": "Usuário" - }, - "pref.UserNameDescription": { - "message": "O nome do usuário geralmente é o endereço de e-mail da sua conta." - }, - "pref.autodetect": { - "message": "melhor disponível" - }, - "pref.birthday": { - "message": "Enviar informações de aniversário" - }, - "pref.calendaroptions": { - "message": "Opções de calendário" - }, - "pref.contactoptions": { - "message": "Opções de contato" - }, - "pref.displayoverride": { - "message": "Substituir nome de exibição com Nome + Segundo nome" - }, - "pref.generaloptions": { - "message": "Opções gerais" - }, - "pref.provision": { - "message": "Reforçar provisionamento (requiredo pelo Kerio)" - }, - "pref.seperator.comma": { - "message": "Vírgula" - }, - "pref.seperator.description": { - "message": "Separador para campo de endereço de múltiplas linhas." - }, - "pref.seperator.linebreak": { - "message": "Quebra de linha" - }, - "pref.synclimit.1month": { - "message": "a partir de 4 semanas atrás" - }, - "pref.synclimit.2weeks": { - "message": "a partir de 2 semanas atrás" - }, - "pref.synclimit.3month": { - "message": "a partir de 3 meses atrás" - }, - "pref.synclimit.6month": { - "message": "a partir de 6 meses atrás" - }, - "pref.synclimit.all": { - "message": "tudo" - }, - "pref.synclimit.description": { - "message": "Período de sincronização:" - }, - "pref.usehttps": { - "message": "Utilizar conexão segura (conectar via https)" - }, - "recyclebin": { - "message": "Lixeira" - }, - "servertype.auto": { - "message": "Configuração automática" - }, - "servertype.custom": { - "message": "Configuração personalizada" - }, - "servertype.description.auto": { - "message": "A configuração para muitos servidores do ActiveSync pode ser descoberta fornecendo apenas seu endereço de e-mail." - }, - "servertype.description.custom": { - "message": "Configure sua conta fornecendo manualmente o endereço do servidor que você deseja conectar." - }, - "servertype.description.office365": { - "message": "Contas conectadas ao Office 365 utilizam um processo de autenticação moderno chamado OAuth 2.0 que também suporta autenticação multi-Fator (MFA)." - }, - "servertype.office365": { - "message": "Microsoft Office 365" - }, - "servertype.unlock": { - "message": "Clique duas vezes para desbloquear todas as configurações do servidor predefinidas." - }, - "status.401": { - "message": "Não foi possível autenticar, verifique o nome de usuário e senha (HTTP Erro 401)." - }, - "status.403": { - "message": "Conexão rejeitada pelo servidor (proibido) (HTTP Erro 403)." - }, - "status.404": { - "message": "Usuário não encontrado (HTTP Erro 404)." - }, - "status.449": { - "message": "O servidor solicita o provisionamento (HTTP Erro 449)." - }, - "status.500": { - "message": "Erro de servidor desconhecido (HTTP Erro 500)." - }, - "status.503": { - "message": "Serviço indisponível (HTTP Erro 503)." - }, - "status.BadItemSkipped": { - "message": "Item inválido ignorado: ##replace.1##" - }, - "status.FolderDelete.3": { - "message": "Não é possível excluir uma pasta do sistema." - }, - "status.FolderDelete.4": { - "message": "?? Folder does not exist (status 4), resyncing ??" - }, - "status.FolderDelete.6": { - "message": "O comando não pôde ser concluído, ocorreu um erro no servidor." - }, - "status.FolderDelete.9": { - "message": "?? Invalid synchronization key (status 9), resyncing ??" - }, - "status.FolderSync.9": { - "message": "?? Invalid synchronization key (status 9), resyncing ??" - }, - "status.InvalidServerOptions": { - "message": "O servidor não fornece informações sobre as versões do ActiveSync com suporte. O EAS está bloqueado para este usuário ou esse cliente (TbSync)? Você pode tentar definir a versão do ActiveSync manualmente." - }, - "status.OK": { - "message": "OK" - }, - "status.ServerRejectedRequest": { - "message": "O servidor EAS rejeitou a última solicitação." - }, - "status.ServerRejectedSomeItems": { - "message": "O servidor EAS não aceitou ##replace.1## elementos." - }, - "status.Sync.12": { - "message": "?? Folder hierarchy changed (status 12), resyncing ??" - }, - "status.Sync.3": { - "message": "?? Invalid synchronization key (status 3), resyncing ??" - }, - "status.Sync.4": { - "message": "?? Malformed request (status 4) ??" - }, - "status.Sync.5": { - "message": "?? Temporary server issues or invalid item (status 5) ??" - }, - "status.Sync.6": { - "message": "?? Invalid item (status 6) ??" - }, - "status.Sync.8": { - "message": "?? Object not found (status 8) ??" - }, - "status.aborted": { - "message": "Não sincronizado" - }, - "status.disabled": { - "message": "Desativado" - }, - "status.empty-response": { - "message": "O servidor enviou uma resposta vazia inesperada." - }, - "status.forbiddenCalendarItemInTasksFolder": { - "message": "?? Forbidden calendar item in a task folder (please resort) ??" - }, - "status.forbiddenTasksItemInCalendarFolder": { - "message": "?? Forbidden task item in a calendar folder (please resort) ??" - }, - "status.global.101": { - "message": "A solicitação contém WBXML, mas não pôde ser decodificada em XML (Erro EAS 101)." - }, - "status.global.102": { - "message": "A solicitação contém WBXML, mas não pôde ser decodificada em XML (Erro EAS 102)." - }, - "status.global.103": { - "message": "O XML fornecido na solicitação não segue os requisitos do protocolo (Erro EAS 103)." - }, - "status.global.110": { - "message": "O servidor relatou um erro interno e não devemos tentar novamente imediatamente. A sincronização periódica automática foi desativada por 30 minutos (Erro 110 do EAS)." - }, - "status.global.clientdenied": { - "message": "O servidor EAS reporta <##replace.2##> (status ##replace.1##) e não permite que o TbSync acesse sua conta." - }, - "status.httperror": { - "message": "Erro de comunicação (HTTP status ##replace.1##)." - }, - "status.invalid": { - "message": "Resposta inválida do servidor (lixo)." - }, - "status.malformed-xml": { - "message": "Não foi possível analisar XML. Verifique o log de eventos para obter detalhes." - }, - "status.modified": { - "message": "Modificações locais" - }, - "status.network": { - "message": "Não foi possível conectar ao servidor (##replace.1##)." - }, - "status.networkerror": { - "message": "Não foi possível conectar ao servidor." - }, - "status.nosupportedeasversion": { - "message": "O servidor não suporta o ActiveSync v2.5 ou v14.0 (somente ##replace.1##). TbSync não funcionará com este servidor ActiveSync." - }, - "status.notargets": { - "message": "Anulando a sincronização, porque os destinos de sincronização não puderam ser criados." - }, - "status.notsupportedeasversion": { - "message": "O servidor não suporta o ActiveSync selecionado v##replace.1## (somente ##replace.2##)." - }, - "status.notsyncronized": { - "message": "A conta precisa ser sincronizada, pelo menos, um item está fora de sincronia." - }, - "status.nouserhost": { - "message": "Nome de usuário e/ou servidor ausente. Por favor, forneça esses valores." - }, - "status.pending": { - "message": "Esperando para ser sincronizado" - }, - "status.policy.2": { - "message": "Não há política para este cliente. Entre em contato com o administrador do servidor ou desabilite o provisionamento para essa conta." - }, - "status.policy.3": { - "message": "Valor de PolicyType desconhecido. Entre em contato com o administrador do servidor ou desabilite o provisionamento para essa conta." - }, - "status.policy.4": { - "message": "Os dados da política no servidor estão corrompidos (possivelmente adulterados). Entre em contato com o administrador do servidor ou desabilite o provisionamento para essa conta." - }, - "status.policy.5": { - "message": "O cliente está reconhecendo a chave de política incorreta. Entre em contato com o administrador do servidor ou desabilite o provisionamento para essa conta." - }, - "status.provision": { - "message": "O provisionamento falhou com o status <##replace.1##>" - }, - "status.response-contains-no-data": { - "message": "A resposta do servidor não contém dados." - }, - "status.resync-loop": { - "message": "Ocorreu um erro do qual não conseguimos recuperar ao reativar a conta. Por favor, desative a conta e tente novamente. (Erro: loop de ressincronização)" - }, - "status.security": { - "message": "Não foi possível estabelecer uma conexão segura. Você está usando um certificado autoassinado ou não confiável sem importá-lo para o Thunderbird? (##replace.1##)" - }, - "status.skipped": { - "message": "Ainda não suportado, ignorado" - }, - "status.syncing": { - "message": "Sincronizando" - }, - "status.timeout": { - "message": "Tempo limite de comunicação." - }, - "status.wbxml-parse-error": { - "message": "O servidor enviou uma resposta ilegível." - }, - "status.wbxmlerror": { - "message": "A sincronização falhou. O servidor respondeu com status <##replace.1##>." - }, - "status.wbxmlmissingfield": { - "message": "Violação do protocolo ActiveSync: o campo obrigatório <##replace.1##> está faltando na resposta do servidor." - }, - "syncstate.accountdone": { - "message": "Sincronização finalizada" - }, - "syncstate.done": { - "message": "Preparando o próximo item para sincronização" - }, - "syncstate.eval.response.autodiscover": { - "message": "Aguardando as configurações do servidor atualizadas" - }, - "syncstate.eval.response.deletefolder": { - "message": "Pasta excluída" - }, - "syncstate.eval.response.estimate": { - "message": "Processando a estimativa de alterações" - }, - "syncstate.eval.response.folders": { - "message": "Processando a atualização da lista de pastas" - }, - "syncstate.eval.response.localchanges": { - "message": "Processando reconhecimento de alterações locais" - }, - "syncstate.eval.response.localdeletes": { - "message": "Processando reconhecimento de exclusões locais" - }, - "syncstate.eval.response.options": { - "message": "Processando opções do servidor" - }, - "syncstate.eval.response.provision": { - "message": "Processando provisão" - }, - "syncstate.eval.response.remotechanges": { - "message": "Processando alterações remotas" - }, - "syncstate.eval.response.revertlocalchanges": { - "message": "Revertendo alterações locais" - }, - "syncstate.eval.response.setdeviceinfo": { - "message": "Enviando informações do dispositivo" - }, - "syncstate.eval.response.synckey": { - "message": "Processando SyncKey" - }, - "syncstate.prepare.request.autodiscover": { - "message": "Solicitando configurações do servidor atualizadas" - }, - "syncstate.prepare.request.deletefolder": { - "message": "Preparando-se para excluir pasta" - }, - "syncstate.prepare.request.estimate": { - "message": "Solicitando estimativa de alterações" - }, - "syncstate.prepare.request.folders": { - "message": "Enviando lista de pastas atualizadas" - }, - "syncstate.prepare.request.localchanges": { - "message": "Enviando alterações locais" - }, - "syncstate.prepare.request.localdeletes": { - "message": "Enviando exclusões locais" - }, - "syncstate.prepare.request.options": { - "message": "Solicitando opções do servidor" - }, - "syncstate.prepare.request.provision": { - "message": "Solicitando provisão" - }, - "syncstate.prepare.request.remotechanges": { - "message": "Solicitando alterações remotas" - }, - "syncstate.prepare.request.revertlocalchanges": { - "message": "Coletando alterações locais" - }, - "syncstate.prepare.request.setdeviceinfo": { - "message": "Enviando informações do dispositivo" - }, - "syncstate.prepare.request.synckey": { - "message": "Solicitando SyncKey" - }, - "syncstate.preparing": { - "message": "Preparando o próximo item para sincronização" - }, - "syncstate.send.request.autodiscover": { - "message": "Aguardando as configurações do servidor atualizadas" - }, - "syncstate.send.request.deletefolder": { - "message": "Aguardando a pasta ser excluída" - }, - "syncstate.send.request.estimate": { - "message": "Aguardando a estimativa de alterações" - }, - "syncstate.send.request.folders": { - "message": "Aguardando a atualização da lista de pastas" - }, - "syncstate.send.request.localchanges": { - "message": "Aguardando confirmação de alterações locais" - }, - "syncstate.send.request.localdeletes": { - "message": "Aguardando o reconhecimento de exclusões locais" - }, - "syncstate.send.request.options": { - "message": "Aguardando por opções do servidor" - }, - "syncstate.send.request.provision": { - "message": "Agurdandando provisão" - }, - "syncstate.send.request.remotechanges": { - "message": "Aguardando alterações remotas" - }, - "syncstate.send.request.revertlocalchanges": { - "message": "Aguardando as versões mais recentes" - }, - "syncstate.send.request.setdeviceinfo": { - "message": "Enviando informações do dispositivo" - }, - "syncstate.send.request.synckey": { - "message": "Esperando SyncKey" - }, - "syncstate.syncing": { - "message": "Inicializar sincronização" - } -} +{ + "abCard.Anniversary": { + "message": "Aniversário:" + }, + "abCard.AssistantName": { + "message": "Assistente:" + }, + "abCard.AssistantPhoneNumber": { + "message": "Telefone Assistente:" + }, + "abCard.Business2PhoneNumber": { + "message": "Telefone alternativo do trabalho:" + }, + "abCard.BusinessFaxNumber": { + "message": "Fax de trabalho:" + }, + "abCard.CarPhoneNumber": { + "message": "Telefone do carro:" + }, + "abCard.CompanyMainPhone": { + "message": "Telefone principal do trabalho:" + }, + "abCard.Email3Address": { + "message": "Email alternativo:" + }, + "abCard.Home2PhoneNumber": { + "message": "Telefone alternativo residencial:" + }, + "abCard.ManagerName": { + "message": "Gerenciar:" + }, + "abCard.MiddleName": { + "message": "Nome do meio:" + }, + "abCard.OtherAddress": { + "message": "Endereço:" + }, + "abCard.OtherCity": { + "message": "Cidade:" + }, + "abCard.OtherCountry": { + "message": "País:" + }, + "abCard.OtherState": { + "message": "Estado:" + }, + "abCard.OtherZip": { + "message": "CEP:" + }, + "abCard.RadioPhoneNumber": { + "message": "Telefone de rádio:" + }, + "abCard.Spouse": { + "message": "Esposa:" + }, + "abCard.header.eas": { + "message": "Outros campos (EAS)" + }, + "abCard.header.homenumbers": { + "message": "Números residenciais adicionais:" + }, + "abCard.header.messaging": { + "message": "Mensagens:" + }, + "abCard.header.otheraddress": { + "message": "Outro endereço (EAS)" + }, + "abCard.header.othernumbers": { + "message": "Números adicionais:" + }, + "abCard.header.people": { + "message": "Pessoas:" + }, + "abCard.header.worknumbers": { + "message": "Números de trabalho adicionais:" + }, + "acl.readonly": { + "message": "Acesso ao servidor somente leitura (reverter alterações locais)" + }, + "acl.readwrite": { + "message": "Ler e escrever no servidor" + }, + "add.description": { + "message": "Selecione uma das opções de configuração do servidor disponíveis e insira os detalhes solicitados." + }, + "add.name": { + "message": "Nome da conta:" + }, + "add.ok": { + "message": "Adicionar conta" + }, + "add.password": { + "message": "Senha:" + }, + "add.server": { + "message": "Configuração do servidor:" + }, + "add.shortdescription": { + "message": "Informações de conta" + }, + "add.title": { + "message": "Adicionando uma conta do Exchange ActiveSync ao TbSync" + }, + "add.url": { + "message": "Endereço do servidor:" + }, + "add.urldescription": { + "message": "Deve ser suficiente fornecer apenas o endereço básico do servidor (ex.: mail.yourserver.com). No entanto, também é possível fornecer a URL completa (ex.: https://mail.yourserver.com/Microsoft-Server-ActiveSync)." + }, + "add.user": { + "message": "Usuário:" + }, + "autocomplete.serverdirectory": { + "message": "servidor de diretório global" + }, + "autodiscover.Failed": { + "message": "Descoberta automática para usuário <##user##> falhou. As credenciais fornecidas estavam erradas ou seu provedor do ActiveSync tem um problema temporário ou não oferece suporte à descoberta automática." + }, + "autodiscover.NeedEmail": { + "message": "A descoberta automática precisa de um endereço de email válido" + }, + "autodiscover.Ok": { + "message": "Descoberta automática concluída com êxito, agora você pode verificar as configurações opcionais e estabelecer a conexão de sincronização." + }, + "autodiscover.Querying": { + "message": "Procurando por configurações..." + }, + "config.auto": { + "message": "Configuração do servidor ActiveSync (Descoberta Automática)" + }, + "config.custom": { + "message": "Configuração do servidor ActiveSync" + }, + "deletefolder.confirm": { + "message": "Você realmente deseja limpar permanentemente a pasta '##replace.1##' da lixeira?" + }, + "deletefolder.menuentry": { + "message": "Remover permanentemente a pasta '##replace.1##' da lixeira" + }, + "deletefolder.notallowed": { + "message": "Por favor, cancele a subscrição da pasta '##replace.1##' antes de tentar limpá-lo do lixo." + }, + "extensionDescription": { + "message": "Adiciona suporte para sincronizar contas do Exchange ActiveSync (contatos, tarefas e calendários) para o TbSync." + }, + "extensionName": { + "message": "Provedor Exchange ActiveSync" + }, + "helplink.BadItemSkipped": { + "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped" + }, + "helplink.global.clientdenied": { + "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F" + }, + "helplink.security": { + "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F" + }, + "manager.tabs.accountsettings": { + "message": "Configurações da conta" + }, + "manager.tabs.outOfOffice": { + "message": "Resposta automática" + }, + "manager.tabs.syncsettings": { + "message": "Opções" + }, + "newaccount.add_auto": { + "message": "Configurações de descoberta automática e adicionar conta" + }, + "newaccount.add_custom": { + "message": "Adicionar conta" + }, + "pref.AccountName": { + "message": "Nome da conta" + }, + "pref.ActiveSyncVersion": { + "message": "Versão do ActiveSync" + }, + "pref.DeviceId": { + "message": "ID Dispositivo ActiveSync" + }, + "pref.ServerName": { + "message": "Endereço do servidor" + }, + "pref.ServerNameDescription": { + "message": "ex. mail.yourserver.com" + }, + "pref.ShowTrashedFolders": { + "message": "Mostrar pastas encontradas na lixeira" + }, + "pref.UserName": { + "message": "Usuário" + }, + "pref.UserNameDescription": { + "message": "O nome do usuário geralmente é o endereço de e-mail da sua conta." + }, + "pref.autodetect": { + "message": "melhor disponível" + }, + "pref.birthday": { + "message": "Enviar informações de aniversário" + }, + "pref.calendaroptions": { + "message": "Opções de calendário" + }, + "pref.contactoptions": { + "message": "Opções de contato" + }, + "pref.displayoverride": { + "message": "Substituir nome de exibição com Nome + Segundo nome" + }, + "pref.generaloptions": { + "message": "Opções gerais" + }, + "pref.provision": { + "message": "Reforçar provisionamento (requiredo pelo Kerio)" + }, + "pref.seperator.comma": { + "message": "Vírgula" + }, + "pref.seperator.description": { + "message": "Separador para campo de endereço de múltiplas linhas." + }, + "pref.seperator.linebreak": { + "message": "Quebra de linha" + }, + "pref.synclimit.1month": { + "message": "a partir de 4 semanas atrás" + }, + "pref.synclimit.2weeks": { + "message": "a partir de 2 semanas atrás" + }, + "pref.synclimit.3month": { + "message": "a partir de 3 meses atrás" + }, + "pref.synclimit.6month": { + "message": "a partir de 6 meses atrás" + }, + "pref.synclimit.all": { + "message": "tudo" + }, + "pref.synclimit.description": { + "message": "Período de sincronização:" + }, + "pref.usehttps": { + "message": "Utilizar conexão segura (conectar via https)" + }, + "recyclebin": { + "message": "Lixeira" + }, + "servertype.auto": { + "message": "Configuração automática" + }, + "servertype.custom": { + "message": "Configuração personalizada" + }, + "servertype.description.auto": { + "message": "A configuração para muitos servidores do ActiveSync pode ser descoberta fornecendo apenas seu endereço de e-mail." + }, + "servertype.description.custom": { + "message": "Configure sua conta fornecendo manualmente o endereço do servidor que você deseja conectar." + }, + "servertype.description.office365": { + "message": "Contas conectadas ao Office 365 utilizam um processo de autenticação moderno chamado OAuth 2.0 que também suporta autenticação multi-Fator (MFA)." + }, + "servertype.office365": { + "message": "Microsoft Office 365" + }, + "servertype.unlock": { + "message": "Clique duas vezes para desbloquear todas as configurações do servidor predefinidas." + }, + "status.401": { + "message": "Não foi possível autenticar, verifique o nome de usuário e senha (HTTP Erro 401)." + }, + "status.403": { + "message": "Conexão rejeitada pelo servidor (proibido) (HTTP Erro 403)." + }, + "status.404": { + "message": "Usuário não encontrado (HTTP Erro 404)." + }, + "status.449": { + "message": "O servidor solicita o provisionamento (HTTP Erro 449)." + }, + "status.500": { + "message": "Erro de servidor desconhecido (HTTP Erro 500)." + }, + "status.503": { + "message": "Serviço indisponível (HTTP Erro 503)." + }, + "status.BadItemSkipped": { + "message": "Item inválido ignorado: ##replace.1##" + }, + "status.FolderDelete.3": { + "message": "Não é possível excluir uma pasta do sistema." + }, + "status.FolderDelete.4": { + "message": "?? Folder does not exist (status 4), resyncing ??" + }, + "status.FolderDelete.6": { + "message": "O comando não pôde ser concluído, ocorreu um erro no servidor." + }, + "status.FolderDelete.9": { + "message": "?? Invalid synchronization key (status 9), resyncing ??" + }, + "status.FolderSync.9": { + "message": "?? Invalid synchronization key (status 9), resyncing ??" + }, + "status.InvalidServerOptions": { + "message": "O servidor não fornece informações sobre as versões do ActiveSync com suporte. O EAS está bloqueado para este usuário ou esse cliente (TbSync)? Você pode tentar definir a versão do ActiveSync manualmente." + }, + "status.OK": { + "message": "OK" + }, + "status.ServerRejectedRequest": { + "message": "O servidor EAS rejeitou a última solicitação." + }, + "status.ServerRejectedSomeItems": { + "message": "O servidor EAS não aceitou ##replace.1## elementos." + }, + "status.Sync.12": { + "message": "?? Folder hierarchy changed (status 12), resyncing ??" + }, + "status.Sync.3": { + "message": "?? Invalid synchronization key (status 3), resyncing ??" + }, + "status.Sync.4": { + "message": "?? Malformed request (status 4) ??" + }, + "status.Sync.5": { + "message": "?? Temporary server issues or invalid item (status 5) ??" + }, + "status.Sync.6": { + "message": "?? Invalid item (status 6) ??" + }, + "status.Sync.8": { + "message": "?? Object not found (status 8) ??" + }, + "status.aborted": { + "message": "Não sincronizado" + }, + "status.disabled": { + "message": "Desativado" + }, + "status.empty-response": { + "message": "O servidor enviou uma resposta vazia inesperada." + }, + "status.forbiddenCalendarItemInTasksFolder": { + "message": "?? Forbidden calendar item in a task folder (please resort) ??" + }, + "status.forbiddenTasksItemInCalendarFolder": { + "message": "?? Forbidden task item in a calendar folder (please resort) ??" + }, + "status.global.101": { + "message": "A solicitação contém WBXML, mas não pôde ser decodificada em XML (Erro EAS 101)." + }, + "status.global.102": { + "message": "A solicitação contém WBXML, mas não pôde ser decodificada em XML (Erro EAS 102)." + }, + "status.global.103": { + "message": "O XML fornecido na solicitação não segue os requisitos do protocolo (Erro EAS 103)." + }, + "status.global.110": { + "message": "O servidor relatou um erro interno e não devemos tentar novamente imediatamente. A sincronização periódica automática foi desativada por 30 minutos (Erro 110 do EAS)." + }, + "status.global.clientdenied": { + "message": "O servidor EAS reporta <##replace.2##> (status ##replace.1##) e não permite que o TbSync acesse sua conta." + }, + "status.httperror": { + "message": "Erro de comunicação (HTTP status ##replace.1##)." + }, + "status.invalid": { + "message": "Resposta inválida do servidor (lixo)." + }, + "status.malformed-xml": { + "message": "Não foi possível analisar XML. Verifique o log de eventos para obter detalhes." + }, + "status.modified": { + "message": "Modificações locais" + }, + "status.network": { + "message": "Não foi possível conectar ao servidor (##replace.1##)." + }, + "status.networkerror": { + "message": "Não foi possível conectar ao servidor." + }, + "status.nosupportedeasversion": { + "message": "O servidor não suporta o ActiveSync v2.5 ou v14.0 (somente ##replace.1##). TbSync não funcionará com este servidor ActiveSync." + }, + "status.notargets": { + "message": "Anulando a sincronização, porque os destinos de sincronização não puderam ser criados." + }, + "status.notsupportedeasversion": { + "message": "O servidor não suporta o ActiveSync selecionado v##replace.1## (somente ##replace.2##)." + }, + "status.notsyncronized": { + "message": "A conta precisa ser sincronizada, pelo menos, um item está fora de sincronia." + }, + "status.nouserhost": { + "message": "Nome de usuário e/ou servidor ausente. Por favor, forneça esses valores." + }, + "status.pending": { + "message": "Esperando para ser sincronizado" + }, + "status.policy.2": { + "message": "Não há política para este cliente. Entre em contato com o administrador do servidor ou desabilite o provisionamento para essa conta." + }, + "status.policy.3": { + "message": "Valor de PolicyType desconhecido. Entre em contato com o administrador do servidor ou desabilite o provisionamento para essa conta." + }, + "status.policy.4": { + "message": "Os dados da política no servidor estão corrompidos (possivelmente adulterados). Entre em contato com o administrador do servidor ou desabilite o provisionamento para essa conta." + }, + "status.policy.5": { + "message": "O cliente está reconhecendo a chave de política incorreta. Entre em contato com o administrador do servidor ou desabilite o provisionamento para essa conta." + }, + "status.provision": { + "message": "O provisionamento falhou com o status <##replace.1##>" + }, + "status.response-contains-no-data": { + "message": "A resposta do servidor não contém dados." + }, + "status.resync-loop": { + "message": "Ocorreu um erro do qual não conseguimos recuperar ao reativar a conta. Por favor, desative a conta e tente novamente. (Erro: loop de ressincronização)" + }, + "status.security": { + "message": "Não foi possível estabelecer uma conexão segura. Você está usando um certificado autoassinado ou não confiável sem importá-lo para o Thunderbird? (##replace.1##)" + }, + "status.skipped": { + "message": "Ainda não suportado, ignorado" + }, + "status.syncing": { + "message": "Sincronizando" + }, + "status.timeout": { + "message": "Tempo limite de comunicação." + }, + "status.wbxml-parse-error": { + "message": "O servidor enviou uma resposta ilegível." + }, + "status.wbxmlerror": { + "message": "A sincronização falhou. O servidor respondeu com status <##replace.1##>." + }, + "status.wbxmlmissingfield": { + "message": "Violação do protocolo ActiveSync: o campo obrigatório <##replace.1##> está faltando na resposta do servidor." + }, + "syncstate.accountdone": { + "message": "Sincronização finalizada" + }, + "syncstate.done": { + "message": "Preparando o próximo item para sincronização" + }, + "syncstate.eval.response.autodiscover": { + "message": "Aguardando as configurações do servidor atualizadas" + }, + "syncstate.eval.response.deletefolder": { + "message": "Pasta excluída" + }, + "syncstate.eval.response.estimate": { + "message": "Processando a estimativa de alterações" + }, + "syncstate.eval.response.folders": { + "message": "Processando a atualização da lista de pastas" + }, + "syncstate.eval.response.localchanges": { + "message": "Processando reconhecimento de alterações locais" + }, + "syncstate.eval.response.localdeletes": { + "message": "Processando reconhecimento de exclusões locais" + }, + "syncstate.eval.response.options": { + "message": "Processando opções do servidor" + }, + "syncstate.eval.response.provision": { + "message": "Processando provisão" + }, + "syncstate.eval.response.remotechanges": { + "message": "Processando alterações remotas" + }, + "syncstate.eval.response.revertlocalchanges": { + "message": "Revertendo alterações locais" + }, + "syncstate.eval.response.setdeviceinfo": { + "message": "Enviando informações do dispositivo" + }, + "syncstate.eval.response.synckey": { + "message": "Processando SyncKey" + }, + "syncstate.prepare.request.autodiscover": { + "message": "Solicitando configurações do servidor atualizadas" + }, + "syncstate.prepare.request.deletefolder": { + "message": "Preparando-se para excluir pasta" + }, + "syncstate.prepare.request.estimate": { + "message": "Solicitando estimativa de alterações" + }, + "syncstate.prepare.request.folders": { + "message": "Enviando lista de pastas atualizadas" + }, + "syncstate.prepare.request.localchanges": { + "message": "Enviando alterações locais" + }, + "syncstate.prepare.request.localdeletes": { + "message": "Enviando exclusões locais" + }, + "syncstate.prepare.request.options": { + "message": "Solicitando opções do servidor" + }, + "syncstate.prepare.request.provision": { + "message": "Solicitando provisão" + }, + "syncstate.prepare.request.remotechanges": { + "message": "Solicitando alterações remotas" + }, + "syncstate.prepare.request.revertlocalchanges": { + "message": "Coletando alterações locais" + }, + "syncstate.prepare.request.setdeviceinfo": { + "message": "Enviando informações do dispositivo" + }, + "syncstate.prepare.request.synckey": { + "message": "Solicitando SyncKey" + }, + "syncstate.preparing": { + "message": "Preparando o próximo item para sincronização" + }, + "syncstate.send.request.autodiscover": { + "message": "Aguardando as configurações do servidor atualizadas" + }, + "syncstate.send.request.deletefolder": { + "message": "Aguardando a pasta ser excluída" + }, + "syncstate.send.request.estimate": { + "message": "Aguardando a estimativa de alterações" + }, + "syncstate.send.request.folders": { + "message": "Aguardando a atualização da lista de pastas" + }, + "syncstate.send.request.localchanges": { + "message": "Aguardando confirmação de alterações locais" + }, + "syncstate.send.request.localdeletes": { + "message": "Aguardando o reconhecimento de exclusões locais" + }, + "syncstate.send.request.options": { + "message": "Aguardando por opções do servidor" + }, + "syncstate.send.request.provision": { + "message": "Agurdandando provisão" + }, + "syncstate.send.request.remotechanges": { + "message": "Aguardando alterações remotas" + }, + "syncstate.send.request.revertlocalchanges": { + "message": "Aguardando as versões mais recentes" + }, + "syncstate.send.request.setdeviceinfo": { + "message": "Enviando informações do dispositivo" + }, + "syncstate.send.request.synckey": { + "message": "Esperando SyncKey" + }, + "syncstate.syncing": { + "message": "Inicializar sincronização" + } +} diff -Nru eas4tbsync-4.11/_locales/ro/messages.json eas4tbsync-4.17/_locales/ro/messages.json --- eas4tbsync-4.11/_locales/ro/messages.json 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/_locales/ro/messages.json 2025-05-15 11:21:20.000000000 +0000 @@ -1,566 +1,566 @@ -{ - "abCard.Anniversary": { - "message": "Anniversary:" - }, - "abCard.AssistantName": { - "message": "Assistant:" - }, - "abCard.AssistantPhoneNumber": { - "message": "Assistant Phone:" - }, - "abCard.Business2PhoneNumber": { - "message": "Work Alternative Phone:" - }, - "abCard.BusinessFaxNumber": { - "message": "Work Fax:" - }, - "abCard.CarPhoneNumber": { - "message": "Car Phone:" - }, - "abCard.CompanyMainPhone": { - "message": "Work Main Phone:" - }, - "abCard.Email3Address": { - "message": "Alternative Email:" - }, - "abCard.Home2PhoneNumber": { - "message": "Home Alternative Phone:" - }, - "abCard.ManagerName": { - "message": "Manager:" - }, - "abCard.MiddleName": { - "message": "Middle name:" - }, - "abCard.OtherAddress": { - "message": "Address:" - }, - "abCard.OtherCity": { - "message": "City:" - }, - "abCard.OtherCountry": { - "message": "Country:" - }, - "abCard.OtherState": { - "message": "State:" - }, - "abCard.OtherZip": { - "message": "ZIP Code:" - }, - "abCard.RadioPhoneNumber": { - "message": "Radio Phone:" - }, - "abCard.Spouse": { - "message": "Spouse:" - }, - "abCard.header.eas": { - "message": "Other Fields (EAS)" - }, - "abCard.header.homenumbers": { - "message": "Additional home numbers:" - }, - "abCard.header.messaging": { - "message": "Messaging:" - }, - "abCard.header.otheraddress": { - "message": "Other Address (EAS)" - }, - "abCard.header.othernumbers": { - "message": "Additional numbers:" - }, - "abCard.header.people": { - "message": "People:" - }, - "abCard.header.worknumbers": { - "message": "Additional work numbers:" - }, - "acl.readonly": { - "message": "Read-only server access (revert local changes)" - }, - "acl.readwrite": { - "message": "Read from and write to server" - }, - "add.description": { - "message": "Please select one of the available server configuration options and enter the requested details. " - }, - "add.name": { - "message": "Account name:" - }, - "add.ok": { - "message": "Add account" - }, - "add.password": { - "message": "Password:" - }, - "add.server": { - "message": "Server configuration:" - }, - "add.shortdescription": { - "message": "Account information" - }, - "add.title": { - "message": "Adding an Exchange ActiveSync account to TbSync" - }, - "add.url": { - "message": "Server address:" - }, - "add.urldescription": { - "message": "It should be sufficient to provide just the basic server address (e.g.: mail.yourserver.com). However, it is also possible to provide the full URL (e.g.: https://mail.yourserver.com/Microsoft-Server-ActiveSync)." - }, - "add.user": { - "message": "User name (email address):" - }, - "autocomplete.serverdirectory": { - "message": "global server directory" - }, - "autodiscover.Failed": { - "message": "Autodiscover for user <##user##> failed. Either the provided credentials were wrong or your ActiveSync provider has a temporary issue, or does not support Autodiscover." - }, - "autodiscover.NeedEmail": { - "message": "Autodiscover needs a valid email address as user name." - }, - "autodiscover.Ok": { - "message": "Autodiscover completed successfully, you can now check the optional settings and establish the synchronization connection." - }, - "autodiscover.Querying": { - "message": "Searching for settings…" - }, - "config.auto": { - "message": "ActiveSync server configuration (Autodiscover)" - }, - "config.custom": { - "message": "ActiveSync server configuration" - }, - "deletefolder.confirm": { - "message": "Do you really want to PERMANENTLY PURGE folder “##replace.1##” from trash?" - }, - "deletefolder.menuentry": { - "message": "Permanently purge folder “##replace.1##” from trash" - }, - "deletefolder.notallowed": { - "message": "Please unsubscribe folder “##replace.1##” before trying to purge it from trash." - }, - "extensionDescription": { - "message": "Add sync support for Exchange ActiveSync accounts to TbSync (contacts, tasks and calendars)." - }, - "extensionName": { - "message": "Provider for Exchange ActiveSync" - }, - "helplink.BadItemSkipped": { - "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped" - }, - "helplink.global.clientdenied": { - "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F" - }, - "helplink.security": { - "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F" - }, - "manager.tabs.accountsettings": { - "message": "Account settings" - }, - "manager.tabs.outOfOffice": { - "message": "Auto responder" - }, - "manager.tabs.syncsettings": { - "message": "Options" - }, - "newaccount.add_auto": { - "message": "Autodiscover settings and add account" - }, - "newaccount.add_custom": { - "message": "Add account" - }, - "pref.AccountName": { - "message": "Description" - }, - "pref.ActiveSyncVersion": { - "message": "ActiveSync version" - }, - "pref.DeviceId": { - "message": "ActiveSync device ID" - }, - "pref.ServerName": { - "message": "Server address" - }, - "pref.ServerNameDescription": { - "message": "e.g. mail.yourserver.com" - }, - "pref.ShowTrashedFolders": { - "message": "Show folders found in trash" - }, - "pref.UserName": { - "message": "User name" - }, - "pref.UserNameDescription": { - "message": "User name is usually the email address of your account." - }, - "pref.autodetect": { - "message": "best available" - }, - "pref.birthday": { - "message": "Send birthday information" - }, - "pref.calendaroptions": { - "message": "Calendar options" - }, - "pref.contactoptions": { - "message": "Contact options" - }, - "pref.displayoverride": { - "message": "Override Display Name with “First Name” + “Second Name”" - }, - "pref.generaloptions": { - "message": "General options" - }, - "pref.provision": { - "message": "Enforce provisioning (required by Kerio)" - }, - "pref.seperator.comma": { - "message": "Comma" - }, - "pref.seperator.description": { - "message": "Separator for multiline address field." - }, - "pref.seperator.linebreak": { - "message": "Line break" - }, - "pref.synclimit.1month": { - "message": "from 4 weeks ago" - }, - "pref.synclimit.2weeks": { - "message": "from 2 weeks ago" - }, - "pref.synclimit.3month": { - "message": "from 3 months ago" - }, - "pref.synclimit.6month": { - "message": "from 6 months ago" - }, - "pref.synclimit.all": { - "message": "everything" - }, - "pref.synclimit.description": { - "message": "Synchronization period: " - }, - "pref.usehttps": { - "message": "Use secure connection (connect via https)" - }, - "recyclebin": { - "message": "Trash" - }, - "servertype.auto": { - "message": "Automatic configuration" - }, - "servertype.custom": { - "message": "Custom configuration" - }, - "servertype.description.auto": { - "message": "The configuration for many ActiveSync servers can be discovered by providing just your email address." - }, - "servertype.description.custom": { - "message": "Setup your account by manually providing the address of the server you want to connect." - }, - "servertype.description.office365": { - "message": "Accounts connected to Office 365 use a modern authentication process called OAuth 2.0 which also supports Multi-Factor-Authentication (MFA)." - }, - "servertype.office365": { - "message": "Microsoft Office 365" - }, - "servertype.unlock": { - "message": "Double click to unlock all predefined server settings." - }, - "status.401": { - "message": "Could not authenticate, check username and password (HTTP Error 401)." - }, - "status.403": { - "message": "Server rejected connection (forbidden) (HTTP Error 403)." - }, - "status.404": { - "message": "User not found (HTTP Error 404)." - }, - "status.449": { - "message": "Server requests provisioning (HTTP Error 449)." - }, - "status.500": { - "message": "Unknown Server Error (HTTP Error 500)." - }, - "status.503": { - "message": "Service unavailable (HTTP Error 503)." - }, - "status.BadItemSkipped": { - "message": "Bad Item Skipped: ##replace.1##" - }, - "status.FolderDelete.3": { - "message": "Cannot delete a system folder (status 3)" - }, - "status.FolderDelete.4": { - "message": "Folder does not exist (status 4), resyncing" - }, - "status.FolderDelete.6": { - "message": "Command could not be completed, an error occurred on the server (status 6)" - }, - "status.FolderDelete.9": { - "message": "Invalid synchronization key (status 9), resyncing" - }, - "status.FolderSync.9": { - "message": "Invalid synchronization key (status 9), resyncing" - }, - "status.InvalidServerOptions": { - "message": "The server does not provide information about the supported ActiveSync versions. Is EAS blocked for this user or this client (TbSync)? You could try to set the ActiveSync version manually." - }, - "status.OK": { - "message": "OK" - }, - "status.ServerRejectedRequest": { - "message": "The EAS Server rejected the last request." - }, - "status.ServerRejectedSomeItems": { - "message": "The EAS server did not accept ##replace.1## elements." - }, - "status.Sync.12": { - "message": "Folder hierarchy changed (status 12), resyncing" - }, - "status.Sync.3": { - "message": "Invalid synchronization key (status 3), resyncing" - }, - "status.Sync.4": { - "message": "Malformed request (status 4)" - }, - "status.Sync.5": { - "message": "Temporary server issues or invalid item (status 5)" - }, - "status.Sync.6": { - "message": "Invalid item (status 6)" - }, - "status.Sync.8": { - "message": "Object not found (status 8)" - }, - "status.aborted": { - "message": "Not synchronized" - }, - "status.disabled": { - "message": "Disabled" - }, - "status.empty-response": { - "message": "Server sends unexpected empty response." - }, - "status.forbiddenCalendarItemInTasksFolder": { - "message": "Forbidden calendar item in a task folder (please resort)" - }, - "status.forbiddenTasksItemInCalendarFolder": { - "message": "Forbidden task item in a calendar folder (please resort)" - }, - "status.global.101": { - "message": "The request contains WBXML but it could not be decoded into XML (EAS Error 101)." - }, - "status.global.102": { - "message": "The request contains WBXML but it could not be decoded into XML (EAS Error 102)." - }, - "status.global.103": { - "message": "The XML provided in the request does not follow the protocol requirements (EAS Error 103)." - }, - "status.global.110": { - "message": "The server reported an internal error and we should not retry immediately. Automatic periodic sync has been disabled for 30 minutes (EAS Error 110)." - }, - "status.global.clientdenied": { - "message": "The EAS server reports <##replace.2##> (status ##replace.1##) and does not allow TbSync to access your account." - }, - "status.httperror": { - "message": "Communication error (HTTP status ##replace.1##)." - }, - "status.invalid": { - "message": "Invalid server response (junk)." - }, - "status.malformed-xml": { - "message": "Could not parse XML. Check event log for details." - }, - "status.modified": { - "message": "Local modifications" - }, - "status.network": { - "message": "Could not connect to server (##replace.1##)." - }, - "status.networkerror": { - "message": "Could not connect to server." - }, - "status.nosupportedeasversion": { - "message": "Server does not support ActiveSync v2.5 or v14.0 (only ##replace.1##). TbSync will not work with this ActiveSync server." - }, - "status.notargets": { - "message": "Aborting Sync, because sync targets could not be created." - }, - "status.notsupportedeasversion": { - "message": "Server does not support selected ActiveSync v##replace.1## (only ##replace.2##)." - }, - "status.notsyncronized": { - "message": "Account needs to be synchronized, at least one item is out of sync." - }, - "status.nouserhost": { - "message": "Missing username and/or server. Please provide those values." - }, - "status.pending": { - "message": "Waiting to be synchronized" - }, - "status.policy.2": { - "message": "There is no policy for this client. Contact your server administrator or disable provisioning for this account." - }, - "status.policy.3": { - "message": "Unknown PolicyType value. Contact your server administrator or disable provisioning for this account." - }, - "status.policy.4": { - "message": "The policy data on the server is corrupted (possibly tampered with). Contact your server administrator or disable provisioning for this account." - }, - "status.policy.5": { - "message": "The client is acknowledging the wrong policy key. Contact your server administrator or disable provisioning for this account." - }, - "status.provision": { - "message": "Provisioning failed with status <##replace.1##>" - }, - "status.response-contains-no-data": { - "message": "Response from the server contains no data." - }, - "status.resync-loop": { - "message": "There was an error from which we could not recover by resyncing the account. Please disable the account and try again. (Error: resync loop)" - }, - "status.security": { - "message": "Could not establish a secure connection. Are you using a self-signed or otherwise untrusted certificate without importing it into Thunderbird? (##replace.1##)" - }, - "status.skipped": { - "message": "Not yet supported, skipped" - }, - "status.syncing": { - "message": "Synchronizing" - }, - "status.timeout": { - "message": "Communication timeout." - }, - "status.wbxml-parse-error": { - "message": "Server sends unreadable response." - }, - "status.wbxmlerror": { - "message": "Sync failed. Server responded with status <##replace.1##>." - }, - "status.wbxmlmissingfield": { - "message": "ActiveSync protocol violation: Mandatory field <##replace.1##> is missing from server response." - }, - "syncstate.accountdone": { - "message": "Finished account" - }, - "syncstate.done": { - "message": "Preparing next item for synchronization" - }, - "syncstate.eval.response.autodiscover": { - "message": "Processing updated server settings" - }, - "syncstate.eval.response.deletefolder": { - "message": "Folder deleted" - }, - "syncstate.eval.response.estimate": { - "message": "Processing change estimate" - }, - "syncstate.eval.response.folders": { - "message": "Processing folder list update" - }, - "syncstate.eval.response.localchanges": { - "message": "Processing acknowledgment of local changes" - }, - "syncstate.eval.response.localdeletes": { - "message": "Processing acknowledgment of local deletes" - }, - "syncstate.eval.response.options": { - "message": "Processing server options" - }, - "syncstate.eval.response.provision": { - "message": "Processing provision" - }, - "syncstate.eval.response.remotechanges": { - "message": "Processing remote changes" - }, - "syncstate.eval.response.revertlocalchanges": { - "message": "Reverting local changes" - }, - "syncstate.eval.response.setdeviceinfo": { - "message": "Sending device information" - }, - "syncstate.eval.response.synckey": { - "message": "Processing SyncKey" - }, - "syncstate.prepare.request.autodiscover": { - "message": "Requesting updated server settings" - }, - "syncstate.prepare.request.deletefolder": { - "message": "Preparing to delete folder" - }, - "syncstate.prepare.request.estimate": { - "message": "Requesting change estimate" - }, - "syncstate.prepare.request.folders": { - "message": "Sending folder list update" - }, - "syncstate.prepare.request.localchanges": { - "message": "Sending local changes" - }, - "syncstate.prepare.request.localdeletes": { - "message": "Sending local deletes" - }, - "syncstate.prepare.request.options": { - "message": "Requesting server options" - }, - "syncstate.prepare.request.provision": { - "message": "Requesting provision" - }, - "syncstate.prepare.request.remotechanges": { - "message": "Requesting remote changes" - }, - "syncstate.prepare.request.revertlocalchanges": { - "message": "Collecting local changes" - }, - "syncstate.prepare.request.setdeviceinfo": { - "message": "Sending device information" - }, - "syncstate.prepare.request.synckey": { - "message": "Requesting SyncKey" - }, - "syncstate.preparing": { - "message": "Preparing next item for synchronization" - }, - "syncstate.send.request.autodiscover": { - "message": "Waiting for updated server settings" - }, - "syncstate.send.request.deletefolder": { - "message": "Waiting for folder to be deleted" - }, - "syncstate.send.request.estimate": { - "message": "Waiting for change estimate" - }, - "syncstate.send.request.folders": { - "message": "Waiting for folder list update" - }, - "syncstate.send.request.localchanges": { - "message": "Waiting for acknowledgment of local changes" - }, - "syncstate.send.request.localdeletes": { - "message": "Waiting for acknowledgment of local deletes" - }, - "syncstate.send.request.options": { - "message": "Waiting for server options" - }, - "syncstate.send.request.provision": { - "message": "Waiting for provision" - }, - "syncstate.send.request.remotechanges": { - "message": "Waiting for remote changes" - }, - "syncstate.send.request.revertlocalchanges": { - "message": "Waiting for most recent versions" - }, - "syncstate.send.request.setdeviceinfo": { - "message": "Sending device information" - }, - "syncstate.send.request.synckey": { - "message": "Waiting for SyncKey" - }, - "syncstate.syncing": { - "message": "Initialize synchronization" - } -} +{ + "abCard.Anniversary": { + "message": "Anniversary:" + }, + "abCard.AssistantName": { + "message": "Assistant:" + }, + "abCard.AssistantPhoneNumber": { + "message": "Assistant Phone:" + }, + "abCard.Business2PhoneNumber": { + "message": "Work Alternative Phone:" + }, + "abCard.BusinessFaxNumber": { + "message": "Work Fax:" + }, + "abCard.CarPhoneNumber": { + "message": "Car Phone:" + }, + "abCard.CompanyMainPhone": { + "message": "Work Main Phone:" + }, + "abCard.Email3Address": { + "message": "Alternative Email:" + }, + "abCard.Home2PhoneNumber": { + "message": "Home Alternative Phone:" + }, + "abCard.ManagerName": { + "message": "Manager:" + }, + "abCard.MiddleName": { + "message": "Middle name:" + }, + "abCard.OtherAddress": { + "message": "Address:" + }, + "abCard.OtherCity": { + "message": "City:" + }, + "abCard.OtherCountry": { + "message": "Country:" + }, + "abCard.OtherState": { + "message": "State:" + }, + "abCard.OtherZip": { + "message": "ZIP Code:" + }, + "abCard.RadioPhoneNumber": { + "message": "Radio Phone:" + }, + "abCard.Spouse": { + "message": "Spouse:" + }, + "abCard.header.eas": { + "message": "Other Fields (EAS)" + }, + "abCard.header.homenumbers": { + "message": "Additional home numbers:" + }, + "abCard.header.messaging": { + "message": "Messaging:" + }, + "abCard.header.otheraddress": { + "message": "Other Address (EAS)" + }, + "abCard.header.othernumbers": { + "message": "Additional numbers:" + }, + "abCard.header.people": { + "message": "People:" + }, + "abCard.header.worknumbers": { + "message": "Additional work numbers:" + }, + "acl.readonly": { + "message": "Read-only server access (revert local changes)" + }, + "acl.readwrite": { + "message": "Read from and write to server" + }, + "add.description": { + "message": "Please select one of the available server configuration options and enter the requested details. " + }, + "add.name": { + "message": "Account name:" + }, + "add.ok": { + "message": "Add account" + }, + "add.password": { + "message": "Password:" + }, + "add.server": { + "message": "Server configuration:" + }, + "add.shortdescription": { + "message": "Account information" + }, + "add.title": { + "message": "Adding an Exchange ActiveSync account to TbSync" + }, + "add.url": { + "message": "Server address:" + }, + "add.urldescription": { + "message": "It should be sufficient to provide just the basic server address (e.g.: mail.yourserver.com). However, it is also possible to provide the full URL (e.g.: https://mail.yourserver.com/Microsoft-Server-ActiveSync)." + }, + "add.user": { + "message": "User name (email address):" + }, + "autocomplete.serverdirectory": { + "message": "global server directory" + }, + "autodiscover.Failed": { + "message": "Autodiscover for user <##user##> failed. Either the provided credentials were wrong or your ActiveSync provider has a temporary issue, or does not support Autodiscover." + }, + "autodiscover.NeedEmail": { + "message": "Autodiscover needs a valid email address as user name." + }, + "autodiscover.Ok": { + "message": "Autodiscover completed successfully, you can now check the optional settings and establish the synchronization connection." + }, + "autodiscover.Querying": { + "message": "Searching for settings…" + }, + "config.auto": { + "message": "ActiveSync server configuration (Autodiscover)" + }, + "config.custom": { + "message": "ActiveSync server configuration" + }, + "deletefolder.confirm": { + "message": "Do you really want to PERMANENTLY PURGE folder “##replace.1##” from trash?" + }, + "deletefolder.menuentry": { + "message": "Permanently purge folder “##replace.1##” from trash" + }, + "deletefolder.notallowed": { + "message": "Please unsubscribe folder “##replace.1##” before trying to purge it from trash." + }, + "extensionDescription": { + "message": "Add sync support for Exchange ActiveSync accounts to TbSync (contacts, tasks and calendars)." + }, + "extensionName": { + "message": "Provider for Exchange ActiveSync" + }, + "helplink.BadItemSkipped": { + "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped" + }, + "helplink.global.clientdenied": { + "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F" + }, + "helplink.security": { + "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F" + }, + "manager.tabs.accountsettings": { + "message": "Account settings" + }, + "manager.tabs.outOfOffice": { + "message": "Auto responder" + }, + "manager.tabs.syncsettings": { + "message": "Options" + }, + "newaccount.add_auto": { + "message": "Autodiscover settings and add account" + }, + "newaccount.add_custom": { + "message": "Add account" + }, + "pref.AccountName": { + "message": "Description" + }, + "pref.ActiveSyncVersion": { + "message": "ActiveSync version" + }, + "pref.DeviceId": { + "message": "ActiveSync device ID" + }, + "pref.ServerName": { + "message": "Server address" + }, + "pref.ServerNameDescription": { + "message": "e.g. mail.yourserver.com" + }, + "pref.ShowTrashedFolders": { + "message": "Show folders found in trash" + }, + "pref.UserName": { + "message": "User name" + }, + "pref.UserNameDescription": { + "message": "User name is usually the email address of your account." + }, + "pref.autodetect": { + "message": "best available" + }, + "pref.birthday": { + "message": "Send birthday information" + }, + "pref.calendaroptions": { + "message": "Calendar options" + }, + "pref.contactoptions": { + "message": "Contact options" + }, + "pref.displayoverride": { + "message": "Override Display Name with “First Name” + “Second Name”" + }, + "pref.generaloptions": { + "message": "General options" + }, + "pref.provision": { + "message": "Enforce provisioning (required by Kerio)" + }, + "pref.seperator.comma": { + "message": "Comma" + }, + "pref.seperator.description": { + "message": "Separator for multiline address field." + }, + "pref.seperator.linebreak": { + "message": "Line break" + }, + "pref.synclimit.1month": { + "message": "from 4 weeks ago" + }, + "pref.synclimit.2weeks": { + "message": "from 2 weeks ago" + }, + "pref.synclimit.3month": { + "message": "from 3 months ago" + }, + "pref.synclimit.6month": { + "message": "from 6 months ago" + }, + "pref.synclimit.all": { + "message": "everything" + }, + "pref.synclimit.description": { + "message": "Synchronization period: " + }, + "pref.usehttps": { + "message": "Use secure connection (connect via https)" + }, + "recyclebin": { + "message": "Trash" + }, + "servertype.auto": { + "message": "Automatic configuration" + }, + "servertype.custom": { + "message": "Custom configuration" + }, + "servertype.description.auto": { + "message": "The configuration for many ActiveSync servers can be discovered by providing just your email address." + }, + "servertype.description.custom": { + "message": "Setup your account by manually providing the address of the server you want to connect." + }, + "servertype.description.office365": { + "message": "Accounts connected to Office 365 use a modern authentication process called OAuth 2.0 which also supports Multi-Factor-Authentication (MFA)." + }, + "servertype.office365": { + "message": "Microsoft Office 365" + }, + "servertype.unlock": { + "message": "Double click to unlock all predefined server settings." + }, + "status.401": { + "message": "Could not authenticate, check username and password (HTTP Error 401)." + }, + "status.403": { + "message": "Server rejected connection (forbidden) (HTTP Error 403)." + }, + "status.404": { + "message": "User not found (HTTP Error 404)." + }, + "status.449": { + "message": "Server requests provisioning (HTTP Error 449)." + }, + "status.500": { + "message": "Unknown Server Error (HTTP Error 500)." + }, + "status.503": { + "message": "Service unavailable (HTTP Error 503)." + }, + "status.BadItemSkipped": { + "message": "Bad Item Skipped: ##replace.1##" + }, + "status.FolderDelete.3": { + "message": "Cannot delete a system folder (status 3)" + }, + "status.FolderDelete.4": { + "message": "Folder does not exist (status 4), resyncing" + }, + "status.FolderDelete.6": { + "message": "Command could not be completed, an error occurred on the server (status 6)" + }, + "status.FolderDelete.9": { + "message": "Invalid synchronization key (status 9), resyncing" + }, + "status.FolderSync.9": { + "message": "Invalid synchronization key (status 9), resyncing" + }, + "status.InvalidServerOptions": { + "message": "The server does not provide information about the supported ActiveSync versions. Is EAS blocked for this user or this client (TbSync)? You could try to set the ActiveSync version manually." + }, + "status.OK": { + "message": "OK" + }, + "status.ServerRejectedRequest": { + "message": "The EAS Server rejected the last request." + }, + "status.ServerRejectedSomeItems": { + "message": "The EAS server did not accept ##replace.1## elements." + }, + "status.Sync.12": { + "message": "Folder hierarchy changed (status 12), resyncing" + }, + "status.Sync.3": { + "message": "Invalid synchronization key (status 3), resyncing" + }, + "status.Sync.4": { + "message": "Malformed request (status 4)" + }, + "status.Sync.5": { + "message": "Temporary server issues or invalid item (status 5)" + }, + "status.Sync.6": { + "message": "Invalid item (status 6)" + }, + "status.Sync.8": { + "message": "Object not found (status 8)" + }, + "status.aborted": { + "message": "Not synchronized" + }, + "status.disabled": { + "message": "Disabled" + }, + "status.empty-response": { + "message": "Server sends unexpected empty response." + }, + "status.forbiddenCalendarItemInTasksFolder": { + "message": "Forbidden calendar item in a task folder (please resort)" + }, + "status.forbiddenTasksItemInCalendarFolder": { + "message": "Forbidden task item in a calendar folder (please resort)" + }, + "status.global.101": { + "message": "The request contains WBXML but it could not be decoded into XML (EAS Error 101)." + }, + "status.global.102": { + "message": "The request contains WBXML but it could not be decoded into XML (EAS Error 102)." + }, + "status.global.103": { + "message": "The XML provided in the request does not follow the protocol requirements (EAS Error 103)." + }, + "status.global.110": { + "message": "The server reported an internal error and we should not retry immediately. Automatic periodic sync has been disabled for 30 minutes (EAS Error 110)." + }, + "status.global.clientdenied": { + "message": "The EAS server reports <##replace.2##> (status ##replace.1##) and does not allow TbSync to access your account." + }, + "status.httperror": { + "message": "Communication error (HTTP status ##replace.1##)." + }, + "status.invalid": { + "message": "Invalid server response (junk)." + }, + "status.malformed-xml": { + "message": "Could not parse XML. Check event log for details." + }, + "status.modified": { + "message": "Local modifications" + }, + "status.network": { + "message": "Could not connect to server (##replace.1##)." + }, + "status.networkerror": { + "message": "Could not connect to server." + }, + "status.nosupportedeasversion": { + "message": "Server does not support ActiveSync v2.5 or v14.0 (only ##replace.1##). TbSync will not work with this ActiveSync server." + }, + "status.notargets": { + "message": "Aborting Sync, because sync targets could not be created." + }, + "status.notsupportedeasversion": { + "message": "Server does not support selected ActiveSync v##replace.1## (only ##replace.2##)." + }, + "status.notsyncronized": { + "message": "Account needs to be synchronized, at least one item is out of sync." + }, + "status.nouserhost": { + "message": "Missing username and/or server. Please provide those values." + }, + "status.pending": { + "message": "Waiting to be synchronized" + }, + "status.policy.2": { + "message": "There is no policy for this client. Contact your server administrator or disable provisioning for this account." + }, + "status.policy.3": { + "message": "Unknown PolicyType value. Contact your server administrator or disable provisioning for this account." + }, + "status.policy.4": { + "message": "The policy data on the server is corrupted (possibly tampered with). Contact your server administrator or disable provisioning for this account." + }, + "status.policy.5": { + "message": "The client is acknowledging the wrong policy key. Contact your server administrator or disable provisioning for this account." + }, + "status.provision": { + "message": "Provisioning failed with status <##replace.1##>" + }, + "status.response-contains-no-data": { + "message": "Response from the server contains no data." + }, + "status.resync-loop": { + "message": "There was an error from which we could not recover by resyncing the account. Please disable the account and try again. (Error: resync loop)" + }, + "status.security": { + "message": "Could not establish a secure connection. Are you using a self-signed or otherwise untrusted certificate without importing it into Thunderbird? (##replace.1##)" + }, + "status.skipped": { + "message": "Not yet supported, skipped" + }, + "status.syncing": { + "message": "Synchronizing" + }, + "status.timeout": { + "message": "Communication timeout." + }, + "status.wbxml-parse-error": { + "message": "Server sends unreadable response." + }, + "status.wbxmlerror": { + "message": "Sync failed. Server responded with status <##replace.1##>." + }, + "status.wbxmlmissingfield": { + "message": "ActiveSync protocol violation: Mandatory field <##replace.1##> is missing from server response." + }, + "syncstate.accountdone": { + "message": "Finished account" + }, + "syncstate.done": { + "message": "Preparing next item for synchronization" + }, + "syncstate.eval.response.autodiscover": { + "message": "Processing updated server settings" + }, + "syncstate.eval.response.deletefolder": { + "message": "Folder deleted" + }, + "syncstate.eval.response.estimate": { + "message": "Processing change estimate" + }, + "syncstate.eval.response.folders": { + "message": "Processing folder list update" + }, + "syncstate.eval.response.localchanges": { + "message": "Processing acknowledgment of local changes" + }, + "syncstate.eval.response.localdeletes": { + "message": "Processing acknowledgment of local deletes" + }, + "syncstate.eval.response.options": { + "message": "Processing server options" + }, + "syncstate.eval.response.provision": { + "message": "Processing provision" + }, + "syncstate.eval.response.remotechanges": { + "message": "Processing remote changes" + }, + "syncstate.eval.response.revertlocalchanges": { + "message": "Reverting local changes" + }, + "syncstate.eval.response.setdeviceinfo": { + "message": "Sending device information" + }, + "syncstate.eval.response.synckey": { + "message": "Processing SyncKey" + }, + "syncstate.prepare.request.autodiscover": { + "message": "Requesting updated server settings" + }, + "syncstate.prepare.request.deletefolder": { + "message": "Preparing to delete folder" + }, + "syncstate.prepare.request.estimate": { + "message": "Requesting change estimate" + }, + "syncstate.prepare.request.folders": { + "message": "Sending folder list update" + }, + "syncstate.prepare.request.localchanges": { + "message": "Sending local changes" + }, + "syncstate.prepare.request.localdeletes": { + "message": "Sending local deletes" + }, + "syncstate.prepare.request.options": { + "message": "Requesting server options" + }, + "syncstate.prepare.request.provision": { + "message": "Requesting provision" + }, + "syncstate.prepare.request.remotechanges": { + "message": "Requesting remote changes" + }, + "syncstate.prepare.request.revertlocalchanges": { + "message": "Collecting local changes" + }, + "syncstate.prepare.request.setdeviceinfo": { + "message": "Sending device information" + }, + "syncstate.prepare.request.synckey": { + "message": "Requesting SyncKey" + }, + "syncstate.preparing": { + "message": "Preparing next item for synchronization" + }, + "syncstate.send.request.autodiscover": { + "message": "Waiting for updated server settings" + }, + "syncstate.send.request.deletefolder": { + "message": "Waiting for folder to be deleted" + }, + "syncstate.send.request.estimate": { + "message": "Waiting for change estimate" + }, + "syncstate.send.request.folders": { + "message": "Waiting for folder list update" + }, + "syncstate.send.request.localchanges": { + "message": "Waiting for acknowledgment of local changes" + }, + "syncstate.send.request.localdeletes": { + "message": "Waiting for acknowledgment of local deletes" + }, + "syncstate.send.request.options": { + "message": "Waiting for server options" + }, + "syncstate.send.request.provision": { + "message": "Waiting for provision" + }, + "syncstate.send.request.remotechanges": { + "message": "Waiting for remote changes" + }, + "syncstate.send.request.revertlocalchanges": { + "message": "Waiting for most recent versions" + }, + "syncstate.send.request.setdeviceinfo": { + "message": "Sending device information" + }, + "syncstate.send.request.synckey": { + "message": "Waiting for SyncKey" + }, + "syncstate.syncing": { + "message": "Initialize synchronization" + } +} diff -Nru eas4tbsync-4.11/_locales/ru/messages.json eas4tbsync-4.17/_locales/ru/messages.json --- eas4tbsync-4.11/_locales/ru/messages.json 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/_locales/ru/messages.json 2025-05-15 11:21:20.000000000 +0000 @@ -1,566 +1,566 @@ -{ - "abCard.Anniversary": { - "message": "День рождения:" - }, - "abCard.AssistantName": { - "message": "Помощник:" - }, - "abCard.AssistantPhoneNumber": { - "message": "Телефон помощника:" - }, - "abCard.Business2PhoneNumber": { - "message": "Рабочий телефон 2:" - }, - "abCard.BusinessFaxNumber": { - "message": "Рабочий факс:" - }, - "abCard.CarPhoneNumber": { - "message": "Автомобильный телефон:" - }, - "abCard.CompanyMainPhone": { - "message": "Основной рабочий телефон:" - }, - "abCard.Email3Address": { - "message": "Запасной Email:" - }, - "abCard.Home2PhoneNumber": { - "message": "Домашний телефон 2:" - }, - "abCard.ManagerName": { - "message": "Руководитель:" - }, - "abCard.MiddleName": { - "message": "Отчество:" - }, - "abCard.OtherAddress": { - "message": "Адрес:" - }, - "abCard.OtherCity": { - "message": "Город:" - }, - "abCard.OtherCountry": { - "message": "Страна:" - }, - "abCard.OtherState": { - "message": "Область:" - }, - "abCard.OtherZip": { - "message": "Почтовый индекс:" - }, - "abCard.RadioPhoneNumber": { - "message": "Радиотелефон:" - }, - "abCard.Spouse": { - "message": "Супруг:" - }, - "abCard.header.eas": { - "message": "Другие поля (EAS)" - }, - "abCard.header.homenumbers": { - "message": "Дополнительные домашние номера:" - }, - "abCard.header.messaging": { - "message": "Мессенджер:" - }, - "abCard.header.otheraddress": { - "message": "Другой адрес (EAS)" - }, - "abCard.header.othernumbers": { - "message": "Дополнительные номера:" - }, - "abCard.header.people": { - "message": "Люди:" - }, - "abCard.header.worknumbers": { - "message": "Дополнительные рабочие номера:" - }, - "acl.readonly": { - "message": "Доступ к серверу только для чтения (отменить локальные изменения)" - }, - "acl.readwrite": { - "message": "Читать и писать на сервер" - }, - "add.description": { - "message": "Пожалуйста, выберите один из доступных параметров конфигурации сервера и введите требуемую информацию. " - }, - "add.name": { - "message": "Имя аккаунта:" - }, - "add.ok": { - "message": "Добавить аккаунт" - }, - "add.password": { - "message": "Пароль:" - }, - "add.server": { - "message": "Конфигурация сервера:" - }, - "add.shortdescription": { - "message": "Информация об учетной записи" - }, - "add.title": { - "message": "Добавить Exchange ActiveSync аккаунт для TbSync" - }, - "add.url": { - "message": "Адрес сервера:" - }, - "add.urldescription": { - "message": "Достаточно указать только базовый адрес сервера (например: mail.yourserver.com). Однако также можно указать полный URL-адрес (например: https://mail.yourserver.com/Microsoft-Server-ActiveSync)." - }, - "add.user": { - "message": "Имя пользователя (email адрес):" - }, - "autocomplete.serverdirectory": { - "message": "глобальный каталог сервера" - }, - "autodiscover.Failed": { - "message": "Автообнаружение для пользователя <##user##> не удалось. Либо предоставленные учетные данные были неправильными, либо у вашего провайдера ActiveSync была временная проблема, или не поддерживается автообнаружение." - }, - "autodiscover.NeedEmail": { - "message": "Автообнаружению нужен действительный адрес электронной почты в качестве имени пользователя." - }, - "autodiscover.Ok": { - "message": "Автообнаружение успешно завершено, теперь вы можете проверить дополнительные настройки и установить соединение синхронизации." - }, - "autodiscover.Querying": { - "message": "Поиск настроек…" - }, - "config.auto": { - "message": "ActiveSync конфигурация сервера (Автообнаружение)" - }, - "config.custom": { - "message": "ActiveSync конфигурация сервера" - }, - "deletefolder.confirm": { - "message": "Вы действительно хотите ПЕРМАНЕНТНО ВЫЧИСТИТЬ папку “##replace.1##” из корзины?" - }, - "deletefolder.menuentry": { - "message": "Перманентно вычистить папку “##replace.1##” из корзины" - }, - "deletefolder.notallowed": { - "message": "Откажитесь от подписки папки “##replace.1##” прежде чем пытаться очистить ее от мусора." - }, - "extensionDescription": { - "message": "Добавляет в TbSync поддержку синхронизации для учетных записей Exchange через базирующийся на http/https протокол ActiveSync (контакты, задачи и календари)." - }, - "extensionName": { - "message": "Provider for Exchange ActiveSync" - }, - "helplink.BadItemSkipped": { - "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped" - }, - "helplink.global.clientdenied": { - "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F" - }, - "helplink.security": { - "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F" - }, - "manager.tabs.accountsettings": { - "message": "Настройки аккаунта" - }, - "manager.tabs.outOfOffice": { - "message": "Автоответчик" - }, - "manager.tabs.syncsettings": { - "message": "Настройки синхронизации" - }, - "newaccount.add_auto": { - "message": "Настройки автообнаружения и добавление аккаунта" - }, - "newaccount.add_custom": { - "message": "Добавить аккаунт" - }, - "pref.AccountName": { - "message": "Имя аккаунта" - }, - "pref.ActiveSyncVersion": { - "message": "Версия ActiveSync" - }, - "pref.DeviceId": { - "message": "Идентификатор устройства" - }, - "pref.ServerName": { - "message": "Адрес сервера" - }, - "pref.ServerNameDescription": { - "message": "например: mail.yourserver.com" - }, - "pref.ShowTrashedFolders": { - "message": "Показывать папки, найденные в корзине" - }, - "pref.UserName": { - "message": "Имя пользователя" - }, - "pref.UserNameDescription": { - "message": "Имя пользователя обычно является адресом электронной почты вашей учетной записи." - }, - "pref.autodetect": { - "message": "лучшее из доступных" - }, - "pref.birthday": { - "message": "Отправить информацию о днях рождения" - }, - "pref.calendaroptions": { - "message": "Параметры календаря" - }, - "pref.contactoptions": { - "message": "Параметры контакта" - }, - "pref.displayoverride": { - "message": "Переопределить отображаемое имя с помощью “Имя” + “Фамилия”" - }, - "pref.generaloptions": { - "message": "Общие параметры" - }, - "pref.provision": { - "message": "Заставить поддерживать (требуется для Kerio)" - }, - "pref.seperator.comma": { - "message": "Запятая" - }, - "pref.seperator.description": { - "message": "Сепаратор для многострочного поля адреса." - }, - "pref.seperator.linebreak": { - "message": "Разрыв строки" - }, - "pref.synclimit.1month": { - "message": "от 4 недель назад" - }, - "pref.synclimit.2weeks": { - "message": "от 2 недель назад" - }, - "pref.synclimit.3month": { - "message": "от 3 месяцев назад" - }, - "pref.synclimit.6month": { - "message": "от 6 месяцев назад" - }, - "pref.synclimit.all": { - "message": "все" - }, - "pref.synclimit.description": { - "message": "Период синхронизации:" - }, - "pref.usehttps": { - "message": "Использовать безопасное соединение (соединение через https)" - }, - "recyclebin": { - "message": "Корзина" - }, - "servertype.auto": { - "message": "Автоматическая настройка" - }, - "servertype.custom": { - "message": "Ручная настройка" - }, - "servertype.description.auto": { - "message": "Для определения конфигурации множества серверов ActiveSync достаточно указать только адрес Вашей электронной почты." - }, - "servertype.description.custom": { - "message": "Настройте Вашу учетную запись, вручную указав адрес сервера, к которому Вы хотите подключиться." - }, - "servertype.description.office365": { - "message": "Учетные записи, подключенные к Office 365, используют современный процесс аутентификации под названием OAuth 2.0, который также поддерживает многофакторную аутентификацию (MFA)." - }, - "servertype.office365": { - "message": "Microsoft Office 365" - }, - "servertype.unlock": { - "message": "Дважды щелкните, чтобы разблокировать все предопределенные настройки сервера." - }, - "status.401": { - "message": "Не удалось аутентифицировать, проверить имя пользователя и пароль. (HTTP Ошибка 401)." - }, - "status.403": { - "message": "Сервер отклонил соединение (запрещено) (HTTP Ошибка 403)." - }, - "status.404": { - "message": "Пользователь не найден (HTTP Ошибка 404)." - }, - "status.449": { - "message": "Серверные запросы дублируются (HTTP Ошибка 449)." - }, - "status.500": { - "message": "Неизвестная ошибка сервера (HTTP Ошибка 500)." - }, - "status.503": { - "message": "Сервис недоступен (HTTP Ошибка 503)." - }, - "status.BadItemSkipped": { - "message": "Плохой элемент пропущен: ##replace.1##" - }, - "status.FolderDelete.3": { - "message": "Не удается удалить системную папку." - }, - "status.FolderDelete.4": { - "message": "Папка не существует (статус 4), повторная синхронизация" - }, - "status.FolderDelete.6": { - "message": "Команда не может быть выполнена, на сервере возникла ошибка." - }, - "status.FolderDelete.9": { - "message": "Неверный ключ синхронизации (статус 9), повторная синхронизация" - }, - "status.FolderSync.9": { - "message": "Неверный ключ синхронизации (статус 9), повторная синхронизация" - }, - "status.InvalidServerOptions": { - "message": "Сервер не предоставляет информацию о поддерживаемых версиях ActiveSync. EAS блокирован для этого пользователя или этого клиента (TbSync)? Вы можете попробовать установить версию ActiveSync вручную." - }, - "status.OK": { - "message": "Готово" - }, - "status.ServerRejectedRequest": { - "message": "Сервер EAS отклонил наш последний запрос." - }, - "status.ServerRejectedSomeItems": { - "message": "Сервер EAS не принял элементы ##replace.1##." - }, - "status.Sync.12": { - "message": "Изменена иерархия папок (статус 12), повторная синхронизация" - }, - "status.Sync.3": { - "message": "Неверный ключ синхронизации (статус 3), повторная синхронизация" - }, - "status.Sync.4": { - "message": "Неверный запрос (статус 4)" - }, - "status.Sync.5": { - "message": "Временные проблемы с сервером или недопустимый элемент (статус 5)" - }, - "status.Sync.6": { - "message": "Недопустимый элемент (статус 6)" - }, - "status.Sync.8": { - "message": "Объект не найден (статус 8)" - }, - "status.aborted": { - "message": "Не синхронизировано" - }, - "status.disabled": { - "message": "Аккаунт не включен, синхронизация отключена." - }, - "status.empty-response": { - "message": "Сервер отправляет неожиданный пустой ответ." - }, - "status.forbiddenCalendarItemInTasksFolder": { - "message": "Запрещенный элемент календаря в папке задач (пожалуйста, исправьте)" - }, - "status.forbiddenTasksItemInCalendarFolder": { - "message": "Запрещенный элемент задачи в папке календаря (пожалуйста, исправьте)" - }, - "status.global.101": { - "message": "Запрос содержит WBXML но он не может быть декодирован в XML (EAS Ошибка 101)." - }, - "status.global.102": { - "message": "Запрос содержит WBXML но он не может быть декодирован в XML (EAS Ошибка 102)." - }, - "status.global.103": { - "message": "XML, указанный в запросе, не соответствует требованиям протокола (EAS Ошибка 103)." - }, - "status.global.110": { - "message": "Сервер сообщил о внутренней ошибке, и мы не должны немедленно повторять попытку. Автоматическая периодическая синхронизация была отключена на 30 минут (Ошибка EAS 110)." - }, - "status.global.clientdenied": { - "message": "Отчеты сервера EAS <##replace.2##> (статус ##replace.1##) и не позволяют TbSync доступ к вашему аккаунту." - }, - "status.httperror": { - "message": "Ошибка связи (HTTP статус ##replace.1##)." - }, - "status.invalid": { - "message": "Недопустимый ответ сервера (мусор в обмене)." - }, - "status.malformed-xml": { - "message": "Не удалось разобрать XML. Проверьте журнал событий для деталей." - }, - "status.modified": { - "message": "Локальные изменения" - }, - "status.network": { - "message": "Не удалось подключиться к серверу (##replace.1##)." - }, - "status.networkerror": { - "message": "Не удалось подключиться к серверу." - }, - "status.nosupportedeasversion": { - "message": "Сервер не поддерживает ActiveSync v2.5 или v14.0 (только ##replace.1##). TbSync не будет работать с этим ActiveSync сервером." - }, - "status.notargets": { - "message": "Отмена синхронизации, поскольку цели синхронизации не могут быть созданы." - }, - "status.notsupportedeasversion": { - "message": "Сервер не поддерживает выбранный ActiveSync v##replace.1## (только ##replace.2##)." - }, - "status.notsyncronized": { - "message": "Аккаунт должен быть синхронизирован, по крайней мере один элемент не синхронизирован." - }, - "status.nouserhost": { - "message": "Отсутствует имя пользователя и/или сервера. Укажите эти значения." - }, - "status.pending": { - "message": "Ожидание пока синхронизируется" - }, - "status.policy.2": { - "message": "Для этого клиента нет политики. Обратитесь к администратору вашего сервера или отключите использование этого аккаунта." - }, - "status.policy.3": { - "message": "Неизвестное значение политики для этого клиента. Обратитесь к администратору вашего сервера или отключите использование этого аккаунта." - }, - "status.policy.4": { - "message": "Данные политики на сервере повреждены (возможно, подделаны). Обратитесь к администратору вашего сервера или отключите использование этого аккаунта." - }, - "status.policy.5": { - "message": "Клиент обнаружил неправильный ключ политики. Обратитесь к администратору вашего сервера или отключите использование этого аккаунта." - }, - "status.provision": { - "message": "Резервирование не удалось со статусом <##replace.1##>" - }, - "status.response-contains-no-data": { - "message": "Ответ от сервера не содержит данных." - }, - "status.resync-loop": { - "message": "Произошла ошибка, из-за которой не удалось пересинхронизировать аккаунт. Отключите аккаунт и повторите попытку. (Ошибка: повторная синхронизация)" - }, - "status.security": { - "message": "Не удалось установить безопасное соединение. Вы используете самоподписанный или ненадежный сертификат без импорта его в Thunderbird? (##replace.1##)" - }, - "status.skipped": { - "message": "Пока не поддерживается, пропущено" - }, - "status.syncing": { - "message": "Синхронизация" - }, - "status.timeout": { - "message": "Тайм-аут связи." - }, - "status.wbxml-parse-error": { - "message": "Сервер отправляет нечитаемый ответ." - }, - "status.wbxmlerror": { - "message": "Ошибка синхронизации. Сервер ответил статусом <##replace.1##>." - }, - "status.wbxmlmissingfield": { - "message": "ActiveSync протокол нарушен: Обязательное поле <##replace.1##> отсутствует в ответе сервера." - }, - "syncstate.accountdone": { - "message": "Завершенный аккаунт" - }, - "syncstate.done": { - "message": "Подготовка следующего элемента для синхронизации" - }, - "syncstate.eval.response.autodiscover": { - "message": "Обработка обновленных настроек сервера" - }, - "syncstate.eval.response.deletefolder": { - "message": "Папка удалена" - }, - "syncstate.eval.response.estimate": { - "message": "Обработка оценки изменений" - }, - "syncstate.eval.response.folders": { - "message": "Обработка обновления листа папок" - }, - "syncstate.eval.response.localchanges": { - "message": "Обработка подтверждения локальных изменений" - }, - "syncstate.eval.response.localdeletes": { - "message": "Обработка подтверждения локальных удалений" - }, - "syncstate.eval.response.options": { - "message": "Обработка настроек сервера" - }, - "syncstate.eval.response.provision": { - "message": "Обработка резервирования" - }, - "syncstate.eval.response.remotechanges": { - "message": "Обработка удаленных изменений" - }, - "syncstate.eval.response.revertlocalchanges": { - "message": "Откат локальных изменений" - }, - "syncstate.eval.response.setdeviceinfo": { - "message": "Обработка информации об устройстве" - }, - "syncstate.eval.response.synckey": { - "message": "Обработка элементов синхронизации" - }, - "syncstate.prepare.request.autodiscover": { - "message": "Запрос обновленных настроек сервера" - }, - "syncstate.prepare.request.deletefolder": { - "message": "Подготовка к удалению папки" - }, - "syncstate.prepare.request.estimate": { - "message": "Запрос оценки изменения" - }, - "syncstate.prepare.request.folders": { - "message": "Отправка обновления листа папок" - }, - "syncstate.prepare.request.localchanges": { - "message": "Отправка локальных изменений" - }, - "syncstate.prepare.request.localdeletes": { - "message": "Отправка локальных удалений" - }, - "syncstate.prepare.request.options": { - "message": "Запрос настроек сервера" - }, - "syncstate.prepare.request.provision": { - "message": "Запрос для резервирования" - }, - "syncstate.prepare.request.remotechanges": { - "message": "Запрос удаленных изменений" - }, - "syncstate.prepare.request.revertlocalchanges": { - "message": "Сбор локальных изменений" - }, - "syncstate.prepare.request.setdeviceinfo": { - "message": "Обработка информации об устройстве" - }, - "syncstate.prepare.request.synckey": { - "message": "Запрос элементов синхронизации" - }, - "syncstate.preparing": { - "message": "Подготовка следующего элемента для синхронизации" - }, - "syncstate.send.request.autodiscover": { - "message": "Ожидание обновленных настроек сервера" - }, - "syncstate.send.request.deletefolder": { - "message": "Ожидание удаления папки" - }, - "syncstate.send.request.estimate": { - "message": "Ожидание оценки изменений" - }, - "syncstate.send.request.folders": { - "message": "Ожидание обновления листа папок" - }, - "syncstate.send.request.localchanges": { - "message": "Ожидание подтверждения локальных изменений" - }, - "syncstate.send.request.localdeletes": { - "message": "Ожидание подтверждения локальных удалений" - }, - "syncstate.send.request.options": { - "message": "Ожидание настроек сервера" - }, - "syncstate.send.request.provision": { - "message": "Ожидание резервирования" - }, - "syncstate.send.request.remotechanges": { - "message": "Ожидание удаленных изменений" - }, - "syncstate.send.request.revertlocalchanges": { - "message": "Ожидание самых последних версий" - }, - "syncstate.send.request.setdeviceinfo": { - "message": "Обработка информации об устройстве" - }, - "syncstate.send.request.synckey": { - "message": "Ожидание элементов синхронизации" - }, - "syncstate.syncing": { - "message": "Инициализация синхронизации" - } -} +{ + "abCard.Anniversary": { + "message": "День рождения:" + }, + "abCard.AssistantName": { + "message": "Помощник:" + }, + "abCard.AssistantPhoneNumber": { + "message": "Телефон помощника:" + }, + "abCard.Business2PhoneNumber": { + "message": "Рабочий телефон 2:" + }, + "abCard.BusinessFaxNumber": { + "message": "Рабочий факс:" + }, + "abCard.CarPhoneNumber": { + "message": "Автомобильный телефон:" + }, + "abCard.CompanyMainPhone": { + "message": "Основной рабочий телефон:" + }, + "abCard.Email3Address": { + "message": "Запасной Email:" + }, + "abCard.Home2PhoneNumber": { + "message": "Домашний телефон 2:" + }, + "abCard.ManagerName": { + "message": "Руководитель:" + }, + "abCard.MiddleName": { + "message": "Отчество:" + }, + "abCard.OtherAddress": { + "message": "Адрес:" + }, + "abCard.OtherCity": { + "message": "Город:" + }, + "abCard.OtherCountry": { + "message": "Страна:" + }, + "abCard.OtherState": { + "message": "Область:" + }, + "abCard.OtherZip": { + "message": "Почтовый индекс:" + }, + "abCard.RadioPhoneNumber": { + "message": "Радиотелефон:" + }, + "abCard.Spouse": { + "message": "Супруг:" + }, + "abCard.header.eas": { + "message": "Другие поля (EAS)" + }, + "abCard.header.homenumbers": { + "message": "Дополнительные домашние номера:" + }, + "abCard.header.messaging": { + "message": "Мессенджер:" + }, + "abCard.header.otheraddress": { + "message": "Другой адрес (EAS)" + }, + "abCard.header.othernumbers": { + "message": "Дополнительные номера:" + }, + "abCard.header.people": { + "message": "Люди:" + }, + "abCard.header.worknumbers": { + "message": "Дополнительные рабочие номера:" + }, + "acl.readonly": { + "message": "Доступ к серверу только для чтения (отменить локальные изменения)" + }, + "acl.readwrite": { + "message": "Читать и писать на сервер" + }, + "add.description": { + "message": "Пожалуйста, выберите один из доступных параметров конфигурации сервера и введите требуемую информацию. " + }, + "add.name": { + "message": "Имя аккаунта:" + }, + "add.ok": { + "message": "Добавить аккаунт" + }, + "add.password": { + "message": "Пароль:" + }, + "add.server": { + "message": "Конфигурация сервера:" + }, + "add.shortdescription": { + "message": "Информация об учетной записи" + }, + "add.title": { + "message": "Добавить Exchange ActiveSync аккаунт для TbSync" + }, + "add.url": { + "message": "Адрес сервера:" + }, + "add.urldescription": { + "message": "Достаточно указать только базовый адрес сервера (например: mail.yourserver.com). Однако также можно указать полный URL-адрес (например: https://mail.yourserver.com/Microsoft-Server-ActiveSync)." + }, + "add.user": { + "message": "Имя пользователя (email адрес):" + }, + "autocomplete.serverdirectory": { + "message": "глобальный каталог сервера" + }, + "autodiscover.Failed": { + "message": "Автообнаружение для пользователя <##user##> не удалось. Либо предоставленные учетные данные были неправильными, либо у вашего провайдера ActiveSync была временная проблема, или не поддерживается автообнаружение." + }, + "autodiscover.NeedEmail": { + "message": "Автообнаружению нужен действительный адрес электронной почты в качестве имени пользователя." + }, + "autodiscover.Ok": { + "message": "Автообнаружение успешно завершено, теперь вы можете проверить дополнительные настройки и установить соединение синхронизации." + }, + "autodiscover.Querying": { + "message": "Поиск настроек…" + }, + "config.auto": { + "message": "ActiveSync конфигурация сервера (Автообнаружение)" + }, + "config.custom": { + "message": "ActiveSync конфигурация сервера" + }, + "deletefolder.confirm": { + "message": "Вы действительно хотите ПЕРМАНЕНТНО ВЫЧИСТИТЬ папку “##replace.1##” из корзины?" + }, + "deletefolder.menuentry": { + "message": "Перманентно вычистить папку “##replace.1##” из корзины" + }, + "deletefolder.notallowed": { + "message": "Откажитесь от подписки папки “##replace.1##” прежде чем пытаться очистить ее от мусора." + }, + "extensionDescription": { + "message": "Добавляет в TbSync поддержку синхронизации для учетных записей Exchange через базирующийся на http/https протокол ActiveSync (контакты, задачи и календари)." + }, + "extensionName": { + "message": "Provider for Exchange ActiveSync" + }, + "helplink.BadItemSkipped": { + "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped" + }, + "helplink.global.clientdenied": { + "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F" + }, + "helplink.security": { + "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F" + }, + "manager.tabs.accountsettings": { + "message": "Настройки аккаунта" + }, + "manager.tabs.outOfOffice": { + "message": "Автоответчик" + }, + "manager.tabs.syncsettings": { + "message": "Настройки синхронизации" + }, + "newaccount.add_auto": { + "message": "Настройки автообнаружения и добавление аккаунта" + }, + "newaccount.add_custom": { + "message": "Добавить аккаунт" + }, + "pref.AccountName": { + "message": "Имя аккаунта" + }, + "pref.ActiveSyncVersion": { + "message": "Версия ActiveSync" + }, + "pref.DeviceId": { + "message": "Идентификатор устройства" + }, + "pref.ServerName": { + "message": "Адрес сервера" + }, + "pref.ServerNameDescription": { + "message": "например: mail.yourserver.com" + }, + "pref.ShowTrashedFolders": { + "message": "Показывать папки, найденные в корзине" + }, + "pref.UserName": { + "message": "Имя пользователя" + }, + "pref.UserNameDescription": { + "message": "Имя пользователя обычно является адресом электронной почты вашей учетной записи." + }, + "pref.autodetect": { + "message": "лучшее из доступных" + }, + "pref.birthday": { + "message": "Отправить информацию о днях рождения" + }, + "pref.calendaroptions": { + "message": "Параметры календаря" + }, + "pref.contactoptions": { + "message": "Параметры контакта" + }, + "pref.displayoverride": { + "message": "Переопределить отображаемое имя с помощью “Имя” + “Фамилия”" + }, + "pref.generaloptions": { + "message": "Общие параметры" + }, + "pref.provision": { + "message": "Заставить поддерживать (требуется для Kerio)" + }, + "pref.seperator.comma": { + "message": "Запятая" + }, + "pref.seperator.description": { + "message": "Сепаратор для многострочного поля адреса." + }, + "pref.seperator.linebreak": { + "message": "Разрыв строки" + }, + "pref.synclimit.1month": { + "message": "от 4 недель назад" + }, + "pref.synclimit.2weeks": { + "message": "от 2 недель назад" + }, + "pref.synclimit.3month": { + "message": "от 3 месяцев назад" + }, + "pref.synclimit.6month": { + "message": "от 6 месяцев назад" + }, + "pref.synclimit.all": { + "message": "все" + }, + "pref.synclimit.description": { + "message": "Период синхронизации:" + }, + "pref.usehttps": { + "message": "Использовать безопасное соединение (соединение через https)" + }, + "recyclebin": { + "message": "Корзина" + }, + "servertype.auto": { + "message": "Автоматическая настройка" + }, + "servertype.custom": { + "message": "Ручная настройка" + }, + "servertype.description.auto": { + "message": "Для определения конфигурации множества серверов ActiveSync достаточно указать только адрес Вашей электронной почты." + }, + "servertype.description.custom": { + "message": "Настройте Вашу учетную запись, вручную указав адрес сервера, к которому Вы хотите подключиться." + }, + "servertype.description.office365": { + "message": "Учетные записи, подключенные к Office 365, используют современный процесс аутентификации под названием OAuth 2.0, который также поддерживает многофакторную аутентификацию (MFA)." + }, + "servertype.office365": { + "message": "Microsoft Office 365" + }, + "servertype.unlock": { + "message": "Дважды щелкните, чтобы разблокировать все предопределенные настройки сервера." + }, + "status.401": { + "message": "Не удалось аутентифицировать, проверить имя пользователя и пароль. (HTTP Ошибка 401)." + }, + "status.403": { + "message": "Сервер отклонил соединение (запрещено) (HTTP Ошибка 403)." + }, + "status.404": { + "message": "Пользователь не найден (HTTP Ошибка 404)." + }, + "status.449": { + "message": "Серверные запросы дублируются (HTTP Ошибка 449)." + }, + "status.500": { + "message": "Неизвестная ошибка сервера (HTTP Ошибка 500)." + }, + "status.503": { + "message": "Сервис недоступен (HTTP Ошибка 503)." + }, + "status.BadItemSkipped": { + "message": "Плохой элемент пропущен: ##replace.1##" + }, + "status.FolderDelete.3": { + "message": "Не удается удалить системную папку." + }, + "status.FolderDelete.4": { + "message": "Папка не существует (статус 4), повторная синхронизация" + }, + "status.FolderDelete.6": { + "message": "Команда не может быть выполнена, на сервере возникла ошибка." + }, + "status.FolderDelete.9": { + "message": "Неверный ключ синхронизации (статус 9), повторная синхронизация" + }, + "status.FolderSync.9": { + "message": "Неверный ключ синхронизации (статус 9), повторная синхронизация" + }, + "status.InvalidServerOptions": { + "message": "Сервер не предоставляет информацию о поддерживаемых версиях ActiveSync. EAS блокирован для этого пользователя или этого клиента (TbSync)? Вы можете попробовать установить версию ActiveSync вручную." + }, + "status.OK": { + "message": "Готово" + }, + "status.ServerRejectedRequest": { + "message": "Сервер EAS отклонил наш последний запрос." + }, + "status.ServerRejectedSomeItems": { + "message": "Сервер EAS не принял элементы ##replace.1##." + }, + "status.Sync.12": { + "message": "Изменена иерархия папок (статус 12), повторная синхронизация" + }, + "status.Sync.3": { + "message": "Неверный ключ синхронизации (статус 3), повторная синхронизация" + }, + "status.Sync.4": { + "message": "Неверный запрос (статус 4)" + }, + "status.Sync.5": { + "message": "Временные проблемы с сервером или недопустимый элемент (статус 5)" + }, + "status.Sync.6": { + "message": "Недопустимый элемент (статус 6)" + }, + "status.Sync.8": { + "message": "Объект не найден (статус 8)" + }, + "status.aborted": { + "message": "Не синхронизировано" + }, + "status.disabled": { + "message": "Аккаунт не включен, синхронизация отключена." + }, + "status.empty-response": { + "message": "Сервер отправляет неожиданный пустой ответ." + }, + "status.forbiddenCalendarItemInTasksFolder": { + "message": "Запрещенный элемент календаря в папке задач (пожалуйста, исправьте)" + }, + "status.forbiddenTasksItemInCalendarFolder": { + "message": "Запрещенный элемент задачи в папке календаря (пожалуйста, исправьте)" + }, + "status.global.101": { + "message": "Запрос содержит WBXML но он не может быть декодирован в XML (EAS Ошибка 101)." + }, + "status.global.102": { + "message": "Запрос содержит WBXML но он не может быть декодирован в XML (EAS Ошибка 102)." + }, + "status.global.103": { + "message": "XML, указанный в запросе, не соответствует требованиям протокола (EAS Ошибка 103)." + }, + "status.global.110": { + "message": "Сервер сообщил о внутренней ошибке, и мы не должны немедленно повторять попытку. Автоматическая периодическая синхронизация была отключена на 30 минут (Ошибка EAS 110)." + }, + "status.global.clientdenied": { + "message": "Отчеты сервера EAS <##replace.2##> (статус ##replace.1##) и не позволяют TbSync доступ к вашему аккаунту." + }, + "status.httperror": { + "message": "Ошибка связи (HTTP статус ##replace.1##)." + }, + "status.invalid": { + "message": "Недопустимый ответ сервера (мусор в обмене)." + }, + "status.malformed-xml": { + "message": "Не удалось разобрать XML. Проверьте журнал событий для деталей." + }, + "status.modified": { + "message": "Локальные изменения" + }, + "status.network": { + "message": "Не удалось подключиться к серверу (##replace.1##)." + }, + "status.networkerror": { + "message": "Не удалось подключиться к серверу." + }, + "status.nosupportedeasversion": { + "message": "Сервер не поддерживает ActiveSync v2.5 или v14.0 (только ##replace.1##). TbSync не будет работать с этим ActiveSync сервером." + }, + "status.notargets": { + "message": "Отмена синхронизации, поскольку цели синхронизации не могут быть созданы." + }, + "status.notsupportedeasversion": { + "message": "Сервер не поддерживает выбранный ActiveSync v##replace.1## (только ##replace.2##)." + }, + "status.notsyncronized": { + "message": "Аккаунт должен быть синхронизирован, по крайней мере один элемент не синхронизирован." + }, + "status.nouserhost": { + "message": "Отсутствует имя пользователя и/или сервера. Укажите эти значения." + }, + "status.pending": { + "message": "Ожидание пока синхронизируется" + }, + "status.policy.2": { + "message": "Для этого клиента нет политики. Обратитесь к администратору вашего сервера или отключите использование этого аккаунта." + }, + "status.policy.3": { + "message": "Неизвестное значение политики для этого клиента. Обратитесь к администратору вашего сервера или отключите использование этого аккаунта." + }, + "status.policy.4": { + "message": "Данные политики на сервере повреждены (возможно, подделаны). Обратитесь к администратору вашего сервера или отключите использование этого аккаунта." + }, + "status.policy.5": { + "message": "Клиент обнаружил неправильный ключ политики. Обратитесь к администратору вашего сервера или отключите использование этого аккаунта." + }, + "status.provision": { + "message": "Резервирование не удалось со статусом <##replace.1##>" + }, + "status.response-contains-no-data": { + "message": "Ответ от сервера не содержит данных." + }, + "status.resync-loop": { + "message": "Произошла ошибка, из-за которой не удалось пересинхронизировать аккаунт. Отключите аккаунт и повторите попытку. (Ошибка: повторная синхронизация)" + }, + "status.security": { + "message": "Не удалось установить безопасное соединение. Вы используете самоподписанный или ненадежный сертификат без импорта его в Thunderbird? (##replace.1##)" + }, + "status.skipped": { + "message": "Пока не поддерживается, пропущено" + }, + "status.syncing": { + "message": "Синхронизация" + }, + "status.timeout": { + "message": "Тайм-аут связи." + }, + "status.wbxml-parse-error": { + "message": "Сервер отправляет нечитаемый ответ." + }, + "status.wbxmlerror": { + "message": "Ошибка синхронизации. Сервер ответил статусом <##replace.1##>." + }, + "status.wbxmlmissingfield": { + "message": "ActiveSync протокол нарушен: Обязательное поле <##replace.1##> отсутствует в ответе сервера." + }, + "syncstate.accountdone": { + "message": "Завершенный аккаунт" + }, + "syncstate.done": { + "message": "Подготовка следующего элемента для синхронизации" + }, + "syncstate.eval.response.autodiscover": { + "message": "Обработка обновленных настроек сервера" + }, + "syncstate.eval.response.deletefolder": { + "message": "Папка удалена" + }, + "syncstate.eval.response.estimate": { + "message": "Обработка оценки изменений" + }, + "syncstate.eval.response.folders": { + "message": "Обработка обновления листа папок" + }, + "syncstate.eval.response.localchanges": { + "message": "Обработка подтверждения локальных изменений" + }, + "syncstate.eval.response.localdeletes": { + "message": "Обработка подтверждения локальных удалений" + }, + "syncstate.eval.response.options": { + "message": "Обработка настроек сервера" + }, + "syncstate.eval.response.provision": { + "message": "Обработка резервирования" + }, + "syncstate.eval.response.remotechanges": { + "message": "Обработка удаленных изменений" + }, + "syncstate.eval.response.revertlocalchanges": { + "message": "Откат локальных изменений" + }, + "syncstate.eval.response.setdeviceinfo": { + "message": "Обработка информации об устройстве" + }, + "syncstate.eval.response.synckey": { + "message": "Обработка элементов синхронизации" + }, + "syncstate.prepare.request.autodiscover": { + "message": "Запрос обновленных настроек сервера" + }, + "syncstate.prepare.request.deletefolder": { + "message": "Подготовка к удалению папки" + }, + "syncstate.prepare.request.estimate": { + "message": "Запрос оценки изменения" + }, + "syncstate.prepare.request.folders": { + "message": "Отправка обновления листа папок" + }, + "syncstate.prepare.request.localchanges": { + "message": "Отправка локальных изменений" + }, + "syncstate.prepare.request.localdeletes": { + "message": "Отправка локальных удалений" + }, + "syncstate.prepare.request.options": { + "message": "Запрос настроек сервера" + }, + "syncstate.prepare.request.provision": { + "message": "Запрос для резервирования" + }, + "syncstate.prepare.request.remotechanges": { + "message": "Запрос удаленных изменений" + }, + "syncstate.prepare.request.revertlocalchanges": { + "message": "Сбор локальных изменений" + }, + "syncstate.prepare.request.setdeviceinfo": { + "message": "Обработка информации об устройстве" + }, + "syncstate.prepare.request.synckey": { + "message": "Запрос элементов синхронизации" + }, + "syncstate.preparing": { + "message": "Подготовка следующего элемента для синхронизации" + }, + "syncstate.send.request.autodiscover": { + "message": "Ожидание обновленных настроек сервера" + }, + "syncstate.send.request.deletefolder": { + "message": "Ожидание удаления папки" + }, + "syncstate.send.request.estimate": { + "message": "Ожидание оценки изменений" + }, + "syncstate.send.request.folders": { + "message": "Ожидание обновления листа папок" + }, + "syncstate.send.request.localchanges": { + "message": "Ожидание подтверждения локальных изменений" + }, + "syncstate.send.request.localdeletes": { + "message": "Ожидание подтверждения локальных удалений" + }, + "syncstate.send.request.options": { + "message": "Ожидание настроек сервера" + }, + "syncstate.send.request.provision": { + "message": "Ожидание резервирования" + }, + "syncstate.send.request.remotechanges": { + "message": "Ожидание удаленных изменений" + }, + "syncstate.send.request.revertlocalchanges": { + "message": "Ожидание самых последних версий" + }, + "syncstate.send.request.setdeviceinfo": { + "message": "Обработка информации об устройстве" + }, + "syncstate.send.request.synckey": { + "message": "Ожидание элементов синхронизации" + }, + "syncstate.syncing": { + "message": "Инициализация синхронизации" + } +} diff -Nru eas4tbsync-4.11/api/EAS4TbSync/implementation.js eas4tbsync-4.17/api/EAS4TbSync/implementation.js --- eas4tbsync-4.11/api/EAS4TbSync/implementation.js 1970-01-01 00:00:00.000000000 +0000 +++ eas4tbsync-4.17/api/EAS4TbSync/implementation.js 2025-05-15 11:21:20.000000000 +0000 @@ -0,0 +1,74 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +// Using a closure to not leak anything but the API to the outside world. +(function (exports) { + + const { ExtensionParent } = ChromeUtils.importESModule( + "resource://gre/modules/ExtensionParent.sys.mjs" + ); + + async function observeTbSyncInitialized(aSubject, aTopic, aData) { + try { + const tbsyncExtension = ExtensionParent.GlobalManager.getExtension( + "tbsync@jobisoft.de" + ); + const { TbSync } = ChromeUtils.importESModule( + `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}` + ); + // Load this provider add-on into TbSync + if (TbSync.enabled) { + const easExtension = ExtensionParent.GlobalManager.getExtension( + "eas4tbsync@jobisoft.de" + ); + console.log(`Registering EAS provider v${easExtension.manifest.version} with TbSync v${tbsyncExtension.manifest.version}`); + await TbSync.providers.loadProvider(easExtension, "eas", "chrome://eas4tbsync/content/provider.js"); + } + } catch (e) { + // If this fails, TbSync is not loaded yet and we will get the notification later again. + } + + } + + var EAS4TbSync = class extends ExtensionCommon.ExtensionAPI { + + getAPI(context) { + return { + EAS4TbSync: { + async load() { + Services.obs.addObserver(observeTbSyncInitialized, "tbsync.observer.initialized", false); + + // Did we miss the observer? + observeTbSyncInitialized(); + } + }, + }; + } + + onShutdown(isAppShutdown) { + if (isAppShutdown) { + return; // the application gets unloaded anyway + } + + Services.obs.removeObserver(observeTbSyncInitialized, "tbsync.observer.initialized"); + //unload this provider add-on from TbSync + try { + const tbsyncExtension = ExtensionParent.GlobalManager.getExtension( + "tbsync@jobisoft.de" + ); + const { TbSync } = ChromeUtils.importESModule( + `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}` + ); + TbSync.providers.unloadProvider("eas"); + } catch (e) { + //if this fails, TbSync has been unloaded already and has unloaded this addon as well + } + } + }; + exports.EAS4TbSync = EAS4TbSync; +})(this); \ No newline at end of file diff -Nru eas4tbsync-4.11/api/EAS4TbSync/schema.json eas4tbsync-4.17/api/EAS4TbSync/schema.json --- eas4tbsync-4.11/api/EAS4TbSync/schema.json 1970-01-01 00:00:00.000000000 +0000 +++ eas4tbsync-4.17/api/EAS4TbSync/schema.json 2025-05-15 11:21:20.000000000 +0000 @@ -0,0 +1,13 @@ +[ + { + "namespace": "EAS4TbSync", + "functions": [ + { + "name": "load", + "type": "function", + "async": true, + "parameters": [] + } + ] + } +] \ No newline at end of file diff -Nru eas4tbsync-4.11/api/LegacyHelper/README.md eas4tbsync-4.17/api/LegacyHelper/README.md --- eas4tbsync-4.11/api/LegacyHelper/README.md 1970-01-01 00:00:00.000000000 +0000 +++ eas4tbsync-4.17/api/LegacyHelper/README.md 2025-05-15 11:21:20.000000000 +0000 @@ -0,0 +1,50 @@ +## Objective + +This API is a temporary helper while converting legacy extensions to modern WebExtensions. It allows to register `resource://` URLs, which are needed to load custom system modules (*.sys.mjs), and `chrome://` URLs, which are needed to open legacy XUL dialogs. + +## Usage + +Add the [LegacyHelper API](https://github.com/thunderbird/webext-support/tree/master/experiments/LegacyHelper) to your add-on. Your `manifest.json` needs an entry like this: + +```json + "experiment_apis": { + "LegacyHelper": { + "schema": "api/LegacyHelper/schema.json", + "parent": { + "scopes": ["addon_parent"], + "paths": [["LegacyHelper"]], + "script": "api/LegacyHelper/implementation.js" + } + } + }, +``` + +## API Functions + +This API provides the following functions: + +### async registerGlobalUrls(data) + +Register `chrome://*/content/` and `resource://*/` URLs. The function accepts a `data` parameter, which is an array of URL definition items. For example: + +```javascript +await browser.LegacyHelper.registerGlobalUrls([ + ["content", "myaddon", "chrome/content/"], + ["resource", "myaddon", "modules/"], +]); +``` + +This registers the following URLs: +* `chrome://myaddon/content/` pointing to the `/chrome/content/` folder (the `/content/` part in the URL is fix and does not depend on the name of the folder it is pointing to) +* `resource://myaddon/` pointing to the `/modules/` folder. To register a `resource://` URL which points to the root folder, use `.` instead". + +### async openDialog(name, path) + +Open a XUL dialog. The `name` parameter is a unique name identifying the dialog. If the dialog with that name is already open, it will be focused instead of being re-opened. The `path` parameter is a `chrome://*/content/` URL pointing to the XUL dialog file (*.xul or *.xhtml). + +```javascript +browser.LegacyHelper.openDialog( + "XulAddonOptions", + "chrome://myaddon/content/options.xhtml" +); +``` diff -Nru eas4tbsync-4.11/api/LegacyHelper/implementation.js eas4tbsync-4.17/api/LegacyHelper/implementation.js --- eas4tbsync-4.11/api/LegacyHelper/implementation.js 1970-01-01 00:00:00.000000000 +0000 +++ eas4tbsync-4.17/api/LegacyHelper/implementation.js 2025-05-15 11:21:20.000000000 +0000 @@ -0,0 +1,118 @@ +/* + * This file is provided by the webext-support repository at + * https://github.com/thunderbird/webext-support + * + * Version 1.1 + * - registerGlobalUrls() is now async, to be able to properly await registration + * + * Version 1.0 + * - initial release + * + * Author: + * - John Bieling (john@thunderbird.net) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +// Using a closure to not leak anything but the API to the outside world. +(function (exports) { + + const aomStartup = Cc[ + "@mozilla.org/addons/addon-manager-startup;1" + ].getService(Ci.amIAddonManagerStartup); + const resProto = Cc[ + "@mozilla.org/network/protocol;1?name=resource" + ].getService(Ci.nsISubstitutingProtocolHandler); + + const chromeHandlers = []; + const resourceUrls = []; + + var LegacyHelper = class extends ExtensionCommon.ExtensionAPI { + getAPI(context) { + return { + LegacyHelper: { + registerGlobalUrls(data) { + const manifestURI = Services.io.newURI( + "manifest.json", + null, + context.extension.rootURI + ); + + for (let entry of data) { + // [ "resource", "shortname" , "path" ] + + switch (entry[0]) { + case "resource": + { + let uri = Services.io.newURI( + entry[2], + null, + context.extension.rootURI + ); + resProto.setSubstitutionWithFlags( + entry[1], + uri, + resProto.ALLOW_CONTENT_ACCESS + ); + resourceUrls.push(entry[1]); + } + break; + + case "content": + case "locale": + { + let handle = aomStartup.registerChrome( + manifestURI, + [entry] + ); + chromeHandlers.push(handle); + } + break; + + default: + console.warn(`LegacyHelper: Unsupported url type: ${entry[0]}`) + } + } + }, + + openDialog(name, path) { + let window = Services.wm.getMostRecentWindow("mail:3pane"); + window.openDialog( + path, + name, + "chrome,resizable,centerscreen" + ); + }, + }, + }; + } + + onShutdown(isAppShutdown) { + if (isAppShutdown) { + return; // the application gets unloaded anyway + } + + for (let chromeHandler of chromeHandlers) { + if (chromeHandler) { + chromeHandler.destruct(); + chromeHandler = null; + } + } + + for (let resourceUrl of resourceUrls) { + resProto.setSubstitution( + resourceUrl, + null + ); + } + + // Flush all caches. + Services.obs.notifyObservers(null, "startupcache-invalidate"); + } + }; + exports.LegacyHelper = LegacyHelper; +})(this); \ No newline at end of file diff -Nru eas4tbsync-4.11/api/LegacyHelper/schema.json eas4tbsync-4.17/api/LegacyHelper/schema.json --- eas4tbsync-4.11/api/LegacyHelper/schema.json 1970-01-01 00:00:00.000000000 +0000 +++ eas4tbsync-4.17/api/LegacyHelper/schema.json 2025-05-15 11:21:20.000000000 +0000 @@ -0,0 +1,42 @@ +[ + { + "namespace": "LegacyHelper", + "functions": [ + { + "name": "registerGlobalUrls", + "type": "function", + "async": true, + "description": "Register folders which should be available as legacy chrome:// urls or resource:// urls", + "parameters": [ + { + "name": "data", + "type": "array", + "items": { + "type": "array", + "items": { + "type": "string" + } + }, + "description": "Array of manifest url definitions (content, locale or resource)" + } + ] + }, + { + "name": "openDialog", + "type": "function", + "parameters": [ + { + "name": "name", + "type": "string", + "description": "name of the new dialog" + }, + { + "name": "path", + "type": "string", + "description": "path of the dialog to be opened" + } + ] + } + ] + } +] \ No newline at end of file diff -Nru eas4tbsync-4.11/background.js eas4tbsync-4.17/background.js --- eas4tbsync-4.11/background.js 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/background.js 2025-05-15 11:21:20.000000000 +0000 @@ -1,6 +1,5 @@ -async function main() { - await messenger.BootstrapLoader.registerChromeUrl([ ["content", "eas4tbsync", "content/"] ]); - await messenger.BootstrapLoader.registerBootstrapScript("chrome://eas4tbsync/content/bootstrap.js"); -} - -main(); +await browser.LegacyHelper.registerGlobalUrls([ + ["content", "eas4tbsync", "content/"], +]); + +await browser.EAS4TbSync.load(); diff -Nru eas4tbsync-4.11/beta-release-channel-update.json eas4tbsync-4.17/beta-release-channel-update.json --- eas4tbsync-4.11/beta-release-channel-update.json 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/beta-release-channel-update.json 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -{ - "addons": { - "eas4tbsync@jobisoft.de": { - "updates": [ - { "version": "%VERSION%", - "update_info_url": "https://github.com/jobisoft/EAS-4-TbSync/releases", - "update_link": "%LINK%", - "applications": { - "gecko": { "strict_min_version": "78.0" } } } - ] - } - } -} \ No newline at end of file diff -Nru eas4tbsync-4.11/content/api/BootstrapLoader/CHANGELOG.md eas4tbsync-4.17/content/api/BootstrapLoader/CHANGELOG.md --- eas4tbsync-4.11/content/api/BootstrapLoader/CHANGELOG.md 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/content/api/BootstrapLoader/CHANGELOG.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,75 +0,0 @@ -Version: 1.21 -------------- -- Explicitly set hasAddonManagerEventListeners flag to false on uninstall - -Version: 1.20 -------------- -- hard fork BootstrapLoader v1.19 implementation and continue to serve it for - Thunderbird 111 and older -- BootstrapLoader v1.20 has removed a lot of unnecessary code used for backward - compatibility - -Version: 1.19 -------------- -- fix race condition which could prevent the AOM tab to be monkey patched correctly - -Version: 1.18 -------------- -- be precise on which revision the wrench symbol should be displayed, instead of - the options button - -Version: 1.17 -------------- -- fix "ownerDoc.getElementById() is undefined" bug - -Version: 1.16 -------------- -- fix "tab.browser is undefined" bug - -Version 1.15 ------------- -- clear cache only if add-on is uninstalled/updated, not on app shutdown - -Version 1.14 ------------- -- fix for TB90 ("view-loaded" event) and TB78.10 (wrench icon for options) - -Version 1.13 ------------- -- removed notifyTools and move it into its own NotifyTools API - -Version 1.12 ------------- -- add support for notifyExperiment and onNotifyBackground - -Version 1.11 ------------- -- add openOptionsDialog() - -Version 1.10 ------------- -- fix for 68 - -Version 1.7 ------------ -- fix for beta 87 - -Version 1.6 ------------ -- add support for options button/menu in add-on manager and fix 68 double menu entry - -Version 1.5 ------------ -- fix for e10s - -Version 1.4 ------------ -- add registerOptionsPage - -Version 1.3 ------------ -- flush cache - -Version 1.2 ------------ -- add support for resource urls diff -Nru eas4tbsync-4.11/content/api/BootstrapLoader/README.md eas4tbsync-4.17/content/api/BootstrapLoader/README.md --- eas4tbsync-4.11/content/api/BootstrapLoader/README.md 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/content/api/BootstrapLoader/README.md 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -Usage description can be found in the [wiki](https://github.com/thundernest/addon-developer-support/wiki/Using-the-BootstrapLoader-API-to-convert-a-Legacy-Bootstrap-WebExtension-into-a-MailExtension-for-Thunderbird-78). diff -Nru eas4tbsync-4.11/content/api/BootstrapLoader/implementation.js eas4tbsync-4.17/content/api/BootstrapLoader/implementation.js --- eas4tbsync-4.11/content/api/BootstrapLoader/implementation.js 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/content/api/BootstrapLoader/implementation.js 1970-01-01 00:00:00.000000000 +0000 @@ -1,187 +0,0 @@ -/* - * This file is provided by the addon-developer-support repository at - * https://github.com/thundernest/addon-developer-support - * - * Version: 1.21 - * - * Author: John Bieling (john@thunderbird.net) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -// Get various parts of the WebExtension framework that we need. -var { ExtensionCommon } = ChromeUtils.import("resource://gre/modules/ExtensionCommon.jsm"); -var { ExtensionSupport } = ChromeUtils.import("resource:///modules/ExtensionSupport.jsm"); -var { AddonManager } = ChromeUtils.import("resource://gre/modules/AddonManager.jsm"); - -function getMessenger(context) { - let apis = ["storage", "runtime", "extension", "i18n"]; - - function getStorage() { - let localstorage = null; - try { - localstorage = context.apiCan.findAPIPath("storage"); - localstorage.local.get = (...args) => - localstorage.local.callMethodInParentProcess("get", args); - localstorage.local.set = (...args) => - localstorage.local.callMethodInParentProcess("set", args); - localstorage.local.remove = (...args) => - localstorage.local.callMethodInParentProcess("remove", args); - localstorage.local.clear = (...args) => - localstorage.local.callMethodInParentProcess("clear", args); - } catch (e) { - console.info("Storage permission is missing"); - } - return localstorage; - } - - let messenger = {}; - for (let api of apis) { - switch (api) { - case "storage": - ChromeUtils.defineLazyGetter(messenger, "storage", () => - getStorage() - ); - break; - - default: - ChromeUtils.defineLazyGetter(messenger, api, () => - context.apiCan.findAPIPath(api) - ); - } - } - return messenger; -} - -// Removed all extra code for backward compatibility for better maintainability. -var BootstrapLoader = class extends ExtensionCommon.ExtensionAPI { - getAPI(context) { - this.uniqueRandomID = "AddOnNS" + context.extension.instanceId; - this.menu_addonPrefs_id = "addonPrefs"; - - - this.pathToBootstrapScript = null; - this.chromeHandle = null; - this.chromeData = null; - this.bootstrappedObj = {}; - - // make the extension object and the messenger object available inside - // the bootstrapped scope - this.bootstrappedObj.extension = context.extension; - this.bootstrappedObj.messenger = getMessenger(this.context); - - this.BOOTSTRAP_REASONS = { - APP_STARTUP: 1, - APP_SHUTDOWN: 2, - ADDON_ENABLE: 3, - ADDON_DISABLE: 4, - ADDON_INSTALL: 5, - ADDON_UNINSTALL: 6, // not supported - ADDON_UPGRADE: 7, - ADDON_DOWNGRADE: 8, - }; - - const aomStartup = Cc["@mozilla.org/addons/addon-manager-startup;1"].getService(Ci.amIAddonManagerStartup); - const resProto = Cc["@mozilla.org/network/protocol;1?name=resource"].getService(Ci.nsISubstitutingProtocolHandler); - - let self = this; - - // TabMonitor to detect opening of tabs, to setup the options button in the add-on manager. - this.tabMonitor = { - onTabTitleChanged(tab) { }, - onTabClosing(tab) { }, - onTabPersist(tab) { }, - onTabRestored(tab) { }, - onTabSwitched(aNewTab, aOldTab) { }, - async onTabOpened(tab) { - if (tab.browser && tab.mode.name == "contentTab") { - let { setTimeout } = Services.wm.getMostRecentWindow("mail:3pane"); - // Instead of registering a load observer, wait until its loaded. Not nice, - // but gets aroud a lot of edge cases. - while (!tab.pageLoaded) { - await new Promise(r => setTimeout(r, 150)); - } - self.setupAddonManager(self.getAddonManagerFromTab(tab)); - } - }, - }; - - return { - BootstrapLoader: { - registerChromeUrl(data) { - let chromeData = []; - for (let entry of data) { - chromeData.push(entry) - } - - if (chromeData.length > 0) { - const manifestURI = Services.io.newURI( - "manifest.json", - null, - context.extension.rootURI - ); - self.chromeHandle = aomStartup.registerChrome(manifestURI, chromeData); - } - - self.chromeData = chromeData; - }, - - registerBootstrapScript: async function (aPath) { - self.pathToBootstrapScript = aPath.startsWith("chrome://") - ? aPath - : context.extension.rootURI.resolve(aPath); - - // Get the addon object belonging to this extension. - let addon = await AddonManager.getAddonByID(context.extension.id); - console.log(addon.id); - //make the addon globally available in the bootstrapped scope - self.bootstrappedObj.addon = addon; - - // add BOOTSTRAP_REASONS to scope - for (let reason of Object.keys(self.BOOTSTRAP_REASONS)) { - self.bootstrappedObj[reason] = self.BOOTSTRAP_REASONS[reason]; - } - - // Load registered bootstrap scripts and execute its startup() function. - try { - if (self.pathToBootstrapScript) Services.scriptloader.loadSubScript(self.pathToBootstrapScript, self.bootstrappedObj, "UTF-8"); - if (self.bootstrappedObj.startup) self.bootstrappedObj.startup.call(self.bootstrappedObj, self.extension.addonData, self.BOOTSTRAP_REASONS[self.extension.startupReason]); - } catch (e) { - Components.utils.reportError(e) - } - - } - } - }; - } - - onShutdown(isAppShutdown) { - if (isAppShutdown) { - return; // the application gets unloaded anyway - } - - - // Execute registered shutdown() - try { - if (this.bootstrappedObj.shutdown) { - this.bootstrappedObj.shutdown( - this.extension.addonData, - isAppShutdown - ? this.BOOTSTRAP_REASONS.APP_SHUTDOWN - : this.BOOTSTRAP_REASONS.ADDON_DISABLE); - } - } catch (e) { - Components.utils.reportError(e) - } - - if (this.chromeHandle) { - this.chromeHandle.destruct(); - this.chromeHandle = null; - } - // Flush all caches - Services.obs.notifyObservers(null, "startupcache-invalidate"); - console.log("BootstrapLoader for " + this.extension.id + " unloaded!"); - } -}; \ No newline at end of file diff -Nru eas4tbsync-4.11/content/api/BootstrapLoader/schema.json eas4tbsync-4.17/content/api/BootstrapLoader/schema.json --- eas4tbsync-4.11/content/api/BootstrapLoader/schema.json 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/content/api/BootstrapLoader/schema.json 1970-01-01 00:00:00.000000000 +0000 @@ -1,61 +0,0 @@ -[ - { - "namespace": "BootstrapLoader", - "functions": [ - { - "name": "registerOptionsPage", - "type": "function", - "parameters": [ - { - "name": "aPath", - "type": "string", - "description": "Path to the options page, which should be made accessible in the (legacy) Add-On Options menu." - } - ] - }, - { - "name": "openOptionsDialog", - "type": "function", - "parameters": [ - { - "name": "windowId", - "type": "integer", - "description": "Id of the window the dialog should be opened from." - } - ] - }, - { - "name": "registerChromeUrl", - "type": "function", - "description": "Register folders which should be available as chrome:// urls (as defined in the legacy chrome.manifest)", - "async": true, - "parameters": [ - { - "name": "chromeData", - "type": "array", - "items": { - "type": "array", - "items": { - "type": "string" - } - }, - "description": "Array of ChromeData Arrays." - } - ] - }, - { - "name": "registerBootstrapScript", - "type": "function", - "description": "Register a bootstrap.js style script", - "async": true, - "parameters": [ - { - "name": "aPath", - "type": "string", - "description": "Either the chrome:// path to the script or its relative location from the root of the extension," - } - ] - } - ] - } -] \ No newline at end of file diff -Nru eas4tbsync-4.11/content/bootstrap.js eas4tbsync-4.17/content/bootstrap.js --- eas4tbsync-4.11/content/bootstrap.js 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/content/bootstrap.js 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ -/* - * This file is part of EAS-4-TbSync. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -// no need to create namespace, we are in a sandbox - -let onInitDoneObserver = { - observe: async function (aSubject, aTopic, aData) { - let valid = false; - try { - var { TbSync } = ChromeUtils.import("chrome://tbsync/content/tbsync.jsm"); - valid = TbSync.enabled; - } catch (e) { - // If this fails, TbSync is not loaded yet and we will get the notification later again. - } - - //load this provider add-on into TbSync - if (valid) { - await TbSync.providers.loadProvider(extension, "eas", "chrome://eas4tbsync/content/provider.js"); - } - } -} - -function startup(data, reason) { - // Possible reasons: APP_STARTUP, ADDON_ENABLE, ADDON_INSTALL, ADDON_UPGRADE, or ADDON_DOWNGRADE. - - Services.obs.addObserver(onInitDoneObserver, "tbsync.observer.initialized", false); - - // Did we miss the observer? - onInitDoneObserver.observe(); -} - -function shutdown(data, reason) { - // Possible reasons: APP_STARTUP, ADDON_ENABLE, ADDON_INSTALL, ADDON_UPGRADE, or ADDON_DOWNGRADE. - - // When the application is shutting down we normally don't have to clean up. - if (reason == APP_SHUTDOWN) { - return; - } - - Services.obs.removeObserver(onInitDoneObserver, "tbsync.observer.initialized"); - //unload this provider add-on from TbSync - try { - var { TbSync } = ChromeUtils.import("chrome://tbsync/content/tbsync.jsm"); - TbSync.providers.unloadProvider("eas"); - } catch (e) { - //if this fails, TbSync has been unloaded already and has unloaded this addon as well - } -} diff -Nru eas4tbsync-4.11/content/includes/calendarsync.js eas4tbsync-4.17/content/includes/calendarsync.js --- eas4tbsync-4.11/content/includes/calendarsync.js 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/content/includes/calendarsync.js 2025-05-15 11:21:20.000000000 +0000 @@ -1,422 +1,430 @@ -/* - * This file is part of EAS-4-TbSync. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -"use strict"; - -var { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); - -XPCOMUtils.defineLazyModuleGetters(this, { - CalAlarm: "resource:///modules/CalAlarm.jsm", - CalAttachment: "resource:///modules/CalAttachment.jsm", - CalAttendee: "resource:///modules/CalAttendee.jsm", - CalEvent: "resource:///modules/CalEvent.jsm", - CalTodo: "resource:///modules/CalTodo.jsm", -}); - -var { TbSync } = ChromeUtils.import("chrome://tbsync/content/tbsync.jsm"); -const cal = TbSync.lightning.cal; -const ICAL = TbSync.lightning.ICAL; - -var Calendar = { - - // --------------------------------------------------------------------------- // - // Read WBXML and set Thunderbird item - // --------------------------------------------------------------------------- // - setThunderbirdItemFromWbxml: function (tbItem, data, id, syncdata, mode = "standard") { - - let item = tbItem instanceof TbSync.lightning.TbItem ? tbItem.nativeItem : tbItem; - - let asversion = syncdata.accountData.getAccountProperty("asversion"); - item.id = id; - eas.sync.setItemSubject(item, syncdata, data); - if (TbSync.prefs.getIntPref("log.userdatalevel") > 2) TbSync.dump("Processing " + mode + " calendar item", item.title + " (" + id + ")"); - - eas.sync.setItemLocation(item, syncdata, data); - eas.sync.setItemCategories(item, syncdata, data); - eas.sync.setItemBody(item, syncdata, data); - - //timezone - let stdOffset = eas.defaultTimezoneInfo.std.offset; - let dstOffset = eas.defaultTimezoneInfo.dst.offset; - let easTZ = new eas.tools.TimeZoneDataStructure(); - if (data.TimeZone) { - if (data.TimeZone == "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==") { - TbSync.dump("Recieve TZ", "No timezone data received, using local default timezone."); - } else { - //load timezone struct into EAS TimeZone object - easTZ.easTimeZone64 = data.TimeZone; - if (TbSync.prefs.getIntPref("log.userdatalevel") > 2) TbSync.dump("Recieve TZ", item.title + easTZ.toString()); - stdOffset = easTZ.utcOffset; - dstOffset = easTZ.daylightBias + easTZ.utcOffset; - } - } - let timezone = eas.tools.guessTimezoneByStdDstOffset(stdOffset, dstOffset, easTZ.standardName); - - if (data.StartTime) { - let utc = cal.createDateTime(data.StartTime); //format "19800101T000000Z" - UTC - item.startDate = utc.getInTimezone(timezone); - if (data.AllDayEvent && data.AllDayEvent == "1") { - item.startDate.timezone = (cal.dtz && cal.dtz.floating) ? cal.dtz.floating : cal.floating(); - item.startDate.isDate = true; - } - } - - if (data.EndTime) { - let utc = cal.createDateTime(data.EndTime); - item.endDate = utc.getInTimezone(timezone); - if (data.AllDayEvent && data.AllDayEvent == "1") { - item.endDate.timezone = (cal.dtz && cal.dtz.floating) ? cal.dtz.floating : cal.floating(); - item.endDate.isDate = true; - } - } - - //stamp time cannot be set and it is not needed, an updated version is only send to the server, if there was a change, so stamp will be updated - - - //EAS Reminder - item.clearAlarms(); - if (data.Reminder && data.StartTime) { - let alarm = new CalAlarm(); - alarm.related = Components.interfaces.calIAlarm.ALARM_RELATED_START; - alarm.offset = cal.createDuration(); - alarm.offset.inSeconds = (0-parseInt(data.Reminder)*60); - alarm.action ="DISPLAY"; - item.addAlarm(alarm); - - let alarmData = cal.alarms.calculateAlarmDate(item, alarm); - let startDate = cal.createDateTime(data.StartTime); - let nowDate = eas.tools.getNowUTC(); - if (startDate.compare(nowDate) < 0) { - // Mark alarm as ACK if in the past. - item.alarmLastAck = nowDate; - } - } - - eas.sync.mapEasPropertyToThunderbird ("BusyStatus", "TRANSP", data, item); - eas.sync.mapEasPropertyToThunderbird ("Sensitivity", "CLASS", data, item); - - if (data.ResponseType) { - //store original EAS value - item.setProperty("X-EAS-ResponseType", eas.xmltools.checkString(data.ResponseType, "0")); //some server send empty ResponseType ??? - } - - //Attendees - remove all Attendees and re-add the ones from XML - item.removeAllAttendees(); - if (data.Attendees && data.Attendees.Attendee) { - let att = []; - if (Array.isArray(data.Attendees.Attendee)) att = data.Attendees.Attendee; - else att.push(data.Attendees.Attendee); - for (let i = 0; i < att.length; i++) { - if (att[i].Email && eas.tools.isString(att[i].Email) && att[i].Name) { //req. - - let attendee = new CalAttendee(); - - //is this attendee the local EAS user? - let isSelf = (att[i].Email == syncdata.accountData.getAccountProperty("user")); - - attendee["id"] = cal.email.prependMailTo(att[i].Email); - attendee["commonName"] = att[i].Name; - //default is "FALSE", only if THIS attendee isSelf, use ResponseRequested (we cannot respond for other attendee) - ResponseType is not send back to the server, it is just a local information - attendee["rsvp"] = (isSelf && data.ResponseRequested) ? "TRUE" : "FALSE"; - - //not supported in 2.5 - switch (att[i].AttendeeType) { - case "1": //required - attendee["role"] = "REQ-PARTICIPANT"; - attendee["userType"] = "INDIVIDUAL"; - break; - case "2": //optional - attendee["role"] = "OPT-PARTICIPANT"; - attendee["userType"] = "INDIVIDUAL"; - break; - default : //resource or unknown - attendee["role"] = "NON-PARTICIPANT"; - attendee["userType"] = "RESOURCE"; - break; - } - - //not supported in 2.5 - if attendeeStatus is missing, check if this isSelf and there is a ResponseType - if (att[i].AttendeeStatus) - attendee["participationStatus"] = eas.sync.MAP_EAS2TB.ATTENDEESTATUS[att[i].AttendeeStatus]; - else if (isSelf && data.ResponseType) - attendee["participationStatus"] = eas.sync.MAP_EAS2TB.ATTENDEESTATUS[data.ResponseType]; - else - attendee["participationStatus"] = "NEEDS-ACTION"; - - // status : [NEEDS-ACTION, ACCEPTED, DECLINED, TENTATIVE, DELEGATED, COMPLETED, IN-PROCESS] - // rolemap : [REQ-PARTICIPANT, OPT-PARTICIPANT, NON-PARTICIPANT, CHAIR] - // typemap : [INDIVIDUAL, GROUP, RESOURCE, ROOM] - - // Add attendee to event - item.addAttendee(attendee); - } else { - TbSync.eventlog.add("info", syncdata, "Attendee without required name and/or email found. Skipped."); - } - } - } - - if (data.OrganizerName && data.OrganizerEmail && eas.tools.isString(data.OrganizerEmail)) { - //Organizer - let organizer = new CalAttendee(); - organizer.id = cal.email.prependMailTo(data.OrganizerEmail); - organizer.commonName = data.OrganizerName; - organizer.rsvp = "FALSE"; - organizer.role = "CHAIR"; - organizer.userType = null; - organizer.participationStatus = "ACCEPTED"; - organizer.isOrganizer = true; - item.organizer = organizer; - } - - eas.sync.setItemRecurrence(item, syncdata, data, timezone); - - // BusyStatus is always representing the status of the current user in terms of availability. - // It has nothing to do with the status of a meeting. The user could be just the organizer, but does not need to attend, so he would be free. - // The correct map is between BusyStatus and TRANSP (show time as avail, busy, unset) - // A new event always sets TRANSP to busy, so unset is indeed a good way to store Tentiative - // However: - // - EAS Meetingstatus only knows ACTIVE or CANCELLED, but not CONFIRMED or TENTATIVE - // - TB STATUS has UNSET, CONFIRMED, TENTATIVE, CANCELLED - // -> Special case: User sets BusyStatus to TENTIATIVE -> TRANSP is unset and also set STATUS to TENTATIVE - // The TB STATUS is the correct map for EAS Meetingstatus and should be unset, if it is not a meeting EXCEPT if set to TENTATIVE - let tbStatus = (data.BusyStatus && data.BusyStatus == "1" ? "TENTATIVE" : null); - - if (data.MeetingStatus) { - //store original EAS value - item.setProperty("X-EAS-MeetingStatus", data.MeetingStatus); - //bitwise representation for Meeting, Received, Cancelled: - let M = data.MeetingStatus & 0x1; - let R = data.MeetingStatus & 0x2; - let C = data.MeetingStatus & 0x4; - - // We can map M+C to TB STATUS (TENTATIVE, CONFIRMED, CANCELLED, unset). - if (M) { - if (C) tbStatus = "CANCELLED"; - else if (!tbStatus) tbStatus = "CONFIRMED"; // do not override "TENTIATIVE" - } - - //we can also use the R information, to update our fallbackOrganizerName - if (!R && data.OrganizerName) syncdata.target.calendar.setProperty("fallbackOrganizerName", data.OrganizerName); - } - - if (tbStatus) item.setProperty("STATUS", tbStatus) - else item.deleteProperty("STATUS"); - - //TODO: attachements (needs EAS 16.0!) - }, - - - - - - - - - - // --------------------------------------------------------------------------- // - //read TB event and return its data as WBXML - // --------------------------------------------------------------------------- // - getWbxmlFromThunderbirdItem: async function (tbItem, syncdata, isException = false) { - let item = tbItem instanceof TbSync.lightning.TbItem ? tbItem.nativeItem : tbItem; - - let asversion = syncdata.accountData.getAccountProperty("asversion"); - let wbxml = eas.wbxmltools.createWBXML("", syncdata.type); //init wbxml with "" and not with precodes, and set initial codepage - let nowDate = new Date(); - - /* - * We do not use ghosting, that means, if we do not include a value in CHANGE, it is removed from the server. - * However, this does not seem to work on all fields. Furthermore, we need to include any (empty) container to blank its childs. - */ - - //Order of tags taken from https://msdn.microsoft.com/en-us/library/dn338917(v=exchg.80).aspx - - //timezone - if (!isException) { - let easTZ = new eas.tools.TimeZoneDataStructure(); - - //if there is no end and no start (or both are floating) use default timezone info - let tzInfo = null; - if (item.startDate && item.startDate.timezone.tzid != "floating") tzInfo = eas.tools.getTimezoneInfo(item.startDate.timezone); - else if (item.endDate && item.endDate.timezone.tzid != "floating") tzInfo = eas.tools.getTimezoneInfo(item.endDate.timezone); - if (!tzInfo) tzInfo = eas.defaultTimezoneInfo; - - easTZ.utcOffset = tzInfo.std.offset; - easTZ.standardBias = 0; - easTZ.daylightBias = tzInfo.dst.offset - tzInfo.std.offset; - - easTZ.standardName = eas.ianaToWindowsTimezoneMap.hasOwnProperty(tzInfo.std.displayname) ? eas.ianaToWindowsTimezoneMap[tzInfo.std.displayname] : tzInfo.std.displayname; - easTZ.daylightName = eas.ianaToWindowsTimezoneMap.hasOwnProperty(tzInfo.dst.displayname) ? eas.ianaToWindowsTimezoneMap[tzInfo.dst.displayname] : tzInfo.dst.displayname; - - if (tzInfo.std.switchdate && tzInfo.dst.switchdate) { - easTZ.standardDate.wMonth = tzInfo.std.switchdate.month; - easTZ.standardDate.wDay = tzInfo.std.switchdate.weekOfMonth; - easTZ.standardDate.wDayOfWeek = tzInfo.std.switchdate.dayOfWeek; - easTZ.standardDate.wHour = tzInfo.std.switchdate.hour; - easTZ.standardDate.wMinute = tzInfo.std.switchdate.minute; - easTZ.standardDate.wSecond = tzInfo.std.switchdate.second; - - easTZ.daylightDate.wMonth = tzInfo.dst.switchdate.month; - easTZ.daylightDate.wDay = tzInfo.dst.switchdate.weekOfMonth; - easTZ.daylightDate.wDayOfWeek = tzInfo.dst.switchdate.dayOfWeek; - easTZ.daylightDate.wHour = tzInfo.dst.switchdate.hour; - easTZ.daylightDate.wMinute = tzInfo.dst.switchdate.minute; - easTZ.daylightDate.wSecond = tzInfo.dst.switchdate.second; - } - - wbxml.atag("TimeZone", easTZ.easTimeZone64); - if (TbSync.prefs.getIntPref("log.userdatalevel") > 2) TbSync.dump("Send TZ", item.title + easTZ.toString()); - } - - //AllDayEvent (for simplicity, we always send a value) - wbxml.atag("AllDayEvent", (item.startDate && item.startDate.isDate && item.endDate && item.endDate.isDate) ? "1" : "0"); - - //Body - wbxml.append(eas.sync.getItemBody(item, syncdata)); - - //BusyStatus (Free, Tentative, Busy) is taken from TRANSP (busy, free, unset=tentative) - //However if STATUS is set to TENTATIVE, overide TRANSP and set BusyStatus to TENTATIVE - if (item.hasProperty("STATUS") && item.getProperty("STATUS") == "TENTATIVE") { - wbxml.atag("BusyStatus","1"); - } else { - wbxml.atag("BusyStatus", eas.sync.mapThunderbirdPropertyToEas("TRANSP", "BusyStatus", item)); - } - - //Organizer - if (!isException) { - if (item.organizer && item.organizer.commonName) wbxml.atag("OrganizerName", item.organizer.commonName); - if (item.organizer && item.organizer.id) wbxml.atag("OrganizerEmail", cal.email.removeMailTo(item.organizer.id)); - } - - //DtStamp in UTC - wbxml.atag("DtStamp", item.stampTime ? eas.tools.getIsoUtcString(item.stampTime) : eas.tools.dateToBasicISOString(nowDate)); - - //EndTime in UTC - wbxml.atag("EndTime", item.endDate ? eas.tools.getIsoUtcString(item.endDate) : eas.tools.dateToBasicISOString(nowDate)); - - //Location - wbxml.atag("Location", (item.hasProperty("location")) ? item.getProperty("location") : ""); - - //EAS Reminder (TB getAlarms) - at least with zpush blanking by omitting works, horde does not work - let alarms = item.getAlarms({}); - if (alarms.length>0) { - - let reminder = -1; - if (alarms[0].offset !== null) { - reminder = 0 - alarms[0].offset.inSeconds/60; - } else if (item.startDate) { - let timeDiff =item.startDate.getInTimezone(eas.utcTimezone).subtractDate(alarms[0].alarmDate.getInTimezone(eas.utcTimezone)); - reminder = timeDiff.inSeconds/60; - TbSync.eventlog.add("info", syncdata, "Converting absolute alarm to relative alarm (not supported).", item.icalString); - } - if (reminder >= 0) wbxml.atag("Reminder", reminder.toString()); - else TbSync.eventlog.add("info", syncdata, "Droping alarm after start date (not supported).", item.icalString); - - } - - //Sensitivity (CLASS) - wbxml.atag("Sensitivity", eas.sync.mapThunderbirdPropertyToEas("CLASS", "Sensitivity", item)); - - //Subject (obmitting these, should remove them from the server - that does not work reliably, so we send blanks) - wbxml.atag("Subject", (item.title) ? item.title : ""); - - //StartTime in UTC - wbxml.atag("StartTime", item.startDate ? eas.tools.getIsoUtcString(item.startDate) : eas.tools.dateToBasicISOString(nowDate)); - - //UID (limit to 300) - //each TB event has an ID, which is used as EAS serverId - however there is a second UID in the ApplicationData - //since we do not have two different IDs to use, we use the same ID - if (!isException) { //docs say it would be allowed in exception in 2.5, but it does not work, if present - wbxml.atag("UID", item.id); - } - //IMPORTANT in EAS v16 it is no longer allowed to send a UID - //Only allowed in exceptions in v2.5 - - - //EAS MeetingStatus - // 0 (000) The event is an appointment, which has no attendees. - // 1 (001) The event is a meeting and the user is the meeting organizer. - // 3 (011) This event is a meeting, and the user is not the meeting organizer; the meeting was received from someone else. - // 5 (101) The meeting has been canceled and the user was the meeting organizer. - // 7 (111) The meeting has been canceled. The user was not the meeting organizer; the meeting was received from someone else - - //there are 3 fields; Meeting, Owner, Cancelled - //M can be reconstructed from #of attendees (looking at the old value is not wise, since it could have been changed) - //C can be reconstucted from TB STATUS - //O can be reconstructed by looking at the original value, or (if not present) by comparing EAS ownerID with TB ownerID - - let attendees = item.getAttendees(); - //if (!(isException && asversion == "2.5")) { //MeetingStatus is not supported in exceptions in EAS 2.5 - if (!isException) { //Exchange 2010 does not seem to support MeetingStatus at all in exceptions - if (attendees.length == 0) wbxml.atag("MeetingStatus", "0"); - else { - //get owner information - let isReceived = false; - if (item.hasProperty("X-EAS-MEETINGSTATUS")) isReceived = item.getProperty("X-EAS-MEETINGSTATUS") & 0x2; - else isReceived = (item.organizer && item.organizer.id && cal.email.removeMailTo(item.organizer.id) != syncdata.accountData.getAccountProperty("user")); - - //either 1,3,5 or 7 - if (item.hasProperty("STATUS") && item.getProperty("STATUS") == "CANCELLED") { - //either 5 or 7 - wbxml.atag("MeetingStatus", (isReceived ? "7" : "5")); - } else { - //either 1 or 3 - wbxml.atag("MeetingStatus", (isReceived ? "3" : "1")); - } - } - } - - //Attendees - let TB_responseType = null; - if (!(isException && asversion == "2.5")) { //attendees are not supported in exceptions in EAS 2.5 - if (attendees.length > 0) { //We should use it instead of countAttendees.value - wbxml.otag("Attendees"); - for (let attendee of attendees) { - wbxml.otag("Attendee"); - wbxml.atag("Email", cal.email.removeMailTo(attendee.id)); - wbxml.atag("Name", (attendee.commonName ? attendee.commonName : cal.email.removeMailTo(attendee.id).split("@")[0])); - if (asversion != "2.5") { - //it's pointless to send AttendeeStatus, - // - if we are the owner of a meeting, TB does not have an option to actually set the attendee status (on behalf of an attendee) in the UI - // - if we are an attendee (of an invite) we cannot and should not set status of other attendees and or own status must be send through a MeetingResponse - // -> all changes of attendee status are send from the server to us, either via ResponseType or via AttendeeStatus - //wbxml.atag("AttendeeStatus", eas.sync.MAP_TB2EAS.ATTENDEESTATUS[attendee.participationStatus]); - - if (attendee.userType == "RESOURCE" || attendee.userType == "ROOM" || attendee.role == "NON-PARTICIPANT") wbxml.atag("AttendeeType","3"); - else if (attendee.role == "REQ-PARTICIPANT" || attendee.role == "CHAIR") wbxml.atag("AttendeeType","1"); - else wbxml.atag("AttendeeType","2"); //leftovers are optional - } - wbxml.ctag(); - } - wbxml.ctag(); - } else { - wbxml.atag("Attendees"); - } - } - - //Categories (see https://github.com/jobisoft/TbSync/pull/35#issuecomment-359286374) - if (!isException) { - wbxml.append(eas.sync.getItemCategories(item, syncdata)); - } - - //recurrent events (implemented by Chris Allan) - if (!isException) { - wbxml.append(await eas.sync.getItemRecurrence(item, syncdata)); - } - - - //--------------------------- - - //TP PRIORITY (9=LOW, 5=NORMAL, 1=HIGH) not mapable to EAS Event - //TODO: attachements (needs EAS 16.0!) - - //https://dxr.mozilla.org/comm-central/source/calendar/base/public/calIAlarm.idl - //TbSync.dump("ALARM ("+i+")", [, alarms[i].related, alarms[i].repeat, alarms[i].repeatOffset, alarms[i].repeatDate, alarms[i].action].join("|")); - - return wbxml.getBytes(); - } -} +/* + * This file is part of EAS-4-TbSync. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +ChromeUtils.defineESModuleGetters(this, { + CalAlarm: "resource:///modules/CalAlarm.sys.mjs", + CalAttachment: "resource:///modules/CalAttachment.sys.mjs", + CalAttendee: "resource:///modules/CalAttendee.sys.mjs", + CalEvent: "resource:///modules/CalEvent.sys.mjs", + CalTodo: "resource:///modules/CalTodo.sys.mjs", +}); + +var { ExtensionParent } = ChromeUtils.importESModule( + "resource://gre/modules/ExtensionParent.sys.mjs" +); + +var tbsyncExtension = ExtensionParent.GlobalManager.getExtension( + "tbsync@jobisoft.de" +); +var { TbSync } = ChromeUtils.importESModule( + `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}` +); + +const cal = TbSync.lightning.cal; +const ICAL = TbSync.lightning.ICAL; + +var Calendar = { + + // --------------------------------------------------------------------------- // + // Read WBXML and set Thunderbird item + // --------------------------------------------------------------------------- // + setThunderbirdItemFromWbxml: function (tbItem, data, id, syncdata, mode = "standard") { + + let item = tbItem instanceof TbSync.lightning.TbItem ? tbItem.nativeItem : tbItem; + + let asversion = syncdata.accountData.getAccountProperty("asversion"); + item.id = id; + eas.sync.setItemSubject(item, syncdata, data); + if (TbSync.prefs.getIntPref("log.userdatalevel") > 2) TbSync.dump("Processing " + mode + " calendar item", item.title + " (" + id + ")"); + + eas.sync.setItemLocation(item, syncdata, data); + eas.sync.setItemCategories(item, syncdata, data); + eas.sync.setItemBody(item, syncdata, data); + + //timezone + let stdOffset = eas.defaultTimezoneInfo.std.offset; + let dstOffset = eas.defaultTimezoneInfo.dst.offset; + let easTZ = new eas.tools.TimeZoneDataStructure(); + if (data.TimeZone) { + if (data.TimeZone == "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==") { + TbSync.dump("Recieve TZ", "No timezone data received, using local default timezone."); + } else { + //load timezone struct into EAS TimeZone object + easTZ.easTimeZone64 = data.TimeZone; + if (TbSync.prefs.getIntPref("log.userdatalevel") > 2) TbSync.dump("Recieve TZ", item.title + easTZ.toString()); + stdOffset = easTZ.utcOffset; + dstOffset = easTZ.daylightBias + easTZ.utcOffset; + } + } + let timezone = eas.tools.guessTimezoneByStdDstOffset(stdOffset, dstOffset, easTZ.standardName); + + if (data.StartTime) { + let utc = cal.createDateTime(data.StartTime); //format "19800101T000000Z" - UTC + item.startDate = utc.getInTimezone(timezone); + if (data.AllDayEvent && data.AllDayEvent == "1") { + item.startDate.timezone = (cal.dtz && cal.dtz.floating) ? cal.dtz.floating : cal.floating(); + item.startDate.isDate = true; + } + } + + if (data.EndTime) { + let utc = cal.createDateTime(data.EndTime); + item.endDate = utc.getInTimezone(timezone); + if (data.AllDayEvent && data.AllDayEvent == "1") { + item.endDate.timezone = (cal.dtz && cal.dtz.floating) ? cal.dtz.floating : cal.floating(); + item.endDate.isDate = true; + } + } + + //stamp time cannot be set and it is not needed, an updated version is only send to the server, if there was a change, so stamp will be updated + + + //EAS Reminder + item.clearAlarms(); + if (data.Reminder && data.StartTime) { + let alarm = new CalAlarm(); + alarm.related = Components.interfaces.calIAlarm.ALARM_RELATED_START; + alarm.offset = cal.createDuration(); + alarm.offset.inSeconds = (0 - parseInt(data.Reminder) * 60); + alarm.action = "DISPLAY"; + item.addAlarm(alarm); + + let alarmData = cal.alarms.calculateAlarmDate(item, alarm); + let startDate = cal.createDateTime(data.StartTime); + let nowDate = eas.tools.getNowUTC(); + if (startDate.compare(nowDate) < 0) { + // Mark alarm as ACK if in the past. + item.alarmLastAck = nowDate; + } + } + + eas.sync.mapEasPropertyToThunderbird("BusyStatus", "TRANSP", data, item); + eas.sync.mapEasPropertyToThunderbird("Sensitivity", "CLASS", data, item); + + if (data.ResponseType) { + //store original EAS value + item.setProperty("X-EAS-ResponseType", eas.xmltools.checkString(data.ResponseType, "0")); //some server send empty ResponseType ??? + } + + //Attendees - remove all Attendees and re-add the ones from XML + item.removeAllAttendees(); + if (data.Attendees && data.Attendees.Attendee) { + let att = []; + if (Array.isArray(data.Attendees.Attendee)) att = data.Attendees.Attendee; + else att.push(data.Attendees.Attendee); + for (let i = 0; i < att.length; i++) { + if (att[i].Email && eas.tools.isString(att[i].Email) && att[i].Name) { //req. + + let attendee = new CalAttendee(); + + //is this attendee the local EAS user? + let isSelf = (att[i].Email == syncdata.accountData.getAccountProperty("user")); + + attendee["id"] = cal.email.prependMailTo(att[i].Email); + attendee["commonName"] = att[i].Name; + //default is "FALSE", only if THIS attendee isSelf, use ResponseRequested (we cannot respond for other attendee) - ResponseType is not send back to the server, it is just a local information + attendee["rsvp"] = (isSelf && data.ResponseRequested) ? "TRUE" : "FALSE"; + + //not supported in 2.5 + switch (att[i].AttendeeType) { + case "1": //required + attendee["role"] = "REQ-PARTICIPANT"; + attendee["userType"] = "INDIVIDUAL"; + break; + case "2": //optional + attendee["role"] = "OPT-PARTICIPANT"; + attendee["userType"] = "INDIVIDUAL"; + break; + default: //resource or unknown + attendee["role"] = "NON-PARTICIPANT"; + attendee["userType"] = "RESOURCE"; + break; + } + + //not supported in 2.5 - if attendeeStatus is missing, check if this isSelf and there is a ResponseType + if (att[i].AttendeeStatus) + attendee["participationStatus"] = eas.sync.MAP_EAS2TB.ATTENDEESTATUS[att[i].AttendeeStatus]; + else if (isSelf && data.ResponseType) + attendee["participationStatus"] = eas.sync.MAP_EAS2TB.ATTENDEESTATUS[data.ResponseType]; + else + attendee["participationStatus"] = "NEEDS-ACTION"; + + // status : [NEEDS-ACTION, ACCEPTED, DECLINED, TENTATIVE, DELEGATED, COMPLETED, IN-PROCESS] + // rolemap : [REQ-PARTICIPANT, OPT-PARTICIPANT, NON-PARTICIPANT, CHAIR] + // typemap : [INDIVIDUAL, GROUP, RESOURCE, ROOM] + + // Add attendee to event + item.addAttendee(attendee); + } else { + TbSync.eventlog.add("info", syncdata, "Attendee without required name and/or email found. Skipped."); + } + } + } + + if (data.OrganizerName && data.OrganizerEmail && eas.tools.isString(data.OrganizerEmail)) { + //Organizer + let organizer = new CalAttendee(); + organizer.id = cal.email.prependMailTo(data.OrganizerEmail); + organizer.commonName = data.OrganizerName; + organizer.rsvp = "FALSE"; + organizer.role = "CHAIR"; + organizer.userType = null; + organizer.participationStatus = "ACCEPTED"; + organizer.isOrganizer = true; + item.organizer = organizer; + } + + eas.sync.setItemRecurrence(item, syncdata, data, timezone); + + // BusyStatus is always representing the status of the current user in terms of availability. + // It has nothing to do with the status of a meeting. The user could be just the organizer, but does not need to attend, so he would be free. + // The correct map is between BusyStatus and TRANSP (show time as avail, busy, unset) + // A new event always sets TRANSP to busy, so unset is indeed a good way to store Tentiative + // However: + // - EAS Meetingstatus only knows ACTIVE or CANCELLED, but not CONFIRMED or TENTATIVE + // - TB STATUS has UNSET, CONFIRMED, TENTATIVE, CANCELLED + // -> Special case: User sets BusyStatus to TENTIATIVE -> TRANSP is unset and also set STATUS to TENTATIVE + // The TB STATUS is the correct map for EAS Meetingstatus and should be unset, if it is not a meeting EXCEPT if set to TENTATIVE + let tbStatus = (data.BusyStatus && data.BusyStatus == "1" ? "TENTATIVE" : null); + + if (data.MeetingStatus) { + //store original EAS value + item.setProperty("X-EAS-MeetingStatus", data.MeetingStatus); + //bitwise representation for Meeting, Received, Cancelled: + let M = data.MeetingStatus & 0x1; + let R = data.MeetingStatus & 0x2; + let C = data.MeetingStatus & 0x4; + + // We can map M+C to TB STATUS (TENTATIVE, CONFIRMED, CANCELLED, unset). + if (M) { + if (C) tbStatus = "CANCELLED"; + else if (!tbStatus) tbStatus = "CONFIRMED"; // do not override "TENTIATIVE" + } + + //we can also use the R information, to update our fallbackOrganizerName + if (!R && data.OrganizerName) syncdata.target.calendar.setProperty("fallbackOrganizerName", data.OrganizerName); + } + + if (tbStatus) item.setProperty("STATUS", tbStatus) + else item.deleteProperty("STATUS"); + + //TODO: attachements (needs EAS 16.0!) + }, + + + + + + + + + + // --------------------------------------------------------------------------- // + //read TB event and return its data as WBXML + // --------------------------------------------------------------------------- // + getWbxmlFromThunderbirdItem: async function (tbItem, syncdata, isException = false) { + let item = tbItem instanceof TbSync.lightning.TbItem ? tbItem.nativeItem : tbItem; + + let asversion = syncdata.accountData.getAccountProperty("asversion"); + let wbxml = eas.wbxmltools.createWBXML("", syncdata.type); //init wbxml with "" and not with precodes, and set initial codepage + let nowDate = new Date(); + + /* + * We do not use ghosting, that means, if we do not include a value in CHANGE, it is removed from the server. + * However, this does not seem to work on all fields. Furthermore, we need to include any (empty) container to blank its childs. + */ + + //Order of tags taken from https://msdn.microsoft.com/en-us/library/dn338917(v=exchg.80).aspx + + //timezone + if (!isException) { + let easTZ = new eas.tools.TimeZoneDataStructure(); + + //if there is no end and no start (or both are floating) use default timezone info + let tzInfo = null; + if (item.startDate && item.startDate.timezone.tzid != "floating") tzInfo = eas.tools.getTimezoneInfo(item.startDate.timezone); + else if (item.endDate && item.endDate.timezone.tzid != "floating") tzInfo = eas.tools.getTimezoneInfo(item.endDate.timezone); + if (!tzInfo) tzInfo = eas.defaultTimezoneInfo; + + easTZ.utcOffset = tzInfo.std.offset; + easTZ.standardBias = 0; + easTZ.daylightBias = tzInfo.dst.offset - tzInfo.std.offset; + + easTZ.standardName = eas.ianaToWindowsTimezoneMap.hasOwnProperty(tzInfo.std.displayname) ? eas.ianaToWindowsTimezoneMap[tzInfo.std.displayname] : tzInfo.std.displayname; + easTZ.daylightName = eas.ianaToWindowsTimezoneMap.hasOwnProperty(tzInfo.dst.displayname) ? eas.ianaToWindowsTimezoneMap[tzInfo.dst.displayname] : tzInfo.dst.displayname; + + if (tzInfo.std.switchdate && tzInfo.dst.switchdate) { + easTZ.standardDate.wMonth = tzInfo.std.switchdate.month; + easTZ.standardDate.wDay = tzInfo.std.switchdate.weekOfMonth; + easTZ.standardDate.wDayOfWeek = tzInfo.std.switchdate.dayOfWeek; + easTZ.standardDate.wHour = tzInfo.std.switchdate.hour; + easTZ.standardDate.wMinute = tzInfo.std.switchdate.minute; + easTZ.standardDate.wSecond = tzInfo.std.switchdate.second; + + easTZ.daylightDate.wMonth = tzInfo.dst.switchdate.month; + easTZ.daylightDate.wDay = tzInfo.dst.switchdate.weekOfMonth; + easTZ.daylightDate.wDayOfWeek = tzInfo.dst.switchdate.dayOfWeek; + easTZ.daylightDate.wHour = tzInfo.dst.switchdate.hour; + easTZ.daylightDate.wMinute = tzInfo.dst.switchdate.minute; + easTZ.daylightDate.wSecond = tzInfo.dst.switchdate.second; + } + + wbxml.atag("TimeZone", easTZ.easTimeZone64); + if (TbSync.prefs.getIntPref("log.userdatalevel") > 2) TbSync.dump("Send TZ", item.title + easTZ.toString()); + } + + //AllDayEvent (for simplicity, we always send a value) + wbxml.atag("AllDayEvent", (item.startDate && item.startDate.isDate && item.endDate && item.endDate.isDate) ? "1" : "0"); + + //Body + wbxml.append(eas.sync.getItemBody(item, syncdata)); + + //BusyStatus (Free, Tentative, Busy) is taken from TRANSP (busy, free, unset=tentative) + //However if STATUS is set to TENTATIVE, overide TRANSP and set BusyStatus to TENTATIVE + if (item.hasProperty("STATUS") && item.getProperty("STATUS") == "TENTATIVE") { + wbxml.atag("BusyStatus", "1"); + } else { + wbxml.atag("BusyStatus", eas.sync.mapThunderbirdPropertyToEas("TRANSP", "BusyStatus", item)); + } + + //Organizer + if (!isException) { + if (item.organizer && item.organizer.commonName) wbxml.atag("OrganizerName", item.organizer.commonName); + if (item.organizer && item.organizer.id) wbxml.atag("OrganizerEmail", cal.email.removeMailTo(item.organizer.id)); + } + + //DtStamp in UTC + wbxml.atag("DtStamp", item.stampTime ? eas.tools.getIsoUtcString(item.stampTime) : eas.tools.dateToBasicISOString(nowDate)); + + //EndTime in UTC + wbxml.atag("EndTime", item.endDate ? eas.tools.getIsoUtcString(item.endDate) : eas.tools.dateToBasicISOString(nowDate)); + + //Location + wbxml.atag("Location", (item.hasProperty("location")) ? item.getProperty("location") : ""); + + //EAS Reminder (TB getAlarms) - at least with zpush blanking by omitting works, horde does not work + let alarms = item.getAlarms({}); + if (alarms.length > 0) { + + let reminder = -1; + if (alarms[0].offset !== null) { + reminder = 0 - alarms[0].offset.inSeconds / 60; + } else if (item.startDate) { + let timeDiff = item.startDate.getInTimezone(eas.utcTimezone).subtractDate(alarms[0].alarmDate.getInTimezone(eas.utcTimezone)); + reminder = timeDiff.inSeconds / 60; + TbSync.eventlog.add("info", syncdata, "Converting absolute alarm to relative alarm (not supported).", item.icalString); + } + if (reminder >= 0) wbxml.atag("Reminder", reminder.toString()); + else TbSync.eventlog.add("info", syncdata, "Droping alarm after start date (not supported).", item.icalString); + + } + + //Sensitivity (CLASS) + wbxml.atag("Sensitivity", eas.sync.mapThunderbirdPropertyToEas("CLASS", "Sensitivity", item)); + + //Subject (obmitting these, should remove them from the server - that does not work reliably, so we send blanks) + wbxml.atag("Subject", (item.title) ? item.title : ""); + + //StartTime in UTC + wbxml.atag("StartTime", item.startDate ? eas.tools.getIsoUtcString(item.startDate) : eas.tools.dateToBasicISOString(nowDate)); + + //UID (limit to 300) + //each TB event has an ID, which is used as EAS serverId - however there is a second UID in the ApplicationData + //since we do not have two different IDs to use, we use the same ID + if (!isException) { //docs say it would be allowed in exception in 2.5, but it does not work, if present + wbxml.atag("UID", item.id); + } + //IMPORTANT in EAS v16 it is no longer allowed to send a UID + //Only allowed in exceptions in v2.5 + + + //EAS MeetingStatus + // 0 (000) The event is an appointment, which has no attendees. + // 1 (001) The event is a meeting and the user is the meeting organizer. + // 3 (011) This event is a meeting, and the user is not the meeting organizer; the meeting was received from someone else. + // 5 (101) The meeting has been canceled and the user was the meeting organizer. + // 7 (111) The meeting has been canceled. The user was not the meeting organizer; the meeting was received from someone else + + //there are 3 fields; Meeting, Owner, Cancelled + //M can be reconstructed from #of attendees (looking at the old value is not wise, since it could have been changed) + //C can be reconstucted from TB STATUS + //O can be reconstructed by looking at the original value, or (if not present) by comparing EAS ownerID with TB ownerID + + let attendees = item.getAttendees(); + //if (!(isException && asversion == "2.5")) { //MeetingStatus is not supported in exceptions in EAS 2.5 + if (!isException) { //Exchange 2010 does not seem to support MeetingStatus at all in exceptions + if (attendees.length == 0) wbxml.atag("MeetingStatus", "0"); + else { + //get owner information + let isReceived = false; + if (item.hasProperty("X-EAS-MEETINGSTATUS")) isReceived = item.getProperty("X-EAS-MEETINGSTATUS") & 0x2; + else isReceived = (item.organizer && item.organizer.id && cal.email.removeMailTo(item.organizer.id) != syncdata.accountData.getAccountProperty("user")); + + //either 1,3,5 or 7 + if (item.hasProperty("STATUS") && item.getProperty("STATUS") == "CANCELLED") { + //either 5 or 7 + wbxml.atag("MeetingStatus", (isReceived ? "7" : "5")); + } else { + //either 1 or 3 + wbxml.atag("MeetingStatus", (isReceived ? "3" : "1")); + } + } + } + + //Attendees + let TB_responseType = null; + if (!(isException && asversion == "2.5")) { //attendees are not supported in exceptions in EAS 2.5 + if (attendees.length > 0) { //We should use it instead of countAttendees.value + wbxml.otag("Attendees"); + for (let attendee of attendees) { + wbxml.otag("Attendee"); + wbxml.atag("Email", cal.email.removeMailTo(attendee.id)); + wbxml.atag("Name", (attendee.commonName ? attendee.commonName : cal.email.removeMailTo(attendee.id).split("@")[0])); + if (asversion != "2.5") { + //it's pointless to send AttendeeStatus, + // - if we are the owner of a meeting, TB does not have an option to actually set the attendee status (on behalf of an attendee) in the UI + // - if we are an attendee (of an invite) we cannot and should not set status of other attendees and or own status must be send through a MeetingResponse + // -> all changes of attendee status are send from the server to us, either via ResponseType or via AttendeeStatus + //wbxml.atag("AttendeeStatus", eas.sync.MAP_TB2EAS.ATTENDEESTATUS[attendee.participationStatus]); + + if (attendee.userType == "RESOURCE" || attendee.userType == "ROOM" || attendee.role == "NON-PARTICIPANT") wbxml.atag("AttendeeType", "3"); + else if (attendee.role == "REQ-PARTICIPANT" || attendee.role == "CHAIR") wbxml.atag("AttendeeType", "1"); + else wbxml.atag("AttendeeType", "2"); //leftovers are optional + } + wbxml.ctag(); + } + wbxml.ctag(); + } else { + wbxml.atag("Attendees"); + } + } + + //Categories (see https://github.com/jobisoft/TbSync/pull/35#issuecomment-359286374) + if (!isException) { + wbxml.append(eas.sync.getItemCategories(item, syncdata)); + } + + //recurrent events (implemented by Chris Allan) + if (!isException) { + wbxml.append(await eas.sync.getItemRecurrence(item, syncdata)); + } + + + //--------------------------- + + //TP PRIORITY (9=LOW, 5=NORMAL, 1=HIGH) not mapable to EAS Event + //TODO: attachements (needs EAS 16.0!) + + //https://dxr.mozilla.org/comm-central/source/calendar/base/public/calIAlarm.idl + //TbSync.dump("ALARM ("+i+")", [, alarms[i].related, alarms[i].repeat, alarms[i].repeatOffset, alarms[i].repeatDate, alarms[i].action].join("|")); + + return wbxml.getBytes(); + } +} diff -Nru eas4tbsync-4.11/content/includes/contactsync.js eas4tbsync-4.17/content/includes/contactsync.js --- eas4tbsync-4.11/content/includes/contactsync.js 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/content/includes/contactsync.js 2025-05-15 11:21:20.000000000 +0000 @@ -1,551 +1,558 @@ -/* - * This file is part of EAS-4-TbSync. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - - "use strict"; - - var { XPCOMUtils } = ChromeUtils.import( - "resource://gre/modules/XPCOMUtils.jsm" -); - -XPCOMUtils.defineLazyModuleGetters(this, { - newUID: "resource:///modules/AddrBookUtils.jsm", - AddrBookCard: "resource:///modules/AddrBookCard.jsm", - BANISHED_PROPERTIES: "resource:///modules/VCardUtils.jsm", - VCardProperties: "resource:///modules/VCardUtils.jsm", - VCardPropertyEntry: "resource:///modules/VCardUtils.jsm", - VCardUtils: "resource:///modules/VCardUtils.jsm", -}); - -var { TbSync } = ChromeUtils.import("chrome://tbsync/content/tbsync.jsm"); -var { MailServices } = ChromeUtils.import("resource:///modules/MailServices.jsm"); - -const eas = TbSync.providers.eas; - -var Contacts = { - - // Remove if migration code is removed. - arrayFromString: function (stringValue) { - let arrayValue = []; - if (stringValue.trim().length>0) arrayValue = stringValue.trim().split("\u001A").filter(String); - return arrayValue; - }, - - /* The following TB properties are not synced to the server: - - only one WebPage - - more than 3 emails - - more than one fax, pager, mobile, work, home - - position (in org) - */ - - vcard_array_fields : { - n : 5, - adr : 7, - org : 2 - }, - - map_EAS_properties_to_vCard: revision => ({ - FileAs: {item: "fn", type: "text", params: {}}, /* DisplayName */ - - Birthday: {item: "bday", type: "date", params: {}}, - Anniversary: {item: "anniversary", type: "date", params: {}}, - - LastName: {item: "n", type: "text", params: {}, index: 0}, - FirstName: {item: "n", type: "text", params: {}, index: 1}, - MiddleName: {item: "n", type: "text", params: {}, index: 2}, - Title: {item: "n", type: "text", params: {}, index: 3}, - Suffix: {item: "n", type: "text", params: {}, index: 4}, - - Notes: {item: "note", type: "text", params: {}}, - - // What should we do with Email 4+? - // EAS does not have the concept of home/work for emails. Define matchAll - // to not use params for finding the correct entry. They will come back as - // "other". - Email1Address: {item: "email", type: "text", entry: 0, matchAll: true, params: {}}, - Email2Address: {item: "email", type: "text", entry: 1, matchAll: true, params: {}}, - Email3Address: {item: "email", type: "text", entry: 2, matchAll: true, params: {}}, - - // EAS does not have the concept of home/work for WebPage. Define matchAll - // to not use params for finding the correct entry. It will come back as - // "other". - WebPage: {item: "url", type: "text", matchAll: true, params: {}}, - - CompanyName: {item: "org", type: "text", params: {}, index: revision < 2 ? 1 : 0}, /* Company */ - Department: {item: "org", type: "text", params: {}, index: revision < 2 ? 0 : 1}, /* Department */ - JobTitle: { item: "title", type: "text", params: {} }, /* JobTitle */ - - MobilePhoneNumber: { item: "tel", type: "text", params: {type: "cell" }}, - PagerNumber: { item: "tel", type: "text", params: {type: "pager" }}, - HomeFaxNumber: { item: "tel", type: "text", params: {type: "fax" }}, - // If home phone is defined, use that, otherwise use unspecified phone - // Note: This must be exclusive (no other field may use home/unspecified) - // except if entry is specified. - HomePhoneNumber: { item: "tel", type: "text", params: {type: "home"}, fallbackParams: [{}]}, - BusinessPhoneNumber: { item: "tel", type: "text", params: {type: "work"}}, - Home2PhoneNumber: { item: "tel", type: "text", params: {type: "home"}, entry: 1 }, - Business2PhoneNumber: { item: "tel", type: "text", params: {type: "work"}, entry: 1 }, - - HomeAddressStreet: {item: "adr", type: "text", params: {type: "home"}, index: 2}, // needs special handling - HomeAddressCity: {item: "adr", type: "text", params: {type: "home"}, index: 3}, - HomeAddressState: {item: "adr", type: "text", params: {type: "home"}, index: 4}, - HomeAddressPostalCode: {item: "adr", type: "text", params: {type: "home"}, index: 5}, - HomeAddressCountry: {item: "adr", type: "text", params: {type: "home"}, index: 6}, - - BusinessAddressStreet: {item: "adr", type: "text", params: {type: "work"}, index: 2}, // needs special handling - BusinessAddressCity: {item: "adr", type: "text", params: {type: "work"}, index: 3}, - BusinessAddressState: {item: "adr", type: "text", params: {type: "work"}, index: 4}, - BusinessAddressPostalCode: {item: "adr", type: "text", params: {type: "work"}, index: 5}, - BusinessAddressCountry: {item: "adr", type: "text", params: {type: "work"}, index: 6}, - - OtherAddressStreet: {item: "adr", type: "text", params: {}, index: 2}, // needs special handling - OtherAddressCity: {item: "adr", type: "text", params: {}, index: 3}, - OtherAddressState: {item: "adr", type: "text", params: {}, index: 4}, - OtherAddressPostalCode: {item: "adr", type: "text", params: {}, index: 5}, - OtherAddressCountry: {item: "adr", type: "text", params: {}, index: 6}, - - // Misusing this EAS field, so that "Custom1" is saved to the server. - OfficeLocation: {item: "x-custom1", type: "text", params: {}}, - - Picture: {item: "photo", params: {}, type: "uri"}, - - // TB shows them as undefined, but showing them might be better, than not. Use a prefix. - AssistantPhoneNumber: { item: "tel", type: "text", params: {type: "Assistant"}, prefix: true}, - CarPhoneNumber: { item: "tel", type: "text", params: {type: "Car"}, prefix: true}, - RadioPhoneNumber: { item: "tel", type: "text", params: {type: "Radio"}, prefix: true}, - BusinessFaxNumber: { item: "tel", type: "text", params: {type: "WorkFax"}, prefix: true}, - }), - - map_EAS_properties_to_vCard_set2 : { - NickName: {item: "nickname", type: "text", params: {} }, - // Misusing these EAS fields, so that "Custom2,3,4" is saved to the server. - CustomerId: {item: "x-custom2", type: "text", params: {}}, - GovernmentId: {item: "x-custom3", type: "text", params: {}}, - AccountName: {item: "x-custom4", type: "text", params: {}}, - - IMAddress: {item: "impp", type: "text", params: {} }, - IMAddress2: {item: "impp", type: "text", params: {}, entry: 1 }, - IMAddress3: {item: "impp", type: "text", params: {}, entry: 2 }, - - CompanyMainPhone: { item: "tel", type: "text", params: {type: "Company"}, prefix: true}, - }, - - // There are currently no TB fields for these values, TbSync will store (and - // resend) them, but will not allow to view/edit. - unused_EAS_properties: [ - "Alias", //pseudo field - "WeightedRank", //pseudo field - "YomiCompanyName", //japanese phonetic equivalent - "YomiFirstName", //japanese phonetic equivalent - "YomiLastName", //japanese phonetic equivalent - "CompressedRTF", - "MMS", - // Former custom EAS fields, no longer added to UI after 102. - "ManagerName", - "AssistantName", - "Spouse", - ], - - // Normalize a parameters entry, to be able to find matching existing - // entries. If we want to be less restrictive, we need to check if all - // the requested values exist. But we should be the only one who sets - // the vCard props, so it should be safe. Except someone moves a contact. - // Should we prevent that via a vendor id in the vcard? - normalizeParameters: function (unordered) { - return JSON.stringify( - Object.keys(unordered).map(e => `${e}`.toLowerCase()).sort().reduce( - (obj, key) => { - obj[key] = `${unordered[key]}`.toLowerCase(); - return obj; - }, - {} - ) - ); - }, - - getValue: function (vCardProperties, vCard_property) { - let parameters = [vCard_property.params]; - if (vCard_property.fallbackParams) { - parameters.push(...vCard_property.fallbackParams); - } - let entries; - for (let normalizedParams of parameters.map(this.normalizeParameters)) { - // If no params set, do not filter, otherwise filter for exact match. - entries = vCardProperties.getAllEntries(vCard_property.item) - .filter(e => vCard_property.matchAll || normalizedParams == this.normalizeParameters(e.params)); - if (entries.length > 0) { - break; - } - } - - // Which entry should we take? - let entryNr = vCard_property.entry || 0; - if (entries[entryNr]) { - let value; - if (vCard_property.item == "org" && !Array.isArray(entries[entryNr].value)) { - // The org field sometimes comes back as a string (then it is Company), - // even though it should be an array [Department,Company] - value = vCard_property.index == 1 ? entries[entryNr].value : ""; - } else if (this.vcard_array_fields[vCard_property.item]) { - if (!Array.isArray(entries[entryNr].value)) { - // If the returned value is a single string, return it only - // when index 0 is requested, otherwise return nothing. - value = vCard_property.index == 0 ? entries[entryNr].value : ""; - } else { - value = entries[entryNr].value[vCard_property.index]; - } - } else { - value = entries[entryNr].value; - } - - if (value) { - if (vCard_property.prefix && value.startsWith(`${vCard_property.params.type}: `)) { - return value.substring(`${vCard_property.params.type}: `.length); - } - return value; - } - } - return ""; - }, - - /** - * Reads a DOM File and returns a Promise for its dataUrl. - * - * @param {File} file - * @returns {string} - */ - getDataUrl(file) { - return new Promise((resolve, reject) => { - var reader = new FileReader(); - reader.readAsDataURL(file); - reader.onload = function() { - resolve(reader.result); - }; - reader.onerror = function(error) { - resolve(""); - }; - }); - }, - - - - // --------------------------------------------------------------------------- // - // Read WBXML and set Thunderbird item - // --------------------------------------------------------------------------- // - setThunderbirdItemFromWbxml: function (abItem, data, id, syncdata, mode = "standard") { - let asversion = syncdata.accountData.getAccountProperty("asversion"); - let revision = parseInt(syncdata.target._directory.getStringValue("tbSyncRevision","1"), 10); - let map_EAS_properties_to_vCard = this.map_EAS_properties_to_vCard(revision); - - if (TbSync.prefs.getIntPref("log.userdatalevel") > 2) TbSync.dump("Processing " + mode + " contact item", id); - - // Make sure we are dealing with a vCard, so we can update the card just - // by updating its vCardProperties. - if (!abItem._card.supportsVCard) { - // This is an older card?? - throw new Error("It looks like you are trying to sync a TB91 sync state. Does not work."); - } - let vCardProperties = abItem._card.vCardProperties - abItem.primaryKey = id; - - // Loop over all known EAS properties (two EAS sets Contacts and Contacts2). - for (let set=0; set < 2; set++) { - let properties = (set == 0) ? this.EAS_properties : this.EAS_properties2; - - for (let EAS_property of properties) { - let vCard_property = (set == 0) ? map_EAS_properties_to_vCard[EAS_property] : this.map_EAS_properties_to_vCard_set2[EAS_property]; - let value; - switch (EAS_property) { - case "Notes": - if (asversion == "2.5") { - value = eas.xmltools.checkString(data.Body); - } else if (data.Body && data.Body.Data) { - value = eas.xmltools.checkString(data.Body.Data); - } - break; - - default: - value = eas.xmltools.checkString(data[EAS_property]); - } - - let normalizedParams = this.normalizeParameters(vCard_property.params) - let entries = vCardProperties.getAllEntries(vCard_property.item) - .filter(e => vCard_property.matchAll || normalizedParams == this.normalizeParameters(e.params)); - // Which entry should we update? Add empty entries, if the requested entry number - // does not yet exist. - let entryNr = vCard_property.entry || 0; - while (entries.length <= entryNr) { - let newEntry = new VCardPropertyEntry( - vCard_property.item, - vCard_property.params, - vCard_property.type, - this.vcard_array_fields[vCard_property.item] - ? new Array(this.vcard_array_fields[vCard_property.item]).fill("") - : "" - ); - vCardProperties.addEntry(newEntry); - entries = vCardProperties.getAllEntries(vCard_property.item); - entryNr = entries.length - 1; - } - - // Is this property part of the send data? - if (value) { - // Do we need to manipulate the value? - switch (EAS_property) { - case "Picture": - value = `data:image/jpeg;base64,${eas.xmltools.nodeAsArray(data.Picture)[0]}`; //Kerio sends Picture as container - break; - - case "Birthday": - case "Anniversary": - let dateObj = new Date(value); - value = dateObj.toISOString().substr(0, 10); - break; - - case "Email1Address": - case "Email2Address": - case "Email3Address": - let parsedInput = MailServices.headerParser.makeFromDisplayAddress(value); - let fixedValue = (parsedInput && parsedInput[0] && parsedInput[0].email) ? parsedInput[0].email : value; - if (fixedValue != value) { - if (TbSync.prefs.getIntPref("log.userdatalevel") > 2) TbSync.dump("Parsing email display string via RFC 2231 and RFC 2047 ("+EAS_property+")", value + " -> " + fixedValue); - value = fixedValue; - } - break; - - case "HomeAddressStreet": - case "BusinessAddressStreet": - case "OtherAddressStreet": - // Thunderbird accepts an array in the vCardProperty of the 2nd index of the adr field. - let seperator = String.fromCharCode(syncdata.accountData.getAccountProperty("seperator")); // options are 44 (,) or 10 (\n) - value = value.split(seperator); - break; - } - - // Add a typePrefix for fields unknown to TB (better: TB should use the type itself). - if (vCard_property.prefix && !value.startsWith(`${vCard_property.params.type}: `)) { - value = `${vCard_property.params.type}: ${value}`; - } - - // Is this an array value? - if (this.vcard_array_fields[vCard_property.item]) { - // Make sure this is an array. - if (!Array.isArray(entries[entryNr].value)) { - let arr = new Array(this.vcard_array_fields[vCard_property.item]).fill(""); - arr[0] = entries[entryNr].value; - entries[entryNr].value = arr; - } - entries[entryNr].value[vCard_property.index] = value; - } else { - entries[entryNr].value = value; - } - } else { - if (this.vcard_array_fields[vCard_property.item]) { - // Make sure this is an array. - if (!Array.isArray(entries[entryNr].value)) { - let arr = new Array(this.vcard_array_fields[vCard_property.item]).fill(""); - arr[0] = entries[entryNr].value; - entries[entryNr].value = arr; - } - entries[entryNr].value[vCard_property.index] = ""; - } else { - entries[entryNr].value = ""; - } - } - } - } - - // Take care of categories. - if (data["Categories"] && data["Categories"]["Category"]) { - let categories = Array.isArray(data["Categories"]["Category"]) - ? data["Categories"]["Category"] - : [data["Categories"]["Category"]]; - vCardProperties.clearValues("categories"); - vCardProperties.addValue("categories", categories); - // Migration code, remove once no longer needed. - abItem.setProperty("Categories", ""); - } - - // Take care of children, stored in contacts property bag. - if (data["Children"] && data["Children"]["Child"]) { - let children = Array.isArray(data["Children"]["Child"]) - ? data["Children"]["Child"] - : [data["Children"]["Child"]]; - abItem.setProperty("Children", JSON.stringify(children)); - } - - // Take care of un-mappable EAS options, which are stored in the contacts - // property bag. - for (let i=0; i < this.unused_EAS_properties.length; i++) { - if (data[this.unused_EAS_properties[i]]) abItem.setProperty("EAS-" + this.unused_EAS_properties[i], data[this.unused_EAS_properties[i]]); - } - - // Remove all entries, which are marked for deletion. - vCardProperties.entries = vCardProperties.entries.filter(e => Array.isArray(e.value) ? e.value.some(a => a != "") : e.value != ""); - - // Further manipulations (a few getters are still usable \o/). - if (syncdata.accountData.getAccountProperty("displayoverride")) { - abItem._card.displayName = abItem._card.firstName + " " + abItem._card.lastName; - if (abItem._card.displayName == " " ) { - let company = (vCardProperties.getFirstValue("org") || [""])[0]; - abItem._card.displayName = company || abItem._card.primaryEmail - } - } - }, - - - - - // --------------------------------------------------------------------------- // - //read TB event and return its data as WBXML - // --------------------------------------------------------------------------- // - getWbxmlFromThunderbirdItem: async function (abItem, syncdata, isException = false) { - let asversion = syncdata.accountData.getAccountProperty("asversion"); - let revision = parseInt(syncdata.target._directory.getStringValue("tbSyncRevision","1"), 10); - let map_EAS_properties_to_vCard = this.map_EAS_properties_to_vCard(revision); - - let wbxml = eas.wbxmltools.createWBXML("", syncdata.type); //init wbxml with "" and not with precodes, and set initial codepage - let nowDate = new Date(); - - // Make sure we are dealing with a vCard, so we can access its vCardProperties. - if (!abItem._card.supportsVCard) { - throw new Error("It looks like you are trying to sync a TB91 sync state. Does not work."); - } - let vCardProperties = abItem._card.vCardProperties - - // Loop over all known EAS properties (send empty value if not set). - for (let EAS_property of this.EAS_properties) { - // Some props need special handling. - let vCard_property = map_EAS_properties_to_vCard[EAS_property]; - let value; - switch (EAS_property) { - case "Notes": - // Needs to be done later, because we have to switch the code page. - continue; - - case "Picture": { - let photoUrl = abItem._card.photoURL; - if (!photoUrl) { - continue; - } - if (photoUrl.startsWith("file://")) { - let realPhotoFile = Services.io.newURI(photoUrl).QueryInterface(Ci.nsIFileURL).file; - let photoFile = await File.createFromNsIFile(realPhotoFile); - photoUrl = await this.getDataUrl(photoFile); - } - if (photoUrl.startsWith("data:image/")) { - let parts = photoUrl.split(","); - parts.shift(); - value = parts.join(","); - } - } - break; - - case "Birthday": - case "Anniversary": { - let raw = this.getValue(vCardProperties, vCard_property); - if (raw) { - let dateObj = new Date(raw); - value = dateObj.toISOString(); - } - } - break; - - case "HomeAddressStreet": - case "BusinessAddressStreet": - case "OtherAddressStreet": { - let raw = this.getValue(vCardProperties, vCard_property); - try { - if (raw) { - // We either get a single string or an array for the - // street adr field from Thunderbird. - if (!Array.isArray(raw)) { - raw = [raw]; - } - let seperator = String.fromCharCode(syncdata.accountData.getAccountProperty("seperator")); // options are 44 (,) or 10 (\n) - value = raw.join(seperator); - } - } catch (ex) { - throw new Error(`Failed to eval value: <${JSON.stringify(raw)}> @ ${JSON.stringify(vCard_property)}`); - } - } - break; - - default: { - value = this.getValue(vCardProperties, vCard_property); - } - } - - if (value) { - wbxml.atag(EAS_property, value); - } - } - - // Take care of un-mappable EAS option. - for (let i=0; i < this.unused_EAS_properties.length; i++) { - let value = abItem.getProperty("EAS-" + this.unused_EAS_properties[i], ""); - if (value) wbxml.atag(this.unused_EAS_properties[i], value); - } - - // Take care of categories. - let categories = vCardProperties.getFirstValue("categories"); - let categoriesProperty = abItem.getProperty("Categories", ""); - if (categoriesProperty) { - // Migration code, remove once no longer needed. - abItem.setProperty("Categories", ""); - categories = this.arrayFromString(categoriesProperty); - } - if (categories) { - wbxml.otag("Categories"); - for (let category of categories) wbxml.atag("Category", category); - wbxml.ctag(); - } - - // Take care of children, stored in contacts property bag. - let childrenProperty = abItem.getProperty("Children", ""); - if (childrenProperty) { - let children = []; - try { - children = JSON.parse(childrenProperty); - } catch(ex) { - // Migration code, remove once no longer needed. - children = this.arrayFromString(childrenProperty); - } - wbxml.otag("Children"); - for (let child of children) wbxml.atag("Child", child); - wbxml.ctag(); - } - - // Take care of notes - SWITCHING TO AirSyncBase (if 2.5, we still need Contact group here!) - let description = this.getValue(vCardProperties, map_EAS_properties_to_vCard["Notes"]); - if (asversion == "2.5") { - wbxml.atag("Body", description); - } else { - wbxml.switchpage("AirSyncBase"); - wbxml.otag("Body"); - wbxml.atag("Type", "1"); - wbxml.atag("EstimatedDataSize", "" + description.length); - wbxml.atag("Data", description); - wbxml.ctag(); - } - - // Take care of Contacts2 group - SWITCHING TO CONTACTS2 - wbxml.switchpage("Contacts2"); - - // Loop over all known TB properties of EAS group Contacts2 (send empty value if not set). - for (let EAS_property of this.EAS_properties2) { - let vCard_property = this.map_EAS_properties_to_vCard_set2[EAS_property]; - let value = this.getValue(vCardProperties, vCard_property); - if (value) wbxml.atag(EAS_property, value); - } - - return wbxml.getBytes(); - } -} - -Contacts.EAS_properties = Object.keys(Contacts.map_EAS_properties_to_vCard()); -Contacts.EAS_properties2 = Object.keys(Contacts.map_EAS_properties_to_vCard_set2); +/* + * This file is part of EAS-4-TbSync. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +ChromeUtils.defineESModuleGetters(this, { + newUID: "resource:///modules/AddrBookUtils.sys.mjs", + AddrBookCard: "resource:///modules/AddrBookCard.sys.mjs", + BANISHED_PROPERTIES: "resource:///modules/VCardUtils.sys.mjs", + VCardProperties: "resource:///modules/VCardUtils.sys.mjs", + VCardPropertyEntry: "resource:///modules/VCardUtils.sys.mjs", + VCardUtils: "resource:///modules/VCardUtils.sys.mjs", +}); + +var { ExtensionParent } = ChromeUtils.importESModule( + "resource://gre/modules/ExtensionParent.sys.mjs" +); +var { MailServices } = ChromeUtils.importESModule( + "resource:///modules/MailServices.sys.mjs" +); + +var tbsyncExtension = ExtensionParent.GlobalManager.getExtension( + "tbsync@jobisoft.de" +); +var { TbSync } = ChromeUtils.importESModule( + `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}` +); + +const eas = TbSync.providers.eas; + +var Contacts = { + + // Remove if migration code is removed. + arrayFromString: function (stringValue) { + let arrayValue = []; + if (stringValue.trim().length > 0) arrayValue = stringValue.trim().split("\u001A").filter(String); + return arrayValue; + }, + + /* The following TB properties are not synced to the server: + - only one WebPage + - more than 3 emails + - more than one fax, pager, mobile, work, home + - position (in org) + */ + + vcard_array_fields: { + n: 5, + adr: 7, + org: 2 + }, + + map_EAS_properties_to_vCard: revision => ({ + FileAs: { item: "fn", type: "text", params: {} }, /* DisplayName */ + + Birthday: { item: "bday", type: "date", params: {} }, + Anniversary: { item: "anniversary", type: "date", params: {} }, + + LastName: { item: "n", type: "text", params: {}, index: 0 }, + FirstName: { item: "n", type: "text", params: {}, index: 1 }, + MiddleName: { item: "n", type: "text", params: {}, index: 2 }, + Title: { item: "n", type: "text", params: {}, index: 3 }, + Suffix: { item: "n", type: "text", params: {}, index: 4 }, + + Notes: { item: "note", type: "text", params: {} }, + + // What should we do with Email 4+? + // EAS does not have the concept of home/work for emails. Define matchAll + // to not use params for finding the correct entry. They will come back as + // "other". + Email1Address: { item: "email", type: "text", entry: 0, matchAll: true, params: {} }, + Email2Address: { item: "email", type: "text", entry: 1, matchAll: true, params: {} }, + Email3Address: { item: "email", type: "text", entry: 2, matchAll: true, params: {} }, + + // EAS does not have the concept of home/work for WebPage. Define matchAll + // to not use params for finding the correct entry. It will come back as + // "other". + WebPage: { item: "url", type: "text", matchAll: true, params: {} }, + + CompanyName: { item: "org", type: "text", params: {}, index: revision < 2 ? 1 : 0 }, /* Company */ + Department: { item: "org", type: "text", params: {}, index: revision < 2 ? 0 : 1 }, /* Department */ + JobTitle: { item: "title", type: "text", params: {} }, /* JobTitle */ + + MobilePhoneNumber: { item: "tel", type: "text", params: { type: "cell" } }, + PagerNumber: { item: "tel", type: "text", params: { type: "pager" } }, + HomeFaxNumber: { item: "tel", type: "text", params: { type: "fax" } }, + // If home phone is defined, use that, otherwise use unspecified phone + // Note: This must be exclusive (no other field may use home/unspecified) + // except if entry is specified. + HomePhoneNumber: { item: "tel", type: "text", params: { type: "home" }, fallbackParams: [{}] }, + BusinessPhoneNumber: { item: "tel", type: "text", params: { type: "work" } }, + Home2PhoneNumber: { item: "tel", type: "text", params: { type: "home" }, entry: 1 }, + Business2PhoneNumber: { item: "tel", type: "text", params: { type: "work" }, entry: 1 }, + + HomeAddressStreet: { item: "adr", type: "text", params: { type: "home" }, index: 2 }, // needs special handling + HomeAddressCity: { item: "adr", type: "text", params: { type: "home" }, index: 3 }, + HomeAddressState: { item: "adr", type: "text", params: { type: "home" }, index: 4 }, + HomeAddressPostalCode: { item: "adr", type: "text", params: { type: "home" }, index: 5 }, + HomeAddressCountry: { item: "adr", type: "text", params: { type: "home" }, index: 6 }, + + BusinessAddressStreet: { item: "adr", type: "text", params: { type: "work" }, index: 2 }, // needs special handling + BusinessAddressCity: { item: "adr", type: "text", params: { type: "work" }, index: 3 }, + BusinessAddressState: { item: "adr", type: "text", params: { type: "work" }, index: 4 }, + BusinessAddressPostalCode: { item: "adr", type: "text", params: { type: "work" }, index: 5 }, + BusinessAddressCountry: { item: "adr", type: "text", params: { type: "work" }, index: 6 }, + + OtherAddressStreet: { item: "adr", type: "text", params: {}, index: 2 }, // needs special handling + OtherAddressCity: { item: "adr", type: "text", params: {}, index: 3 }, + OtherAddressState: { item: "adr", type: "text", params: {}, index: 4 }, + OtherAddressPostalCode: { item: "adr", type: "text", params: {}, index: 5 }, + OtherAddressCountry: { item: "adr", type: "text", params: {}, index: 6 }, + + // Misusing this EAS field, so that "Custom1" is saved to the server. + OfficeLocation: { item: "x-custom1", type: "text", params: {} }, + + Picture: { item: "photo", params: {}, type: "uri" }, + + // TB shows them as undefined, but showing them might be better, than not. Use a prefix. + AssistantPhoneNumber: { item: "tel", type: "text", params: { type: "Assistant" }, prefix: true }, + CarPhoneNumber: { item: "tel", type: "text", params: { type: "Car" }, prefix: true }, + RadioPhoneNumber: { item: "tel", type: "text", params: { type: "Radio" }, prefix: true }, + BusinessFaxNumber: { item: "tel", type: "text", params: { type: "WorkFax" }, prefix: true }, + }), + + map_EAS_properties_to_vCard_set2: { + NickName: { item: "nickname", type: "text", params: {} }, + // Misusing these EAS fields, so that "Custom2,3,4" is saved to the server. + CustomerId: { item: "x-custom2", type: "text", params: {} }, + GovernmentId: { item: "x-custom3", type: "text", params: {} }, + AccountName: { item: "x-custom4", type: "text", params: {} }, + + IMAddress: { item: "impp", type: "text", params: {} }, + IMAddress2: { item: "impp", type: "text", params: {}, entry: 1 }, + IMAddress3: { item: "impp", type: "text", params: {}, entry: 2 }, + + CompanyMainPhone: { item: "tel", type: "text", params: { type: "Company" }, prefix: true }, + }, + + // There are currently no TB fields for these values, TbSync will store (and + // resend) them, but will not allow to view/edit. + unused_EAS_properties: [ + "Alias", //pseudo field + "WeightedRank", //pseudo field + "YomiCompanyName", //japanese phonetic equivalent + "YomiFirstName", //japanese phonetic equivalent + "YomiLastName", //japanese phonetic equivalent + "CompressedRTF", + "MMS", + // Former custom EAS fields, no longer added to UI after 102. + "ManagerName", + "AssistantName", + "Spouse", + ], + + // Normalize a parameters entry, to be able to find matching existing + // entries. If we want to be less restrictive, we need to check if all + // the requested values exist. But we should be the only one who sets + // the vCard props, so it should be safe. Except someone moves a contact. + // Should we prevent that via a vendor id in the vcard? + normalizeParameters: function (unordered) { + return JSON.stringify( + Object.keys(unordered).map(e => `${e}`.toLowerCase()).sort().reduce( + (obj, key) => { + obj[key] = `${unordered[key]}`.toLowerCase(); + return obj; + }, + {} + ) + ); + }, + + getValue: function (vCardProperties, vCard_property) { + let parameters = [vCard_property.params]; + if (vCard_property.fallbackParams) { + parameters.push(...vCard_property.fallbackParams); + } + let entries; + for (let normalizedParams of parameters.map(this.normalizeParameters)) { + // If no params set, do not filter, otherwise filter for exact match. + entries = vCardProperties.getAllEntries(vCard_property.item) + .filter(e => vCard_property.matchAll || normalizedParams == this.normalizeParameters(e.params)); + if (entries.length > 0) { + break; + } + } + + // Which entry should we take? + let entryNr = vCard_property.entry || 0; + if (entries[entryNr]) { + let value; + if (vCard_property.item == "org" && !Array.isArray(entries[entryNr].value)) { + // The org field sometimes comes back as a string (then it is Company), + // even though it should be an array [Department,Company] + value = vCard_property.index == 1 ? entries[entryNr].value : ""; + } else if (this.vcard_array_fields[vCard_property.item]) { + if (!Array.isArray(entries[entryNr].value)) { + // If the returned value is a single string, return it only + // when index 0 is requested, otherwise return nothing. + value = vCard_property.index == 0 ? entries[entryNr].value : ""; + } else { + value = entries[entryNr].value[vCard_property.index]; + } + } else { + value = entries[entryNr].value; + } + + if (value) { + if (vCard_property.prefix && value.startsWith(`${vCard_property.params.type}: `)) { + return value.substring(`${vCard_property.params.type}: `.length); + } + return value; + } + } + return ""; + }, + + /** + * Reads a DOM File and returns a Promise for its dataUrl. + * + * @param {File} file + * @returns {string} + */ + getDataUrl(file) { + return new Promise((resolve, reject) => { + var reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = function () { + resolve(reader.result); + }; + reader.onerror = function (error) { + resolve(""); + }; + }); + }, + + + + // --------------------------------------------------------------------------- // + // Read WBXML and set Thunderbird item + // --------------------------------------------------------------------------- // + setThunderbirdItemFromWbxml: function (abItem, data, id, syncdata, mode = "standard") { + let asversion = syncdata.accountData.getAccountProperty("asversion"); + let revision = parseInt(syncdata.target._directory.getStringValue("tbSyncRevision", "1"), 10); + let map_EAS_properties_to_vCard = this.map_EAS_properties_to_vCard(revision); + + if (TbSync.prefs.getIntPref("log.userdatalevel") > 2) TbSync.dump("Processing " + mode + " contact item", id); + + // Make sure we are dealing with a vCard, so we can update the card just + // by updating its vCardProperties. + if (!abItem._card.supportsVCard) { + // This is an older card?? + throw new Error("It looks like you are trying to sync a TB91 sync state. Does not work."); + } + let vCardProperties = abItem._card.vCardProperties + abItem.primaryKey = id; + + // Loop over all known EAS properties (two EAS sets Contacts and Contacts2). + for (let set = 0; set < 2; set++) { + let properties = (set == 0) ? this.EAS_properties : this.EAS_properties2; + + for (let EAS_property of properties) { + let vCard_property = (set == 0) ? map_EAS_properties_to_vCard[EAS_property] : this.map_EAS_properties_to_vCard_set2[EAS_property]; + let value; + switch (EAS_property) { + case "Notes": + if (asversion == "2.5") { + value = eas.xmltools.checkString(data.Body); + } else if (data.Body && data.Body.Data) { + value = eas.xmltools.checkString(data.Body.Data); + } + break; + + default: + value = eas.xmltools.checkString(data[EAS_property]); + } + + let normalizedParams = this.normalizeParameters(vCard_property.params) + let entries = vCardProperties.getAllEntries(vCard_property.item) + .filter(e => vCard_property.matchAll || normalizedParams == this.normalizeParameters(e.params)); + // Which entry should we update? Add empty entries, if the requested entry number + // does not yet exist. + let entryNr = vCard_property.entry || 0; + while (entries.length <= entryNr) { + let newEntry = new VCardPropertyEntry( + vCard_property.item, + vCard_property.params, + vCard_property.type, + this.vcard_array_fields[vCard_property.item] + ? new Array(this.vcard_array_fields[vCard_property.item]).fill("") + : "" + ); + vCardProperties.addEntry(newEntry); + entries = vCardProperties.getAllEntries(vCard_property.item); + entryNr = entries.length - 1; + } + + // Is this property part of the send data? + if (value) { + // Do we need to manipulate the value? + switch (EAS_property) { + case "Picture": + value = `data:image/jpeg;base64,${eas.xmltools.nodeAsArray(data.Picture)[0]}`; //Kerio sends Picture as container + break; + + case "Birthday": + case "Anniversary": + let dateObj = new Date(value); + value = dateObj.toISOString().substr(0, 10); + break; + + case "Email1Address": + case "Email2Address": + case "Email3Address": + let parsedInput = MailServices.headerParser.makeFromDisplayAddress(value); + let fixedValue = (parsedInput && parsedInput[0] && parsedInput[0].email) ? parsedInput[0].email : value; + if (fixedValue != value) { + if (TbSync.prefs.getIntPref("log.userdatalevel") > 2) TbSync.dump("Parsing email display string via RFC 2231 and RFC 2047 (" + EAS_property + ")", value + " -> " + fixedValue); + value = fixedValue; + } + break; + + case "HomeAddressStreet": + case "BusinessAddressStreet": + case "OtherAddressStreet": + // Thunderbird accepts an array in the vCardProperty of the 2nd index of the adr field. + let seperator = String.fromCharCode(syncdata.accountData.getAccountProperty("seperator")); // options are 44 (,) or 10 (\n) + value = value.split(seperator); + break; + } + + // Add a typePrefix for fields unknown to TB (better: TB should use the type itself). + if (vCard_property.prefix && !value.startsWith(`${vCard_property.params.type}: `)) { + value = `${vCard_property.params.type}: ${value}`; + } + + // Is this an array value? + if (this.vcard_array_fields[vCard_property.item]) { + // Make sure this is an array. + if (!Array.isArray(entries[entryNr].value)) { + let arr = new Array(this.vcard_array_fields[vCard_property.item]).fill(""); + arr[0] = entries[entryNr].value; + entries[entryNr].value = arr; + } + entries[entryNr].value[vCard_property.index] = value; + } else { + entries[entryNr].value = value; + } + } else { + if (this.vcard_array_fields[vCard_property.item]) { + // Make sure this is an array. + if (!Array.isArray(entries[entryNr].value)) { + let arr = new Array(this.vcard_array_fields[vCard_property.item]).fill(""); + arr[0] = entries[entryNr].value; + entries[entryNr].value = arr; + } + entries[entryNr].value[vCard_property.index] = ""; + } else { + entries[entryNr].value = ""; + } + } + } + } + + // Take care of categories. + if (data["Categories"] && data["Categories"]["Category"]) { + let categories = Array.isArray(data["Categories"]["Category"]) + ? data["Categories"]["Category"] + : [data["Categories"]["Category"]]; + vCardProperties.clearValues("categories"); + vCardProperties.addValue("categories", categories); + // Migration code, remove once no longer needed. + abItem.setProperty("Categories", ""); + } + + // Take care of children, stored in contacts property bag. + if (data["Children"] && data["Children"]["Child"]) { + let children = Array.isArray(data["Children"]["Child"]) + ? data["Children"]["Child"] + : [data["Children"]["Child"]]; + abItem.setProperty("Children", JSON.stringify(children)); + } + + // Take care of un-mappable EAS options, which are stored in the contacts + // property bag. + for (let i = 0; i < this.unused_EAS_properties.length; i++) { + if (data[this.unused_EAS_properties[i]]) abItem.setProperty("EAS-" + this.unused_EAS_properties[i], data[this.unused_EAS_properties[i]]); + } + + // Remove all entries, which are marked for deletion. + vCardProperties.entries = vCardProperties.entries.filter(e => Array.isArray(e.value) ? e.value.some(a => a != "") : e.value != ""); + + // Further manipulations (a few getters are still usable \o/). + if (syncdata.accountData.getAccountProperty("displayoverride")) { + abItem._card.displayName = abItem._card.firstName + " " + abItem._card.lastName; + if (abItem._card.displayName == " ") { + let company = (vCardProperties.getFirstValue("org") || [""])[0]; + abItem._card.displayName = company || abItem._card.primaryEmail + } + } + }, + + + + + // --------------------------------------------------------------------------- // + //read TB event and return its data as WBXML + // --------------------------------------------------------------------------- // + getWbxmlFromThunderbirdItem: async function (abItem, syncdata, isException = false) { + let asversion = syncdata.accountData.getAccountProperty("asversion"); + let revision = parseInt(syncdata.target._directory.getStringValue("tbSyncRevision", "1"), 10); + let map_EAS_properties_to_vCard = this.map_EAS_properties_to_vCard(revision); + + let wbxml = eas.wbxmltools.createWBXML("", syncdata.type); //init wbxml with "" and not with precodes, and set initial codepage + let nowDate = new Date(); + + // Make sure we are dealing with a vCard, so we can access its vCardProperties. + if (!abItem._card.supportsVCard) { + throw new Error("It looks like you are trying to sync a TB91 sync state. Does not work."); + } + let vCardProperties = abItem._card.vCardProperties + + // Loop over all known EAS properties (send empty value if not set). + for (let EAS_property of this.EAS_properties) { + // Some props need special handling. + let vCard_property = map_EAS_properties_to_vCard[EAS_property]; + let value; + switch (EAS_property) { + case "Notes": + // Needs to be done later, because we have to switch the code page. + continue; + + case "Picture": { + let photoUrl = abItem._card.photoURL; + if (!photoUrl) { + continue; + } + if (photoUrl.startsWith("file://")) { + let realPhotoFile = Services.io.newURI(photoUrl).QueryInterface(Ci.nsIFileURL).file; + let photoFile = await File.createFromNsIFile(realPhotoFile); + photoUrl = await this.getDataUrl(photoFile); + } + if (photoUrl.startsWith("data:image/")) { + let parts = photoUrl.split(","); + parts.shift(); + value = parts.join(","); + } + } + break; + + case "Birthday": + case "Anniversary": { + let raw = this.getValue(vCardProperties, vCard_property); + if (raw) { + let dateObj = new Date(raw); + value = dateObj.toISOString(); + } + } + break; + + case "HomeAddressStreet": + case "BusinessAddressStreet": + case "OtherAddressStreet": { + let raw = this.getValue(vCardProperties, vCard_property); + try { + if (raw) { + // We either get a single string or an array for the + // street adr field from Thunderbird. + if (!Array.isArray(raw)) { + raw = [raw]; + } + let seperator = String.fromCharCode(syncdata.accountData.getAccountProperty("seperator")); // options are 44 (,) or 10 (\n) + value = raw.join(seperator); + } + } catch (ex) { + throw new Error(`Failed to eval value: <${JSON.stringify(raw)}> @ ${JSON.stringify(vCard_property)}`); + } + } + break; + + default: { + value = this.getValue(vCardProperties, vCard_property); + } + } + + if (value) { + wbxml.atag(EAS_property, value); + } + } + + // Take care of un-mappable EAS option. + for (let i = 0; i < this.unused_EAS_properties.length; i++) { + let value = abItem.getProperty("EAS-" + this.unused_EAS_properties[i], ""); + if (value) wbxml.atag(this.unused_EAS_properties[i], value); + } + + // Take care of categories. + let categories = vCardProperties.getFirstValue("categories"); + let categoriesProperty = abItem.getProperty("Categories", ""); + if (categoriesProperty) { + // Migration code, remove once no longer needed. + abItem.setProperty("Categories", ""); + categories = this.arrayFromString(categoriesProperty); + } + if (categories) { + wbxml.otag("Categories"); + for (let category of categories) wbxml.atag("Category", category); + wbxml.ctag(); + } + + // Take care of children, stored in contacts property bag. + let childrenProperty = abItem.getProperty("Children", ""); + if (childrenProperty) { + let children = []; + try { + children = JSON.parse(childrenProperty); + } catch (ex) { + // Migration code, remove once no longer needed. + children = this.arrayFromString(childrenProperty); + } + wbxml.otag("Children"); + for (let child of children) wbxml.atag("Child", child); + wbxml.ctag(); + } + + // Take care of notes - SWITCHING TO AirSyncBase (if 2.5, we still need Contact group here!) + let description = this.getValue(vCardProperties, map_EAS_properties_to_vCard["Notes"]); + if (asversion == "2.5") { + wbxml.atag("Body", description); + } else { + wbxml.switchpage("AirSyncBase"); + wbxml.otag("Body"); + wbxml.atag("Type", "1"); + wbxml.atag("EstimatedDataSize", "" + description.length); + wbxml.atag("Data", description); + wbxml.ctag(); + } + + // Take care of Contacts2 group - SWITCHING TO CONTACTS2 + wbxml.switchpage("Contacts2"); + + // Loop over all known TB properties of EAS group Contacts2 (send empty value if not set). + for (let EAS_property of this.EAS_properties2) { + let vCard_property = this.map_EAS_properties_to_vCard_set2[EAS_property]; + let value = this.getValue(vCardProperties, vCard_property); + if (value) wbxml.atag(EAS_property, value); + } + + return wbxml.getBytes(); + } +} + +Contacts.EAS_properties = Object.keys(Contacts.map_EAS_properties_to_vCard()); +Contacts.EAS_properties2 = Object.keys(Contacts.map_EAS_properties_to_vCard_set2); diff -Nru eas4tbsync-4.11/content/includes/network.js eas4tbsync-4.17/content/includes/network.js --- eas4tbsync-4.11/content/includes/network.js 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/content/includes/network.js 2025-05-15 11:21:20.000000000 +0000 @@ -1,1544 +1,1606 @@ -/* - * This file is part of EAS-4-TbSync. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -"use strict"; - -var { OAuth2 } = ChromeUtils.import("resource:///modules/OAuth2.jsm"); -var { TbSync } = ChromeUtils.import("chrome://tbsync/content/tbsync.jsm"); - -var containers = []; -var sandboxes = {}; - -function resetContainerWithId(id) { - Services.clearData.deleteDataFromOriginAttributesPattern({ userContextId: id }); -} - -function getContainerIdForContainerName(containerName) { - // Define the allowed range of container ids to be used - // TbSync is using 10000 - 19999 - // Lightning is using 20000 - 29999 - // Cardbook is using 30000 - 39999 - let min = 10000; - let max = 19999; - - //reset if adding an entry will exceed allowed range - if (containers.length > (max - min) && containers.indexOf(containerName) == -1) { - for (let i = 0; i < containers.length; i++) { - resetContainerWithId(i + min); - } - containers = []; - } - - let idx = containers.indexOf(containerName); - return (idx == -1) ? containers.push(containerName) - 1 + min : (idx + min); -} - -function getSandBoxedXHR({ user, accountname }, uri, containerReset = false) { - // The content principal used for the sandbox honours CORS. A server redirect - // to a different server may cause CORS violations. We implemented code to - // catch such redirects and re-run the request with the correct sandbox. If - // that becomes an issue, we need to make sandboxing optional. - // return new XMLHttpRequest({ mozAnon: false }); - - let containerName = `${accountname}::${user}@${uri.scheme}://${uri.hostPort}`; - - let userContextId = getContainerIdForContainerName(containerName); - if (containerReset) { - resetContainerWithId(userContextId); - } - if (!sandboxes.hasOwnProperty(containerName)) { - console.log("Creating sandbox for <" + containerName + ">"); - let principal = Services.scriptSecurityManager.createContentPrincipal(uri, { userContextId }); - sandboxes[containerName] = Components.utils.Sandbox(principal, { - wantXrays: true, - wantGlobalProperties: ["XMLHttpRequest"], - }); - } - return new sandboxes[containerName].XMLHttpRequest({ mozAnon: false }); -} - -var network = { - - getEasURL: function (accountData) { - let protocol = (accountData.getAccountProperty("https")) ? "https://" : "http://"; - let h = protocol + accountData.getAccountProperty("host"); - while (h.endsWith("/")) { h = h.slice(0, -1); } - - if (h.endsWith("Microsoft-Server-ActiveSync")) return h; - return h + "/Microsoft-Server-ActiveSync"; - }, - - getAuthData: function (accountData) { - let authData = { - // This is the host for the password manager, which could be different from - // the actual host property of the account. For EAS we want to couple the password - // with the ACCOUNT and not any sort of url, which could change via autodiscover - // at any time. - get host() { - return "TbSync#" + accountData.accountID; - }, - - get user() { - return accountData.getAccountProperty("user"); - }, - - get password() { - return TbSync.passwordManager.getLoginInfo(this.host, "TbSync/EAS", this.user); - }, - - get accountname() { - return accountData.getAccountProperty("accountname"); - }, - - updateLoginData: async function (newUsername, newPassword) { - let oldUsername = this.user; - await TbSync.passwordManager.updateLoginInfo(this.host, "TbSync/EAS", oldUsername, newUsername, newPassword); - // Also update the username of this account. Add dedicated username setter? - accountData.setAccountProperty("user", newUsername); - }, - - removeLoginData: function () { - TbSync.passwordManager.removeLoginInfos(this.host, "TbSync/EAS"); - } - }; - return authData; - }, - - getContextData: function (configObject = null) { - let contextData = {} - contextData.accountData = (configObject && configObject.hasOwnProperty("accountData")) ? configObject.accountData : null; - - if (contextData.accountData) { - contextData.accountname = contextData.accountData.getAccountProperty("accountname"); - contextData.user = contextData.accountData.getAccountProperty("user"); - contextData.host = contextData.accountData.getAccountProperty("host"); - contextData.servertype = contextData.accountData.getAccountProperty("servertype"); - contextData.accountID = contextData.accountData.accountID; - } else { - contextData.accountname = (configObject && configObject.hasOwnProperty("accountname")) ? configObject.accountname : ""; - contextData.user = (configObject && configObject.hasOwnProperty("user")) ? configObject.user : ""; - contextData.host = (configObject && configObject.hasOwnProperty("host")) ? configObject.host : ""; - contextData.servertype = (configObject && configObject.hasOwnProperty("servertype")) ? configObject.servertype : ""; - contextData.accountID = ""; - } - - return contextData; - }, - - // prepare and patch OAuth2 object - getOAuthObj: function (configObject = null) { - let { - accountData, - accountname, - user, - host, - accountID, - servertype - } = this.getContextData(configObject); - - if (!["office365"].includes(servertype)) - return null; - - let config = {}; - let customID = eas.Base.getCustomeOauthClientID(); - switch (host) { - case "outlook.office365.com": - case "eas.outlook.com": - config = { - auth_uri: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize", - token_uri: "https://login.microsoftonline.com/common/oauth2/v2.0/token", - redirect_uri: "https://login.microsoftonline.com/common/oauth2/nativeclient", - client_id: customID != "" ? customID : "2980deeb-7460-4723-864a-f9b0f10cd992", - } - break; - - default: - return null; - } - - switch (host) { - case "outlook.office365.com": - config.scope = "offline_access https://outlook.office.com/.default"; - break; - case "eas.outlook.com": - config.scope = "offline_access https://outlook.office.com/EAS.AccessAsUser.All"; - break; - } - - let oauth = new OAuth2(config.scope, { - authorizationEndpoint: config.auth_uri, - tokenEndpoint: config.token_uri, - clientId: config.client_id, - clientSecret: config.client_secret - }); - oauth.requestWindowFeatures = "chrome,private,centerscreen,width=500,height=750"; - - // The v2 redirection endpoint differs from the default and needs manual override - oauth.redirectionEndpoint = config.redirect_uri; - - oauth.extraAuthParams = [ - // removed in beta 1.14.1, according to - // https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent#default-and-consent - // prompt = consent will always ask for admin consent, even if it was granted - //["prompt", "consent"], - ["login_hint", user], - ]; - - if (accountname) { - oauth.requestWindowTitle = "TbSync account <" + accountname + "> requests authorization."; - } else { - oauth.requestWindowTitle = "A TbSync account requests authorization."; - } - - - - - /* Adding custom methods to the oauth object */ - - oauth.asyncConnect = async function (rv) { - rv.error = ""; - - // If multiple resources need to authenticate they will all end here, even though they - // might share the same token. Due to the async nature, each process will refresh - // "its own" token again, which is not needed. We force clear the token here and each - // final connect process will actually check the acccessToken and abort the refresh, - // if it is already there, generated by some other process. - if (oauth.getToken("accessToken")) { - await oauth.setToken("accessToken", ""); - } - - - try { - // refresh = false will do nothing and resolve immediately, if an accessToken - // exists already, which must have been generated by another process, as - // we cleared it beforehand. - await oauth.connect(/* with UI */ true, /* refresh */ false); - await oauth.setToken("accessToken", oauth.accessToken); - await oauth.setToken("refreshToken", oauth.refreshToken); - await oauth.setToken("tokenExpires", oauth.tokenExpires); - rv.tokens = oauth.tokens; - return true; - } catch (e) { - await oauth.setToken("accessToken", oauth.accessToken); - await oauth.setToken("refreshToken", oauth.refreshToken); - await oauth.setToken("tokenExpires", oauth.tokenExpires); - rv.error = eas.tools.isString(e) ? e : JSON.stringify(e); - } - - try { - switch (JSON.parse(rv.error).error) { - case "invalid_grant": - await oauth.setToken("accessToken", ""); - await oauth.setToken("refreshToken", ""); - rv.tokens = oauth.tokens; - return true; - - case "cancelled": - rv.error = "OAuthAbortError"; - break; - - default: - rv.error = "OAuthServerError::" + rv.error; - break; - } - } catch (e) { - rv.error = "OAuthServerError::" + rv.error; - Components.utils.reportError(e); - } - rv.tokens = oauth.tokens; - return false; - }; - - oauth.isExpired = function () { - const OAUTH_GRACE_TIME = 30 * 1000; - return (oauth.getToken("tokenExpires") - OAUTH_GRACE_TIME < new Date().getTime()); - }; - - const OAUTHVALUES = [ - ["access", "", "accessToken"], - ["refresh", "", "refreshToken"], - ["expires", Number.MAX_VALUE, "tokenExpires"], - ]; - - // returns a JSON string containing all the oauth values - Object.defineProperty(oauth, "tokens", { - get: function () { - let tokensObj = {}; - for (let oauthValue of OAUTHVALUES) { - // use the system value or if not defined the default - tokensObj[oauthValue[0]] = this[oauthValue[2]] || oauthValue[1]; - } - return JSON.stringify(tokensObj); - }, - enumerable: true, - }); - - if (accountData) { - // authData allows us to access the password manager values belonging to this account/calendar - // simply by authdata.username and authdata.password - oauth.authData = TbSync.providers.eas.network.getAuthData(accountData); - - oauth.parseAndSanitizeTokenString = function (tokenString) { - let _tokensObj = {}; - try { - _tokensObj = JSON.parse(tokenString); - } catch (e) { } - - let tokensObj = {}; - for (let oauthValue of OAUTHVALUES) { - // use the provided value or if not defined the default - tokensObj[oauthValue[0]] = (_tokensObj && _tokensObj.hasOwnProperty(oauthValue[0])) - ? _tokensObj[oauthValue[0]] - : oauthValue[1]; - } - return tokensObj; - }; - - oauth.getToken = function (tokenName) { - let oauthValue = OAUTHVALUES.find(e => e[2] == tokenName); - return oauth.parseAndSanitizeTokenString(oauth.authData.password)[oauthValue[0]]; - }; - - oauth.setToken = async function (tokenName, val) { - oauth[tokenName] = val; - - let oauthValue = OAUTHVALUES.find(e => e[2] == tokenName); - let tokens = oauth.parseAndSanitizeTokenString(oauth.authData.password); - let valueChanged = (val != tokens[oauthValue[0]]) - if (valueChanged) { - tokens[oauthValue[0]] = val; - await oauth.authData.updateLoginData(oauth.authData.user, JSON.stringify(tokens)); - } - }; - } else { - oauth.getToken = function (tokenName) { - return oauth[tokenName]; - }; - - oauth.setToken = async function (tokenName, val) { - oauth[tokenName] = val; - }; - } - - return oauth; - }, - - getOAuthValue: function (currentTokenString, type = "access") { - try { - let tokens = JSON.parse(currentTokenString); - if (tokens.hasOwnProperty(type)) - return tokens[type]; - } catch (e) { - //NOOP - } - return ""; - }, - - sendRequest: async function (wbxml, command, syncData, allowSoftFail = false) { - let ALLOWED_RETRIES = { - PasswordPrompt: 3, - NetworkError: 1, - } - - let rv = {}; - let oauthData = eas.network.getOAuthObj({ accountData: syncData.accountData }); - let syncState = syncData.getSyncState().state; - - for (; ;) { - - if (rv.errorType) { - let retry = false; - - if (ALLOWED_RETRIES[rv.errorType] > 0) { - ALLOWED_RETRIES[rv.errorType]--; - - - switch (rv.errorType) { - - case "PasswordPrompt": - { - - if (oauthData) { - await oauthData.setToken("accessToken", ""); - retry = true; - } else { - let authData = eas.network.getAuthData(syncData.accountData); - syncData.setSyncState("passwordprompt"); - let promptData = { - windowID: "auth:" + syncData.accountData.accountID, - accountname: syncData.accountData.getAccountProperty("accountname"), - usernameLocked: syncData.accountData.isConnected(), - username: authData.user - } - let credentials = await TbSync.passwordManager.asyncPasswordPrompt(promptData, eas.openWindows); - if (credentials) { - retry = true; - await authData.updateLoginData(credentials.username, credentials.password); - } - } - } - break; - - case "NetworkError": - { - // Could not connect to server. Can we rerun autodiscover? - // Note: Autodiscover is currently not supported by OAuth - if (syncData.accountData.getAccountProperty("servertype") == "auto" && !oauthData) { - let errorcode = await eas.network.updateServerConnectionViaAutodiscover(syncData); - console.log("ERR: " + errorcode); - if (errorcode == 200) { - // autodiscover succeeded, retry with new data - retry = true; - } else if (errorcode == 401) { - // manipulate rv to run password prompt - ALLOWED_RETRIES[rv.errorType]++; - rv.errorType = "PasswordPrompt"; - rv.errorObj = eas.sync.finish("error", "401"); - continue; // with the next loop, skip connection to the server - } - } - } - break; - - } - } - - if (!retry) throw rv.errorObj; - } - - // check OAuth situation before connecting - if (oauthData && (!oauthData.getToken("accessToken") || oauthData.isExpired())) { - syncData.setSyncState("oauthprompt"); - let _rv = {} - if (!(await oauthData.asyncConnect(_rv))) { - throw eas.sync.finish("error", _rv.error); - } - } - - // Return to original syncstate - if (syncState != syncData.getSyncState().state) { - syncData.setSyncState(syncState); - } - rv = await this.sendRequestPromise(wbxml, command, syncData, allowSoftFail); - - if (rv.errorType) { - // make sure, there is a valid ALLOWED_RETRIES setting for the returned error - if (rv.errorType && !ALLOWED_RETRIES.hasOwnProperty(rv.errorType)) { - ALLOWED_RETRIES[rv.errorType] = 1; - } - } else { - return rv; - } - } - }, - - sendRequestPromise: function (wbxml, command, syncData, allowSoftFail = false) { - let msg = "Sending data <" + syncData.getSyncState().state + "> for " + syncData.accountData.getAccountProperty("accountname"); - if (syncData.currentFolderData) msg += " (" + syncData.currentFolderData.getFolderProperty("foldername") + ")"; - syncData.request = eas.network.logXML(wbxml, msg); - syncData.response = ""; - - let connection = eas.network.getAuthData(syncData.accountData); - let userAgent = syncData.accountData.getAccountProperty("useragent"); //plus calendar.useragent.extra = Lightning/5.4.5.2 - let deviceType = syncData.accountData.getAccountProperty("devicetype"); - let deviceId = syncData.accountData.getAccountProperty("deviceId"); - - TbSync.dump("Sending (EAS v" + syncData.accountData.getAccountProperty("asversion") + ")", "POST " + eas.network.getEasURL(syncData.accountData) + '?Cmd=' + command + '&User=' + encodeURIComponent(connection.user) + '&DeviceType=' + deviceType + '&DeviceId=' + deviceId, true); - - const textEncoder = new TextEncoder(); - let encoded = textEncoder.encode(wbxml); - // console.log("wbxml: " + wbxml); - // console.log("byte array: " + encoded); - // console.log("length :" + wbxml.length + " vs " + encoded.byteLength + " vs " + encoded.length); - - let contextData = eas.network.getContextData({ accountData: syncData.accountData }); - let uri = Services.io.newURI(eas.network.getEasURL(syncData.accountData) + '?Cmd=' + command + '&User=' + encodeURIComponent(connection.user) + '&DeviceType=' + encodeURIComponent(deviceType) + '&DeviceId=' + deviceId); - return new Promise(function (resolve, reject) { - syncData.req = getSandBoxedXHR(contextData, uri); - syncData.req.mozBackgroundRequest = true; - syncData.req.open("POST", uri.spec, true); - syncData.req.overrideMimeType("text/plain"); - syncData.req.setRequestHeader("User-Agent", userAgent); - syncData.req.setRequestHeader("Content-Type", "application/vnd.ms-sync.wbxml"); - if (connection.password) { - if (eas.network.getOAuthObj({ accountData: syncData.accountData })) { - syncData.req.setRequestHeader("Authorization", 'Bearer ' + eas.network.getOAuthValue(connection.password, "access")); - } else { - syncData.req.setRequestHeader("Authorization", 'Basic ' + TbSync.tools.b64encode(connection.user + ':' + connection.password)); - } - } - - if (syncData.accountData.getAccountProperty("asversion") == "2.5") { - syncData.req.setRequestHeader("MS-ASProtocolVersion", "2.5"); - } else { - syncData.req.setRequestHeader("MS-ASProtocolVersion", "14.0"); - } - syncData.req.setRequestHeader("Content-Length", encoded.length); - if (syncData.accountData.getAccountProperty("provision")) { - syncData.req.setRequestHeader("X-MS-PolicyKey", syncData.accountData.getAccountProperty("policykey")); - TbSync.dump("PolicyKey used", syncData.accountData.getAccountProperty("policykey")); - } - - syncData.req.timeout = eas.Base.getConnectionTimeout(); - - syncData.req.ontimeout = function () { - if (allowSoftFail) { - resolve(""); - } else { - reject(eas.sync.finish("error", "timeout")); - } - }; - - syncData.req.onerror = function () { - if (allowSoftFail) { - resolve(""); - } else { - let error = TbSync.network.createTCPErrorFromFailedXHR(syncData.req) || "networkerror"; - let rv = {}; - rv.errorObj = eas.sync.finish("error", error); - rv.errorType = "NetworkError"; - resolve(rv); - } - }; - - syncData.req.onload = function () { - let response = syncData.req.responseText; - switch (syncData.req.status) { - - case 200: //OK - let msg = "Receiving data <" + syncData.getSyncState().state + "> for " + syncData.accountData.getAccountProperty("accountname"); - if (syncData.currentFolderData) msg += " (" + syncData.currentFolderData.getFolderProperty("foldername") + ")"; - syncData.response = eas.network.logXML(response, msg); - - //What to do on error? IS this an error? Yes! - if (!allowSoftFail && response.length !== 0 && response.substr(0, 4) !== String.fromCharCode(0x03, 0x01, 0x6A, 0x00)) { - TbSync.dump("Recieved Data", "Expecting WBXML but got junk (request status = " + syncData.req.status + ", ready state = " + syncData.req.readyState + "\n>>>>>>>>>>\n" + response + "\n<<<<<<<<<<\n"); - reject(eas.sync.finish("warning", "invalid")); - } else { - resolve(response); - } - break; - - case 401: // AuthError - case 403: // Forbiddden (some servers send forbidden on AuthError, like Freenet) - let rv = {}; - rv.errorObj = eas.sync.finish("error", "401"); - rv.errorType = "PasswordPrompt"; - resolve(rv); - break; - - case 449: // Request for new provision (enable it if needed) - //enable provision - syncData.accountData.setAccountProperty("provision", true); - syncData.accountData.resetAccountProperty("policykey"); - reject(eas.sync.finish("resyncAccount", syncData.req.status)); - break; - - case 451: // Redirect - update host and login manager - let header = syncData.req.getResponseHeader("X-MS-Location"); - let newHost = header.slice(header.indexOf("://") + 3, header.indexOf("/M")); - - TbSync.dump("redirect (451)", "header: " + header + ", oldHost: " + syncData.accountData.getAccountProperty("host") + ", newHost: " + newHost); - - syncData.accountData.setAccountProperty("host", newHost); - reject(eas.sync.finish("resyncAccount", syncData.req.status)); - break; - - default: - if (allowSoftFail) { - resolve(""); - } else { - reject(eas.sync.finish("error", "httperror::" + syncData.req.status)); - } - } - }; - - syncData.req.send(encoded); - - }); - }, - - - - - - - - - - - // RESPONSE EVALUATION - - logXML: function (wbxml, what) { - let rawxml = eas.wbxmltools.convert2xml(wbxml); - let xml = null; - if (rawxml) { - xml = rawxml.split('><').join('>\n<'); - } - - //include xml in log, if userdatalevel 2 or greater - if (TbSync.prefs.getIntPref("log.userdatalevel") > 1) { - - //log raw wbxml if userdatalevel is 3 or greater - if (TbSync.prefs.getIntPref("log.userdatalevel") > 2) { - let charcodes = []; - for (let i = 0; i < wbxml.length; i++) charcodes.push(wbxml.charCodeAt(i).toString(16)); - let bytestring = charcodes.join(" "); - TbSync.dump("WBXML: " + what, "\n" + bytestring); - } - - if (xml) { - //raw xml is save xml with all special chars in user data encoded by encodeURIComponent - KEEP that in order to be able to analyze logged XML - //let xml = decodeURIComponent(rawxml.split('><').join('>\n<')); - TbSync.dump("XML: " + what, "\n" + xml); - } else { - TbSync.dump("XML: " + what, "\nFailed to convert WBXML to XML!\n"); - } - } - - return xml; - }, - - //returns false on parse error and null on empty response (if allowed) - getDataFromResponse: function (wbxml, allowEmptyResponse = !eas.flags.allowEmptyResponse) { - //check for empty wbxml - if (wbxml.length === 0) { - if (allowEmptyResponse) return null; - else throw eas.sync.finish("warning", "empty-response"); - } - - //convert to save xml (all special chars in user data encoded by encodeURIComponent) and check for parse errors - let xml = eas.wbxmltools.convert2xml(wbxml); - if (xml === false) { - throw eas.sync.finish("warning", "wbxml-parse-error"); - } - - //retrieve data and check for empty data (all returned data fields are already decoded by decodeURIComponent) - let wbxmlData = eas.xmltools.getDataFromXMLString(xml); - if (wbxmlData === null) { - if (allowEmptyResponse) return null; - else throw eas.sync.finish("warning", "response-contains-no-data"); - } - - //debug - eas.xmltools.printXmlData(wbxmlData, false); //do not include ApplicationData in log - return wbxmlData; - }, - - updateSynckey: function (syncData, wbxmlData) { - let synckey = eas.xmltools.getWbxmlDataField(wbxmlData, "Sync.Collections.Collection.SyncKey"); - - if (synckey) { - // This COULD be a cause of problems... - syncData.synckey = synckey; - syncData.currentFolderData.setFolderProperty("synckey", synckey); - } else { - throw eas.sync.finish("error", "wbxmlmissingfield::Sync.Collections.Collection.SyncKey"); - } - }, - - checkStatus: function (syncData, wbxmlData, path, rootpath = "", allowSoftFail = false) { - //path is relative to wbxmlData - //rootpath is the absolute path and must be specified, if wbxml is not the root node and thus path is not the rootpath - let status = eas.xmltools.getWbxmlDataField(wbxmlData, path); - let fullpath = (rootpath == "") ? path : rootpath; - let elements = fullpath.split("."); - let type = elements[0]; - - //check if fallback to main class status: the answer could just be a "Sync.Status" instead of a "Sync.Collections.Collections.Status" - if (status === false) { - let mainStatus = eas.xmltools.getWbxmlDataField(wbxmlData, type + "." + elements[elements.length - 1]); - if (mainStatus === false) { - //both possible status fields are missing, abort - throw eas.sync.finish("warning", "wbxmlmissingfield::" + fullpath, "Request:\n" + syncData.request + "\n\nResponse:\n" + syncData.response); - } else { - //the alternative status could be extracted - status = mainStatus; - fullpath = type + "." + elements[elements.length - 1]; - } - } - - //check if all is fine (not bad) - if (status == "1") { - return ""; - } - - TbSync.dump("wbxml status check", type + ": " + fullpath + " = " + status); - - //handle errrors based on type - let statusType = type + "." + status; - switch (statusType) { - case "Sync.3": /* - MUST return to SyncKey element value of 0 for the collection. The client SHOULD either delete any items that were added - since the last successful Sync or the client MUST add those items back to the server after completing the full resynchronization - */ - TbSync.eventlog.add("warning", syncData.eventLogInfo, "Forced Folder Resync", "Request:\n" + syncData.request + "\n\nResponse:\n" + syncData.response); - syncData.currentFolderData.remove(); - throw eas.sync.finish("resyncFolder", statusType); - - case "Sync.4": //Malformed request - case "Sync.5": //Temporary server issues or invalid item - case "Sync.6": //Invalid item - case "Sync.8": //Object not found - if (allowSoftFail) return statusType; - throw eas.sync.finish("warning", statusType, "Request:\n" + syncData.request + "\n\nResponse:\n" + syncData.response); - - case "Sync.7": //The client has changed an item for which the conflict policy indicates that the server's changes take precedence. - case "Sync.9": //User account could be out of disk space, also send if no write permission (TODO) - return ""; - - case "FolderDelete.3": // special system folder - fatal error - case "FolderDelete.6": // error on server - throw eas.sync.finish("warning", statusType, "Request:\n" + syncData.request + "\n\nResponse:\n" + syncData.response); - - case "FolderDelete.4": // folder does not exist - resync ( we allow delete only if folder is not subscribed ) - case "FolderDelete.9": // invalid synchronization key - resync - case "FolderSync.9": // invalid synchronization key - resync - case "Sync.12": // folder hierarchy changed - { - let folders = syncData.accountData.getAllFoldersIncludingCache(); - for (let folder of folders) { - folder.remove(); - } - // reset account - eas.Base.onEnableAccount(syncData.accountData); - throw eas.sync.finish("resyncAccount", statusType, "Request:\n" + syncData.request + "\n\nResponse:\n" + syncData.response); - } - } - - //handle global error (https://msdn.microsoft.com/en-us/library/ee218647(v=exchg.80).aspx) - let descriptions = {}; - switch (status) { - case "101": //invalid content - case "102": //invalid wbxml - case "103": //invalid xml - throw eas.sync.finish("error", "global." + status, "Request:\n" + syncData.request + "\n\nResponse:\n" + syncData.response); - - case "109": descriptions["109"] = "DeviceTypeMissingOrInvalid"; - case "112": descriptions["112"] = "ActiveDirectoryAccessDenied"; - case "126": descriptions["126"] = "UserDisabledForSync"; - case "127": descriptions["127"] = "UserOnNewMailboxCannotSync"; - case "128": descriptions["128"] = "UserOnLegacyMailboxCannotSync"; - case "129": descriptions["129"] = "DeviceIsBlockedForThisUser"; - case "130": descriptions["120"] = "AccessDenied"; - case "131": descriptions["131"] = "AccountDisabled"; - throw eas.sync.finish("error", "global.clientdenied" + "::" + status + "::" + descriptions[status]); - - case "110": //server error - abort and disable autoSync for 30 minutes - { - let noAutosyncUntil = 30 * 60000 + Date.now(); - let humanDate = new Date(noAutosyncUntil).toUTCString(); - syncData.accountData.setAccountProperty("noAutosyncUntil", noAutosyncUntil); - throw eas.sync.finish("error", "global." + status, "AutoSync disabled until: " + humanDate + " \n\nRequest:\n" + syncData.request + "\n\nResponse:\n" + syncData.response); - - /* // reset account - * let folders = syncData.accountData.getAllFoldersIncludingCache(); - * for (let folder of folders) { - * folder.remove(); - * } - * // reset account - * eas.Base.onEnableAccount(syncData.accountData); - * throw eas.sync.finish("resyncAccount", statusType, "Request:\n" + syncData.request + "\n\nResponse:\n" + syncData.response); - */ - } - - case "141": // The device is not provisionable - case "142": // DeviceNotProvisioned - case "143": // PolicyRefresh - case "144": // InvalidPolicyKey - //enable provision - syncData.accountData.setAccountProperty("provision", true); - syncData.accountData.resetAccountProperty("policykey"); - throw eas.sync.finish("resyncAccount", statusType); - - default: - if (allowSoftFail) return statusType; - throw eas.sync.finish("error", statusType, "Request:\n" + syncData.request + "\n\nResponse:\n" + syncData.response); - - } - }, - - - - - - - - - - - // WBXML COMM STUFF - - setDeviceInformation: async function (syncData) { - if (syncData.accountData.getAccountProperty("asversion") == "2.5" || !syncData.accountData.getAccountProperty("allowedEasCommands").split(",").includes("Settings")) { - return; - } - - syncData.setSyncState("prepare.request.setdeviceinfo"); - - let wbxml = wbxmltools.createWBXML(); - wbxml.switchpage("Settings"); - wbxml.otag("Settings"); - wbxml.otag("DeviceInformation"); - wbxml.otag("Set"); - wbxml.atag("Model", "Computer"); - wbxml.atag("FriendlyName", "TbSync on Device " + syncData.accountData.getAccountProperty("deviceId").substring(4)); - wbxml.atag("OS", Services.appinfo.OS); - wbxml.atag("UserAgent", syncData.accountData.getAccountProperty("useragent")); - wbxml.ctag(); - wbxml.ctag(); - wbxml.ctag(); - - syncData.setSyncState("send.request.setdeviceinfo"); - let response = await eas.network.sendRequest(wbxml.getBytes(), "Settings", syncData); - - syncData.setSyncState("eval.response.setdeviceinfo"); - let wbxmlData = eas.network.getDataFromResponse(response); - - eas.network.checkStatus(syncData, wbxmlData, "Settings.Status"); - }, - - getPolicykey: async function (syncData) { - //build WBXML to request provision - syncData.setSyncState("prepare.request.provision"); - let wbxml = eas.wbxmltools.createWBXML(); - wbxml.switchpage("Provision"); - wbxml.otag("Provision"); - wbxml.otag("Policies"); - wbxml.otag("Policy"); - wbxml.atag("PolicyType", (syncData.accountData.getAccountProperty("asversion") == "2.5") ? "MS-WAP-Provisioning-XML" : "MS-EAS-Provisioning-WBXML"); - wbxml.ctag(); - wbxml.ctag(); - wbxml.ctag(); - - for (let loop = 0; loop < 2; loop++) { - syncData.setSyncState("send.request.provision"); - let response = await eas.network.sendRequest(wbxml.getBytes(), "Provision", syncData); - - syncData.setSyncState("eval.response.provision"); - let wbxmlData = eas.network.getDataFromResponse(response); - let policyStatus = eas.xmltools.getWbxmlDataField(wbxmlData, "Provision.Policies.Policy.Status"); - let provisionStatus = eas.xmltools.getWbxmlDataField(wbxmlData, "Provision.Status"); - if (provisionStatus === false) { - throw eas.sync.finish("error", "wbxmlmissingfield::Provision.Status"); - } else if (provisionStatus != "1") { - //dump policy status as well - if (policyStatus) TbSync.dump("PolicyKey", "Received policy status: " + policyStatus); - throw eas.sync.finish("error", "provision::" + provisionStatus); - } - - //reaching this point: provision status was ok - let policykey = eas.xmltools.getWbxmlDataField(wbxmlData, "Provision.Policies.Policy.PolicyKey"); - switch (policyStatus) { - case false: - throw eas.sync.finish("error", "wbxmlmissingfield::Provision.Policies.Policy.Status"); - - case "2": - //server does not have a policy for this device: disable provisioning - syncData.accountData.setAccountProperty("provision", false) - syncData.accountData.resetAccountProperty("policykey"); - throw eas.sync.finish("resyncAccount", "NoPolicyForThisDevice"); - - case "1": - if (policykey === false) { - throw eas.sync.finish("error", "wbxmlmissingfield::Provision.Policies.Policy.PolicyKey"); - } - TbSync.dump("PolicyKey", "Received policykey (" + loop + "): " + policykey); - syncData.accountData.setAccountProperty("policykey", policykey); - break; - - default: - throw eas.sync.finish("error", "policy." + policyStatus); - } - - //build WBXML to acknowledge provision - syncData.setSyncState("prepare.request.provision"); - wbxml = eas.wbxmltools.createWBXML(); - wbxml.switchpage("Provision"); - wbxml.otag("Provision"); - wbxml.otag("Policies"); - wbxml.otag("Policy"); - wbxml.atag("PolicyType", (syncData.accountData.getAccountProperty("asversion") == "2.5") ? "MS-WAP-Provisioning-XML" : "MS-EAS-Provisioning-WBXML"); - wbxml.atag("PolicyKey", policykey); - wbxml.atag("Status", "1"); - wbxml.ctag(); - wbxml.ctag(); - wbxml.ctag(); - - //this wbxml will be used by Send at the top of this loop - } - }, - - getSynckey: async function (syncData) { - syncData.setSyncState("prepare.request.synckey"); - //build WBXML to request a new syncKey - let wbxml = eas.wbxmltools.createWBXML(); - wbxml.otag("Sync"); - wbxml.otag("Collections"); - wbxml.otag("Collection"); - if (syncData.accountData.getAccountProperty("asversion") == "2.5") wbxml.atag("Class", syncData.type); - wbxml.atag("SyncKey", "0"); - wbxml.atag("CollectionId", syncData.currentFolderData.getFolderProperty("serverID")); - wbxml.ctag(); - wbxml.ctag(); - wbxml.ctag(); - - syncData.setSyncState("send.request.synckey"); - let response = await eas.network.sendRequest(wbxml.getBytes(), "Sync", syncData); - - syncData.setSyncState("eval.response.synckey"); - // get data from wbxml response - let wbxmlData = eas.network.getDataFromResponse(response); - //check status - eas.network.checkStatus(syncData, wbxmlData, "Sync.Collections.Collection.Status"); - //update synckey - eas.network.updateSynckey(syncData, wbxmlData); - }, - - getItemEstimate: async function (syncData) { - syncData.progressData.reset(); - - if (!syncData.accountData.getAccountProperty("allowedEasCommands").split(",").includes("GetItemEstimate")) { - return; //do not throw, this is optional - } - - syncData.setSyncState("prepare.request.estimate"); - - // BUILD WBXML - let wbxml = eas.wbxmltools.createWBXML(); - wbxml.switchpage("GetItemEstimate"); - wbxml.otag("GetItemEstimate"); - wbxml.otag("Collections"); - wbxml.otag("Collection"); - if (syncData.accountData.getAccountProperty("asversion") == "2.5") { //got this order for 2.5 directly from Microsoft support - wbxml.atag("Class", syncData.type); //only 2.5 - wbxml.atag("CollectionId", syncData.currentFolderData.getFolderProperty("serverID")); - wbxml.switchpage("AirSync"); - // required ! - // https://docs.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-ascmd/ffbefa62-e315-40b9-9cc6-f8d74b5f65d4 - if (syncData.type == "Calendar") wbxml.atag("FilterType", syncData.currentFolderData.accountData.getAccountProperty("synclimit")); - else wbxml.atag("FilterType", "0"); // we may filter incomplete tasks - - wbxml.atag("SyncKey", syncData.synckey); - wbxml.switchpage("GetItemEstimate"); - } else { //14.0 - wbxml.switchpage("AirSync"); - wbxml.atag("SyncKey", syncData.synckey); - wbxml.switchpage("GetItemEstimate"); - wbxml.atag("CollectionId", syncData.currentFolderData.getFolderProperty("serverID")); - wbxml.switchpage("AirSync"); - wbxml.otag("Options"); - // optional - if (syncData.type == "Calendar") wbxml.atag("FilterType", syncData.currentFolderData.accountData.getAccountProperty("synclimit")); - wbxml.atag("Class", syncData.type); - wbxml.ctag(); - wbxml.switchpage("GetItemEstimate"); - } - wbxml.ctag(); - wbxml.ctag(); - wbxml.ctag(); - - //SEND REQUEST - syncData.setSyncState("send.request.estimate"); - let response = await eas.network.sendRequest(wbxml.getBytes(), "GetItemEstimate", syncData, /* allowSoftFail */ true); - - //VALIDATE RESPONSE - syncData.setSyncState("eval.response.estimate"); - - // get data from wbxml response, some servers send empty response if there are no changes, which is not an error - let wbxmlData = eas.network.getDataFromResponse(response, eas.flags.allowEmptyResponse); - if (wbxmlData === null) return; - - let status = eas.xmltools.getWbxmlDataField(wbxmlData, "GetItemEstimate.Response.Status"); - let estimate = eas.xmltools.getWbxmlDataField(wbxmlData, "GetItemEstimate.Response.Collection.Estimate"); - - if (status && status == "1") { //do not throw on error, with EAS v2.5 I get error 2 for tasks and calendars ??? - syncData.progressData.reset(0, estimate); - } - }, - - getUserInfo: async function (syncData) { - if (!syncData.accountData.getAccountProperty("allowedEasCommands").split(",").includes("Settings")) { - return; - } - - syncData.setSyncState("prepare.request.getuserinfo"); - - let wbxml = eas.wbxmltools.createWBXML(); - wbxml.switchpage("Settings"); - wbxml.otag("Settings"); - wbxml.otag("UserInformation"); - wbxml.atag("Get"); - wbxml.ctag(); - wbxml.ctag(); - - syncData.setSyncState("send.request.getuserinfo"); - let response = await eas.network.sendRequest(wbxml.getBytes(), "Settings", syncData); - - - syncData.setSyncState("eval.response.getuserinfo"); - let wbxmlData = eas.network.getDataFromResponse(response); - - eas.network.checkStatus(syncData, wbxmlData, "Settings.Status"); - }, - - - - - - - - - - - // SEARCH - - getSearchResults: async function (accountData, currentQuery) { - - let _wbxml = eas.wbxmltools.createWBXML(); - _wbxml.switchpage("Search"); - _wbxml.otag("Search"); - _wbxml.otag("Store"); - _wbxml.atag("Name", "GAL"); - _wbxml.atag("Query", currentQuery); - _wbxml.otag("Options"); - _wbxml.atag("Range", "0-99"); //Z-Push needs a Range - //Not valid for GAL: https://msdn.microsoft.com/en-us/library/gg675461(v=exchg.80).aspx - //_wbxml.atag("DeepTraversal"); - //_wbxml.atag("RebuildResults"); - _wbxml.ctag(); - _wbxml.ctag(); - _wbxml.ctag(); - - let wbxml = _wbxml.getBytes(); - - eas.network.logXML(wbxml, "Send (GAL Search)"); - let command = "Search"; - - let authData = eas.network.getAuthData(accountData); - let oauthData = eas.network.getOAuthObj({ accountData }); - let userAgent = accountData.getAccountProperty("useragent"); //plus calendar.useragent.extra = Lightning/5.4.5.2 - let deviceType = accountData.getAccountProperty("devicetype"); - let deviceId = accountData.getAccountProperty("deviceId"); - - TbSync.dump("Sending (EAS v" + accountData.getAccountProperty("asversion") + ")", "POST " + eas.network.getEasURL(accountData) + '?Cmd=' + command + '&User=' + encodeURIComponent(authData.user) + '&DeviceType=' + deviceType + '&DeviceId=' + deviceId, true); - - for (let i = 0; i < 2; i++) { - // check OAuth situation before connecting - if (oauthData && (!oauthData.getToken("accessToken") || oauthData.isExpired())) { - let _rv = {} - if (!(await oauthData.asyncConnect(_rv))) { - throw eas.sync.finish("error", _rv.error); - } - } - - try { - let contextData = eas.network.getContextData({ accountData }); - let uri = Services.io.newURI(eas.network.getEasURL(accountData) + '?Cmd=' + command + '&User=' + encodeURIComponent(authData.user) + '&DeviceType=' + encodeURIComponent(deviceType) + '&DeviceId=' + deviceId); - let response = await new Promise(function (resolve, reject) { - let req = getSandBoxedXHR(contextData, uri); - req.mozBackgroundRequest = true; - req.open("POST", uri.spec, true); - req.overrideMimeType("text/plain"); - req.setRequestHeader("User-Agent", userAgent); - req.setRequestHeader("Content-Type", "application/vnd.ms-sync.wbxml"); - - if (authData.password) { - if (eas.network.getOAuthObj({ accountData })) { - req.setRequestHeader("Authorization", 'Bearer ' + eas.network.getOAuthValue(authData.password, "access")); - } else { - req.setRequestHeader("Authorization", 'Basic ' + TbSync.tools.b64encode(authData.user + ':' + authData.password)); - } - } - - if (accountData.getAccountProperty("asversion") == "2.5") { - req.setRequestHeader("MS-ASProtocolVersion", "2.5"); - } else { - req.setRequestHeader("MS-ASProtocolVersion", "14.0"); - } - req.setRequestHeader("Content-Length", wbxml.length); - if (accountData.getAccountProperty("provision")) { - req.setRequestHeader("X-MS-PolicyKey", accountData.getAccountProperty("policykey")); - TbSync.dump("PolicyKey used", accountData.getAccountProperty("policykey")); - } - - req.timeout = eas.Base.getConnectionTimeout(); - - req.ontimeout = function () { - reject("GAL Search timeout"); - }; - - req.onerror = function () { - reject("GAL Search Error"); - }; - - req.onload = function () { - let response = req.responseText; - - switch (req.status) { - - case 200: //OK - eas.network.logXML(response, "Received (GAL Search"); - - //What to do on error? IS this an error? Yes! - if (response.length !== 0 && response.substr(0, 4) !== String.fromCharCode(0x03, 0x01, 0x6A, 0x00)) { - TbSync.dump("Recieved Data", "Expecting WBXML but got junk (request status = " + req.status + ", ready state = " + req.readyState + "\n>>>>>>>>>>\n" + response + "\n<<<<<<<<<<\n"); - reject("GAL Search Response Invalid"); - } else { - resolve(response); - } - break; - - case 401: // bad auth - resolve("401"); - break; - - default: - reject("GAL Search Failed: " + req.status); - } - }; - - req.send(wbxml); - - }); - - if (response === "401") { - // try to recover from bad auth via token refresh - if (oauthData) { - await oauthData.setToken("accessToken", ""); - continue; - } - } - - return response; - } catch (e) { - Components.utils.reportError(e); - return; - } - } - }, - - - - - - - - - - - // OPTIONS - - getServerOptions: async function (syncData) { - syncData.setSyncState("prepare.request.options"); - let authData = eas.network.getAuthData(syncData.accountData); - - let userAgent = syncData.accountData.getAccountProperty("useragent"); //plus calendar.useragent.extra = Lightning/5.4.5.2 - TbSync.dump("Sending", "OPTIONS " + eas.network.getEasURL(syncData.accountData)); - - let allowedRetries = 5; - let retry; - let oauthData = eas.network.getOAuthObj({ accountData: syncData.accountData }); - - do { - retry = false; - - // Check OAuth situation before connecting - if (oauthData && (!oauthData.getToken("accessToken") || oauthData.isExpired())) { - let _rv = {}; - syncData.setSyncState("oauthprompt"); - if (!(await oauthData.asyncConnect(_rv))) { - throw eas.sync.finish("error", _rv.error); - } - } - - let contextData = eas.network.getContextData({ accountData: syncData.accountData }); - let uri = Services.io.newURI(eas.network.getEasURL(syncData.accountData)); - let result = await new Promise(function (resolve, reject) { - syncData.req = getSandBoxedXHR(contextData, uri); - syncData.req.mozBackgroundRequest = true; - syncData.req.open("OPTIONS", uri.spec, true); - syncData.req.overrideMimeType("text/plain"); - syncData.req.setRequestHeader("User-Agent", userAgent); - if (authData.password) { - if (eas.network.getOAuthObj({ accountData: syncData.accountData })) { - syncData.req.setRequestHeader("Authorization", 'Bearer ' + eas.network.getOAuthValue(authData.password, "access")); - } else { - syncData.req.setRequestHeader("Authorization", 'Basic ' + TbSync.tools.b64encode(authData.user + ':' + authData.password)); - } - } - syncData.req.timeout = eas.Base.getConnectionTimeout(); - - syncData.req.ontimeout = function () { - resolve(); - }; - - syncData.req.onerror = function () { - let responseData = {}; - responseData["MS-ASProtocolVersions"] = syncData.req.getResponseHeader("MS-ASProtocolVersions"); - responseData["MS-ASProtocolCommands"] = syncData.req.getResponseHeader("MS-ASProtocolCommands"); - - TbSync.dump("EAS OPTIONS with response (status: " + syncData.req.status + ")", "\n" + - "responseText: " + syncData.req.responseText + "\n" + - "responseHeader(MS-ASProtocolVersions): " + responseData["MS-ASProtocolVersions"] + "\n" + - "responseHeader(MS-ASProtocolCommands): " + responseData["MS-ASProtocolCommands"]); - resolve(); - }; - - syncData.req.onload = function () { - syncData.setSyncState("eval.request.options"); - let responseData = {}; - - switch (syncData.req.status) { - case 401: // AuthError - let rv = {}; - rv.errorObj = eas.sync.finish("error", "401"); - rv.errorType = "PasswordPrompt"; - resolve(rv); - break; - - case 200: - responseData["MS-ASProtocolVersions"] = syncData.req.getResponseHeader("MS-ASProtocolVersions"); - responseData["MS-ASProtocolCommands"] = syncData.req.getResponseHeader("MS-ASProtocolCommands"); - - TbSync.dump("EAS OPTIONS with response (status: 200)", "\n" + - "responseText: " + syncData.req.responseText + "\n" + - "responseHeader(MS-ASProtocolVersions): " + responseData["MS-ASProtocolVersions"] + "\n" + - "responseHeader(MS-ASProtocolCommands): " + responseData["MS-ASProtocolCommands"]); - - if (responseData && responseData["MS-ASProtocolCommands"] && responseData["MS-ASProtocolVersions"]) { - syncData.accountData.setAccountProperty("allowedEasCommands", responseData["MS-ASProtocolCommands"]); - syncData.accountData.setAccountProperty("allowedEasVersions", responseData["MS-ASProtocolVersions"]); - syncData.accountData.setAccountProperty("lastEasOptionsUpdate", Date.now()); - } - resolve(); - break; - - default: - resolve(); - break; - - } - }; - - syncData.setSyncState("send.request.options"); - syncData.req.send(); - - }); - - if (result && result.hasOwnProperty("errorType") && result.errorType == "PasswordPrompt") { - if (allowedRetries > 0) { - if (oauthData) { - await oauthData.setToken("accessToken", ""); - retry = true; - } else { - syncData.setSyncState("passwordprompt"); - let authData = eas.network.getAuthData(syncData.accountData); - let promptData = { - windowID: "auth:" + syncData.accountData.accountID, - accountname: syncData.accountData.getAccountProperty("accountname"), - usernameLocked: syncData.accountData.isConnected(), - username: authData.user - } - let credentials = await TbSync.passwordManager.asyncPasswordPrompt(promptData, eas.openWindows); - if (credentials) { - await authData.updateLoginData(credentials.username, credentials.password); - retry = true; - } - } - } - - if (!retry) { - throw result.errorObj; - } - } - - allowedRetries--; - } while (retry); - }, - - - - - - - - - - - // AUTODISCOVER - - updateServerConnectionViaAutodiscover: async function (syncData) { - syncData.setSyncState("prepare.request.autodiscover"); - let authData = eas.network.getAuthData(syncData.accountData); - - syncData.setSyncState("send.request.autodiscover"); - let result = await eas.network.getServerConnectionViaAutodiscover(authData.accountname, authData.user, authData.password, 30 * 1000); - - syncData.setSyncState("eval.response.autodiscover"); - if (result.errorcode == 200) { - //update account - syncData.accountData.setAccountProperty("host", eas.network.stripAutodiscoverUrl(result.server)); - syncData.accountData.setAccountProperty("user", result.user); - syncData.accountData.setAccountProperty("https", (result.server.substring(0, 5) == "https")); - } - - return result.errorcode; - }, - - stripAutodiscoverUrl: function (url) { - let u = url; - while (u.endsWith("/")) { u = u.slice(0, -1); } - if (u.endsWith("/Microsoft-Server-ActiveSync")) u = u.slice(0, -28); - else TbSync.dump("Received non-standard EAS url via autodiscover:", url); - - return u.split("//")[1]; //cut off protocol - }, - - getServerConnectionViaAutodiscover: async function (accountname, user, password, maxtimeout) { - let urls = []; - let parts = user.split("@"); - - urls.push({ "url": "https://autodiscover." + parts[1] + "/autodiscover/autodiscover.xml", "user": user }); - urls.push({ "url": "https://" + parts[1] + "/autodiscover/autodiscover.xml", "user": user }); - urls.push({ "url": "https://autodiscover." + parts[1] + "/Autodiscover/Autodiscover.xml", "user": user }); - urls.push({ "url": "https://" + parts[1] + "/Autodiscover/Autodiscover.xml", "user": user }); - - urls.push({ "url": "http://autodiscover." + parts[1] + "/autodiscover/autodiscover.xml", "user": user }); - urls.push({ "url": "http://" + parts[1] + "/autodiscover/autodiscover.xml", "user": user }); - urls.push({ "url": "http://autodiscover." + parts[1] + "/Autodiscover/Autodiscover.xml", "user": user }); - urls.push({ "url": "http://" + parts[1] + "/Autodiscover/Autodiscover.xml", "user": user }); - - let requests = []; - let responses = []; //array of objects {url, error, server} - - for (let i = 0; i < urls.length; i++) { - await TbSync.tools.sleep(200); - requests.push(eas.network.getServerConnectionViaAutodiscoverRedirectWrapper( - accountname, - urls[i].url, - urls[i].user, - password, - maxtimeout - )); - } - - try { - responses = await Promise.all(requests); - } catch (e) { - responses.push(e.result); //this is actually a success, see return value of getServerConnectionViaAutodiscoverRedirectWrapper() - } - - let result; - let log = []; - for (let r = 0; r < responses.length; r++) { - log.push("* " + responses[r].url + " @ " + responses[r].user + " : " + (responses[r].server ? responses[r].server : responses[r].error)); - - if (responses[r].server) { - result = { "server": responses[r].server, "user": responses[r].user, "error": "", "errorcode": 200 }; - break; - } - - if (responses[r].error == 403 || responses[r].error == 401) { - //we could still find a valid server, so just store this state - result = { "server": "", "user": responses[r].user, "errorcode": responses[r].error, "error": TbSync.getString("status." + responses[r].error, "eas") }; - } - } - - //this is only reached on fail, if no result defined yet, use general error - if (!result) { - result = { "server": "", "user": user, "error": TbSync.getString("autodiscover.Failed", "eas").replace("##user##", user), "errorcode": 503 }; - } - - TbSync.eventlog.add("error", new TbSync.EventLogInfo("eas"), result.error, log.join("\n")); - return result; - }, - - getServerConnectionViaAutodiscoverRedirectWrapper: async function (accountname, url, user, password, maxtimeout) { - let result = {}; - let method = "POST"; - let connection = { accountname, url, user }; - - do { - await TbSync.tools.sleep(200); - result = await eas.network.getServerConnectionViaAutodiscoverRequest(method, connection, password, maxtimeout); - method = ""; - - if (result.error == "redirect found") { - TbSync.dump("EAS autodiscover URL redirect", "\n" + connection.url + " @ " + connection.user + " => \n" + result.url + " @ " + result.user); - connection.url = result.url; - connection.user = result.user; - method = "POST"; - } - - } while (method); - - //invert reject and resolve, so we exit the promise group on success right away - if (result.server) { - let e = new Error("Not an error (early exit from promise group)"); - e.result = result; - throw e; - } else { - return result; - } - }, - - getServerConnectionViaAutodiscoverRequest: function (method, connection, password, maxtimeout) { - TbSync.dump("Querry EAS autodiscover URL", connection.url + " @ " + connection.user); - - return new Promise(function (resolve, reject) { - - let xml = '\r\n'; - xml += '\r\n'; - xml += '\r\n'; - xml += '' + connection.user + '\r\n'; - xml += 'http://schemas.microsoft.com/exchange/autodiscover/mobilesync/responseschema/2006\r\n'; - xml += '\r\n'; - xml += '\r\n'; - - let userAgent = eas.prefs.getCharPref("clientID.useragent"); //plus calendar.useragent.extra = Lightning/5.4.5.2 - let uri = Services.io.newURI(connection.url); - let req = getSandBoxedXHR(connection, uri); - req.mozBackgroundRequest = true; - req.open(method, uri.spec, true); - req.timeout = maxtimeout; - req.setRequestHeader("User-Agent", userAgent); - - let secure = (connection.url.substring(0, 8).toLowerCase() == "https://"); - - if (method == "POST") { - req.setRequestHeader("Content-Length", xml.length); - req.setRequestHeader("Content-Type", "text/xml"); - if (secure && password) { - // OAUTH accounts cannot authenticate against the standard discovery services - // updateServerConnectionViaAutodiscover() is not passing them on - req.setRequestHeader("Authorization", "Basic " + TbSync.tools.b64encode(connection.user + ":" + password)); - } - } - - req.ontimeout = function () { - TbSync.dump("EAS autodiscover with timeout", "\n" + connection.url + " => \n" + req.responseURL); - resolve({ "url": req.responseURL, "error": "timeout", "server": "", "user": connection.user }); - }; - - req.onerror = function () { - let error = TbSync.network.createTCPErrorFromFailedXHR(req); - if (!error) error = req.responseText; - - // CORS violations can happen on redirects. They come back as NS_ERROR_DOM_BAD_URI. - if (error == "network::NS_ERROR_DOM_BAD_URI" && req.channel.URI.spec != uri.spec) { - resolve({ "url": req.channel.URI.spec, "error": "redirect found", "server": "", "user": connection.user }); - return; - } - - TbSync.dump("EAS autodiscover with error (" + error + ")", "\n" + connection.url + " => \n" + req.responseURL); - resolve({ "url": req.responseURL, "error": error, "server": "", "user": connection.user }); - }; - - req.onload = function () { - //initiate rerun on redirects - if (req.responseURL != connection.url) { - resolve({ "url": req.responseURL, "error": "redirect found", "server": "", "user": connection.user }); - return; - } - - //ignore POST without autherization (we just do them to get redirect information) - if (!secure) { - resolve({ "url": req.responseURL, "error": "unsecure POST", "server": "", "user": connection.user }); - return; - } - - //evaluate secure POST requests which have not been redirected - TbSync.dump("EAS autodiscover POST with status (" + req.status + ")", "\n" + connection.url + " => \n" + req.responseURL + "\n[" + req.responseText + "]"); - - if (req.status === 200) { - let data = null; - // getDataFromXMLString may throw an error which cannot be catched outside onload, - // because we are in an async callback of the surrounding Promise - // Alternatively we could just return the responseText and do any data analysis outside of the Promise - try { - data = eas.xmltools.getDataFromXMLString(req.responseText); - } catch (e) { - resolve({ "url": req.responseURL, "error": "bad response", "server": "", "user": connection.user }); - return; - } - - if (!(data === null) && data.Autodiscover && data.Autodiscover.Response && data.Autodiscover.Response.Action) { - // "Redirect" or "Settings" are possible - if (data.Autodiscover.Response.Action.Redirect) { - // redirect, start again with new user - let newuser = action.Redirect; - resolve({ "url": req.responseURL, "error": "redirect found", "server": "", "user": newuser }); - - } else if (data.Autodiscover.Response.Action.Settings) { - // get server settings - let server = eas.xmltools.nodeAsArray(data.Autodiscover.Response.Action.Settings.Server); - - for (let count = 0; count < server.length; count++) { - if (server[count].Type == "MobileSync" && server[count].Url) { - resolve({ "url": req.responseURL, "error": "", "server": server[count].Url, "user": connection.user }); - return; - } - } - } - } else { - resolve({ "url": req.responseURL, "error": "invalid", "server": "", "user": connection.user }); - } - } else { - resolve({ "url": req.responseURL, "error": req.status, "server": "", "user": connection.user }); - } - }; - - req.send(xml); - }); - }, - - getServerConnectionViaAutodiscoverV2JsonRequest: function (accountname, user, url, maxtimeout) { - TbSync.dump("Querry EAS autodiscover V2 URL", url); - - return new Promise(function (resolve, reject) { - - let userAgent = eas.prefs.getCharPref("clientID.useragent"); //plus calendar.useragent.extra = Lightning/5.4.5.2 - let uri = Services.io.newURI(url); - let req = getSandBoxedXHR({ accountname, user }, uri); - req.mozBackgroundRequest = true; - req.open("GET", uri.spec, true); - req.timeout = maxtimeout; - req.setRequestHeader("User-Agent", userAgent); - - req.ontimeout = function () { - TbSync.dump("EAS autodiscover V2 with timeout", "\n" + url + " => \n" + req.responseURL); - resolve({ "url": req.responseURL, "error": "timeout", "server": "" }); - }; - - req.onerror = function () { - let error = TbSync.network.createTCPErrorFromFailedXHR(req); - if (!error) error = req.responseText; - TbSync.dump("EAS autodiscover V2 with error (" + error + ")", "\n" + url + " => \n" + req.responseURL); - resolve({ "url": req.responseURL, "error": error, "server": "" }); - }; - - req.onload = function () { - if (req.status === 200) { - let data = JSON.parse(req.responseText); - - if (data && data.Url) { - resolve({ "url": req.responseURL, "error": "", "server": eas.network.stripAutodiscoverUrl(data.Url) }); - } else { - resolve({ "url": req.responseURL, "error": "invalid", "server": "" }); - } - return; - } - - resolve({ "url": req.responseURL, "error": req.status, "server": "" }); - }; - - req.send(); - }); - } -} +/* + * This file is part of EAS-4-TbSync. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +var { ExtensionParent } = ChromeUtils.importESModule( + "resource://gre/modules/ExtensionParent.sys.mjs" +); +var { OAuth2 } = ChromeUtils.importESModule( + "resource:///modules/OAuth2.sys.mjs" +); + +var tbsyncExtension = ExtensionParent.GlobalManager.getExtension( + "tbsync@jobisoft.de" +); +var { TbSync } = ChromeUtils.importESModule( + `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}` +); + +var containers = []; +var sandboxes = {}; + +function resetContainerWithId(id) { + Services.clearData.deleteDataFromOriginAttributesPattern({ userContextId: id }); +} + +function getContainerIdForContainerName(containerName) { + // Define the allowed range of container ids to be used + // TbSync is using 10000 - 19999 + // Lightning is using 20000 - 29999 + // Cardbook is using 30000 - 39999 + let min = 10000; + let max = 19999; + + //reset if adding an entry will exceed allowed range + if (containers.length > (max - min) && containers.indexOf(containerName) == -1) { + for (let i = 0; i < containers.length; i++) { + resetContainerWithId(i + min); + } + containers = []; + } + + let idx = containers.indexOf(containerName); + return (idx == -1) ? containers.push(containerName) - 1 + min : (idx + min); +} + +function getSandBoxedXHR({ user, accountname }, uri, containerReset = false) { + // The content principal used for the sandbox honours CORS. A server redirect + // to a different server may cause CORS violations. We implemented code to + // catch such redirects and re-run the request with the correct sandbox. If + // that becomes an issue, we need to make sandboxing optional. + // return new XMLHttpRequest({ mozAnon: false }); + + let containerName = `${accountname}::${user}@${uri.scheme}://${uri.hostPort}`; + + let userContextId = getContainerIdForContainerName(containerName); + if (containerReset) { + resetContainerWithId(userContextId); + } + + // Pre-set cookie needed by eas.outlook.com. The cookie is returned with each + // server response, but is is SameSite=None without the secure flag being set + // and ignored. + if (uri.host == "eas.outlook.com") { + Services.cookies.add( + "eas.outlook.com", + "/", + "DefaultAnchorMailbox", + user, + /* isSecure */ true, + /* isHttponly */ false, + /* isSession = */ false, + /* expiry */ Number.MAX_SAFE_INTEGER, + { userContextId }, + Ci.nsICookie.SAMESITE_NONE, + Ci.nsICookie.SCHEME_HTTPS, + /* partitioned */ false + ); + } + if (!sandboxes.hasOwnProperty(containerName)) { + console.log("Creating sandbox for <" + containerName + ">"); + let principal = Services.scriptSecurityManager.createContentPrincipal(uri, { userContextId }); + sandboxes[containerName] = Components.utils.Sandbox(principal, { + wantXrays: true, + wantGlobalProperties: ["XMLHttpRequest"], + }); + } + return new sandboxes[containerName].XMLHttpRequest({ mozAnon: false }); +} + +var network = { + + getEasURL: function (accountData) { + let protocol = (accountData.getAccountProperty("https")) ? "https://" : "http://"; + let h = protocol + accountData.getAccountProperty("host"); + while (h.endsWith("/")) { h = h.slice(0, -1); } + + if (h.endsWith("Microsoft-Server-ActiveSync")) return h; + return h + "/Microsoft-Server-ActiveSync"; + }, + + getAuthData: function (accountData) { + let authData = { + // This is the host for the password manager, which could be different from + // the actual host property of the account. For EAS we want to couple the password + // with the ACCOUNT and not any sort of url, which could change via autodiscover + // at any time. + get host() { + return "TbSync#" + accountData.accountID; + }, + + get user() { + return accountData.getAccountProperty("user"); + }, + + get password() { + return TbSync.passwordManager.getLoginInfo(this.host, "TbSync/EAS", this.user); + }, + + get accountname() { + return accountData.getAccountProperty("accountname"); + }, + + updateLoginData: async function (newUsername, newPassword) { + let oldUsername = this.user; + await TbSync.passwordManager.updateLoginInfo(this.host, "TbSync/EAS", oldUsername, newUsername, newPassword); + // Also update the username of this account. Add dedicated username setter? + accountData.setAccountProperty("user", newUsername); + }, + + removeLoginData: function () { + TbSync.passwordManager.removeLoginInfos(this.host, "TbSync/EAS"); + } + }; + return authData; + }, + + getContextData: function (configObject = null) { + let contextData = {} + contextData.accountData = (configObject && configObject.hasOwnProperty("accountData")) ? configObject.accountData : null; + + if (contextData.accountData) { + contextData.accountname = contextData.accountData.getAccountProperty("accountname"); + contextData.user = contextData.accountData.getAccountProperty("user"); + contextData.host = contextData.accountData.getAccountProperty("host"); + contextData.servertype = contextData.accountData.getAccountProperty("servertype"); + contextData.accountID = contextData.accountData.accountID; + } else { + contextData.accountname = (configObject && configObject.hasOwnProperty("accountname")) ? configObject.accountname : ""; + contextData.user = (configObject && configObject.hasOwnProperty("user")) ? configObject.user : ""; + contextData.host = (configObject && configObject.hasOwnProperty("host")) ? configObject.host : ""; + contextData.servertype = (configObject && configObject.hasOwnProperty("servertype")) ? configObject.servertype : ""; + contextData.accountID = ""; + } + + return contextData; + }, + + // prepare and patch OAuth2 object + getOAuthObj: function (configObject = null) { + let { + accountData, + accountname, + user, + host, + accountID, + servertype + } = this.getContextData(configObject); + + if (!["office365"].includes(servertype)) + return null; + + let config = {}; + let customID = eas.Base.getCustomeOauthClientID(); + switch (host) { + case "outlook.office365.com": + case "eas.outlook.com": + config = { + auth_uri: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize", + token_uri: "https://login.microsoftonline.com/common/oauth2/v2.0/token", + redirect_uri: "https://login.microsoftonline.com/common/oauth2/nativeclient", + client_id: customID != "" ? customID : "2980deeb-7460-4723-864a-f9b0f10cd992", + } + break; + + default: + return null; + } + + switch (host) { + case "outlook.office365.com": + config.scope = "offline_access https://outlook.office.com/.default"; + break; + case "eas.outlook.com": + config.scope = "offline_access https://outlook.office.com/EAS.AccessAsUser.All"; + break; + } + + let oauth = new OAuth2(config.scope, { + authorizationEndpoint: config.auth_uri, + tokenEndpoint: config.token_uri, + clientId: config.client_id, + clientSecret: config.client_secret + }); + oauth.requestWindowFeatures = "chrome,private,centerscreen,width=500,height=750"; + + // The v2 redirection endpoint differs from the default and needs manual override + oauth.redirectionEndpoint = config.redirect_uri; + + oauth.extraAuthParams = [ + // removed in beta 1.14.1, according to + // https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent#default-and-consent + // prompt = consent will always ask for admin consent, even if it was granted + //["prompt", "consent"], + ["login_hint", user], + ]; + + if (accountname) { + oauth.requestWindowTitle = "TbSync account <" + accountname + "> requests authorization."; + } else { + oauth.requestWindowTitle = "A TbSync account requests authorization."; + } + + + + + /* Adding custom methods to the oauth object */ + + oauth.asyncConnect = async function (rv) { + rv.error = ""; + // This function gets called if we have no accessToken, or the token + // is expired. Load current data from password manager into the + // properties used by the OAuth module. + oauth.accessToken = oauth.getToken("accessToken"); + oauth.refreshToken = oauth.getToken("refreshToken"); + oauth.tokenExpires = oauth.getToken("tokenExpires"); + + try { + // refresh = false will do nothing and resolve immediately, if + // a valid accessToken exists. + await oauth.connect(/* with UI */ true, /* refresh */ false); + } catch (e) { + rv.error = eas.tools.isString(e) ? e : JSON.stringify(e); + } + + await oauth.setToken("accessToken", oauth.accessToken); + await oauth.setToken("refreshToken", oauth.refreshToken); + await oauth.setToken("tokenExpires", oauth.tokenExpires); + rv.tokens = oauth.tokens; + + if (!rv.error) { + return true; + } + + try { + switch (JSON.parse(rv.error).error) { + case "invalid_grant": + await oauth.setToken("accessToken", ""); + await oauth.setToken("refreshToken", ""); + await oauth.setToken("tokenExpires", 0); + rv.tokens = oauth.tokens; + return true; + + case "cancelled": + rv.error = "OAuthAbortError"; + break; + + default: + rv.error = "OAuthServerError::" + rv.error; + break; + } + } catch (e) { + rv.error = "OAuthServerError::" + rv.error; + Components.utils.reportError(e); + } + rv.tokens = oauth.tokens; + return false; + }; + + oauth.isExpired = function () { + const OAUTH_GRACE_TIME = 30 * 1000; + return (oauth.getToken("tokenExpires") - OAUTH_GRACE_TIME < new Date().getTime()); + }; + + const OAUTHVALUES = [ + ["access", "", "accessToken"], + ["refresh", "", "refreshToken"], + ["expires", Number.MAX_VALUE, "tokenExpires"], + ]; + + // returns a JSON string containing all the oauth values + Object.defineProperty(oauth, "tokens", { + get: function () { + let tokensObj = {}; + for (let oauthValue of OAUTHVALUES) { + // use the system value or if not defined the default + tokensObj[oauthValue[0]] = this[oauthValue[2]] || oauthValue[1]; + } + return JSON.stringify(tokensObj); + }, + enumerable: true, + }); + + if (accountData) { + // authData allows us to access the password manager values belonging to this account/calendar + // simply by authdata.username and authdata.password + oauth.authData = TbSync.providers.eas.network.getAuthData(accountData); + + oauth.parseAndSanitizeTokenString = function (tokenString) { + let _tokensObj = {}; + try { + _tokensObj = JSON.parse(tokenString); + } catch (e) { } + + let tokensObj = {}; + for (let oauthValue of OAUTHVALUES) { + // use the provided value or if not defined the default + tokensObj[oauthValue[0]] = (_tokensObj && _tokensObj.hasOwnProperty(oauthValue[0])) + ? _tokensObj[oauthValue[0]] + : oauthValue[1]; + } + return tokensObj; + }; + + oauth.getToken = function (tokenName) { + let oauthValue = OAUTHVALUES.find(e => e[2] == tokenName); + return oauth.parseAndSanitizeTokenString(oauth.authData.password)[oauthValue[0]]; + }; + + oauth.setToken = async function (tokenName, val) { + oauth[tokenName] = val; + + let oauthValue = OAUTHVALUES.find(e => e[2] == tokenName); + let tokens = oauth.parseAndSanitizeTokenString(oauth.authData.password); + let valueChanged = (val != tokens[oauthValue[0]]) + if (valueChanged) { + tokens[oauthValue[0]] = val; + await oauth.authData.updateLoginData(oauth.authData.user, JSON.stringify(tokens)); + } + }; + } else { + oauth.getToken = function (tokenName) { + return oauth[tokenName]; + }; + + oauth.setToken = async function (tokenName, val) { + oauth[tokenName] = val; + }; + } + + return oauth; + }, + + getOAuthValue: function (currentTokenString, type = "access") { + try { + let tokens = JSON.parse(currentTokenString); + if (tokens.hasOwnProperty(type)) + return tokens[type]; + } catch (e) { + //NOOP + } + return ""; + }, + + sendRequest: async function (wbxml, command, syncData, allowSoftFail = false) { + let ALLOWED_RETRIES = { + PasswordPrompt: 3, + NetworkError: 1, + } + + let rv = {}; + let oauthData = eas.network.getOAuthObj({ accountData: syncData.accountData }); + let syncState = syncData.getSyncState().state; + + for (; ;) { + + if (rv.errorType) { + let retry = false; + + if (ALLOWED_RETRIES[rv.errorType] > 0) { + ALLOWED_RETRIES[rv.errorType]--; + + + switch (rv.errorType) { + + case "PasswordPrompt": + { + + if (oauthData) { + await oauthData.setToken("accessToken", ""); + retry = true; + } else { + let authData = eas.network.getAuthData(syncData.accountData); + syncData.setSyncState("passwordprompt"); + let promptData = { + windowID: "auth:" + syncData.accountData.accountID, + accountname: syncData.accountData.getAccountProperty("accountname"), + usernameLocked: syncData.accountData.isConnected(), + username: authData.user + } + let credentials = await TbSync.passwordManager.asyncPasswordPrompt(promptData, eas.openWindows); + if (credentials) { + retry = true; + await authData.updateLoginData(credentials.username, credentials.password); + } + } + } + break; + + case "NetworkError": + { + // Could not connect to server. Can we rerun autodiscover? + // Note: Autodiscover is currently not supported by OAuth + if (syncData.accountData.getAccountProperty("servertype") == "auto" && !oauthData) { + let errorcode = await eas.network.updateServerConnectionViaAutodiscover(syncData); + console.log("ERR: " + errorcode); + if (errorcode == 200) { + // autodiscover succeeded, retry with new data + retry = true; + } else if (errorcode == 401) { + // manipulate rv to run password prompt + ALLOWED_RETRIES[rv.errorType]++; + rv.errorType = "PasswordPrompt"; + rv.errorObj = eas.sync.finish("error", "401"); + continue; // with the next loop, skip connection to the server + } + } + } + break; + + } + } + + if (!retry) throw rv.errorObj; + } + + // check OAuth situation before connecting + if (oauthData && (!oauthData.getToken("accessToken") || oauthData.isExpired())) { + syncData.setSyncState("oauthprompt"); + let _rv = {} + if (!(await oauthData.asyncConnect(_rv))) { + throw eas.sync.finish("error", _rv.error); + } + } + + // Return to original syncstate + if (syncState != syncData.getSyncState().state) { + syncData.setSyncState(syncState); + } + rv = await this.sendRequestPromise(wbxml, command, syncData, allowSoftFail); + + if (rv.errorType) { + // make sure, there is a valid ALLOWED_RETRIES setting for the returned error + if (rv.errorType && !ALLOWED_RETRIES.hasOwnProperty(rv.errorType)) { + ALLOWED_RETRIES[rv.errorType] = 1; + } + } else { + return rv; + } + } + }, + + sendRequestPromise: function (wbxml, command, syncData, allowSoftFail = false) { + let msg = "Sending data <" + syncData.getSyncState().state + "> for " + syncData.accountData.getAccountProperty("accountname"); + if (syncData.currentFolderData) msg += " (" + syncData.currentFolderData.getFolderProperty("foldername") + ")"; + syncData.request = eas.network.logXML(wbxml, msg); + syncData.response = ""; + + let connection = eas.network.getAuthData(syncData.accountData); + let userAgent = syncData.accountData.getAccountProperty("useragent"); //plus calendar.useragent.extra = Lightning/5.4.5.2 + let deviceType = syncData.accountData.getAccountProperty("devicetype"); + let deviceId = syncData.accountData.getAccountProperty("deviceId"); + + TbSync.dump("Sending (EAS v" + syncData.accountData.getAccountProperty("asversion") + ")", "POST " + eas.network.getEasURL(syncData.accountData) + '?Cmd=' + command + '&User=' + encodeURIComponent(connection.user) + '&DeviceType=' + deviceType + '&DeviceId=' + deviceId, true); + + const textEncoder = new TextEncoder(); + let encoded = textEncoder.encode(wbxml); + // console.log("wbxml: " + wbxml); + // console.log("byte array: " + encoded); + // console.log("length :" + wbxml.length + " vs " + encoded.byteLength + " vs " + encoded.length); + + let contextData = eas.network.getContextData({ accountData: syncData.accountData }); + let uri = Services.io.newURI(eas.network.getEasURL(syncData.accountData) + '?Cmd=' + command + '&User=' + encodeURIComponent(connection.user) + '&DeviceType=' + encodeURIComponent(deviceType) + '&DeviceId=' + deviceId); + return new Promise(function (resolve, reject) { + syncData.req = getSandBoxedXHR(contextData, uri); + syncData.req.mozBackgroundRequest = true; + syncData.req.open("POST", uri.spec, true); + syncData.req.overrideMimeType("text/plain"); + syncData.req.setRequestHeader("User-Agent", userAgent); + syncData.req.setRequestHeader("Content-Type", "application/vnd.ms-sync.wbxml"); + if (connection.password) { + if (eas.network.getOAuthObj({ accountData: syncData.accountData })) { + syncData.req.setRequestHeader("Authorization", 'Bearer ' + eas.network.getOAuthValue(connection.password, "access")); + } else { + syncData.req.setRequestHeader("Authorization", 'Basic ' + TbSync.tools.b64encode(connection.user + ':' + connection.password)); + } + } + + if (syncData.accountData.getAccountProperty("asversion") == "2.5") { + syncData.req.setRequestHeader("MS-ASProtocolVersion", "2.5"); + } else { + syncData.req.setRequestHeader("MS-ASProtocolVersion", "14.0"); + } + syncData.req.setRequestHeader("Content-Length", encoded.length); + if (syncData.accountData.getAccountProperty("provision")) { + syncData.req.setRequestHeader("X-MS-PolicyKey", syncData.accountData.getAccountProperty("policykey")); + TbSync.dump("PolicyKey used", syncData.accountData.getAccountProperty("policykey")); + } + + syncData.req.timeout = eas.Base.getConnectionTimeout(); + + syncData.req.ontimeout = function () { + if (allowSoftFail) { + resolve(""); + } else { + reject(eas.sync.finish("error", "timeout")); + } + }; + + syncData.req.onerror = function () { + if (allowSoftFail) { + resolve(""); + } else { + let error = TbSync.network.createTCPErrorFromFailedXHR(syncData.req) || "networkerror"; + let rv = {}; + rv.errorObj = eas.sync.finish("error", error); + rv.errorType = "NetworkError"; + resolve(rv); + } + }; + + syncData.req.onload = function () { + let response = syncData.req.responseText; + + // Debug: Log received cookies. + const channel = syncData.req.channel.QueryInterface(Ci.nsIHttpChannel); + const SET_COOKIE_REGEXP = /set-cookie/i; + channel.visitOriginalResponseHeaders({ + visitHeader(name, value) { + if (SET_COOKIE_REGEXP.test(name)) { + console.log("Received cookie", value); + } + }, + }); + + switch (syncData.req.status) { + + case 200: //OK + let msg = "Receiving data <" + syncData.getSyncState().state + "> for " + syncData.accountData.getAccountProperty("accountname"); + if (syncData.currentFolderData) msg += " (" + syncData.currentFolderData.getFolderProperty("foldername") + ")"; + syncData.response = eas.network.logXML(response, msg); + + //What to do on error? IS this an error? Yes! + if (!allowSoftFail && response.length !== 0 && response.substr(0, 4) !== String.fromCharCode(0x03, 0x01, 0x6A, 0x00)) { + TbSync.dump("Recieved Data", "Expecting WBXML but got junk (request status = " + syncData.req.status + ", ready state = " + syncData.req.readyState + "\n>>>>>>>>>>\n" + response + "\n<<<<<<<<<<\n"); + reject(eas.sync.finish("warning", "invalid")); + } else { + resolve(response); + } + break; + + case 401: // AuthError + case 403: // Forbiddden (some servers send forbidden on AuthError, like Freenet) + let rv = {}; + rv.errorObj = eas.sync.finish("error", "401"); + rv.errorType = "PasswordPrompt"; + resolve(rv); + break; + + case 449: // Request for new provision (enable it if needed) + //enable provision + syncData.accountData.setAccountProperty("provision", true); + syncData.accountData.resetAccountProperty("policykey"); + reject(eas.sync.finish("resyncAccount", syncData.req.status)); + break; + + case 451: // Redirect - update host and login manager + let header = syncData.req.getResponseHeader("X-MS-Location"); + let newHost = header.slice(header.indexOf("://") + 3, header.indexOf("/M")); + + TbSync.dump("redirect (451)", "header: " + header + ", oldHost: " + syncData.accountData.getAccountProperty("host") + ", newHost: " + newHost); + + syncData.accountData.setAccountProperty("host", newHost); + reject(eas.sync.finish("resyncAccount", syncData.req.status)); + break; + + default: + if (allowSoftFail) { + resolve(""); + } else { + reject(eas.sync.finish("error", "httperror::" + syncData.req.status)); + } + } + }; + + syncData.req.send(encoded); + + }); + }, + + + + + + + + + + + // RESPONSE EVALUATION + + logXML: function (wbxml, what) { + let rawxml = eas.wbxmltools.convert2xml(wbxml); + let xml = null; + if (rawxml) { + xml = rawxml.split('><').join('>\n<'); + } + + //include xml in log, if userdatalevel 2 or greater + if (TbSync.prefs.getIntPref("log.userdatalevel") > 1) { + + //log raw wbxml if userdatalevel is 3 or greater + if (TbSync.prefs.getIntPref("log.userdatalevel") > 2) { + let charcodes = []; + for (let i = 0; i < wbxml.length; i++) charcodes.push(wbxml.charCodeAt(i).toString(16)); + let bytestring = charcodes.join(" "); + TbSync.dump("WBXML: " + what, "\n" + bytestring); + } + + if (xml) { + //raw xml is save xml with all special chars in user data encoded by encodeURIComponent - KEEP that in order to be able to analyze logged XML + //let xml = decodeURIComponent(rawxml.split('><').join('>\n<')); + TbSync.dump("XML: " + what, "\n" + xml); + } else { + TbSync.dump("XML: " + what, "\nFailed to convert WBXML to XML!\n"); + } + } + + return xml; + }, + + //returns false on parse error and null on empty response (if allowed) + getDataFromResponse: function (wbxml, allowEmptyResponse = !eas.flags.allowEmptyResponse) { + //check for empty wbxml + if (wbxml.length === 0) { + if (allowEmptyResponse) return null; + else throw eas.sync.finish("warning", "empty-response"); + } + + //convert to save xml (all special chars in user data encoded by encodeURIComponent) and check for parse errors + let xml = eas.wbxmltools.convert2xml(wbxml); + if (xml === false) { + throw eas.sync.finish("warning", "wbxml-parse-error"); + } + + //retrieve data and check for empty data (all returned data fields are already decoded by decodeURIComponent) + let wbxmlData = eas.xmltools.getDataFromXMLString(xml); + if (wbxmlData === null) { + if (allowEmptyResponse) return null; + else throw eas.sync.finish("warning", "response-contains-no-data"); + } + + //debug + eas.xmltools.printXmlData(wbxmlData, false); //do not include ApplicationData in log + return wbxmlData; + }, + + updateSynckey: function (syncData, wbxmlData) { + let synckey = eas.xmltools.getWbxmlDataField(wbxmlData, "Sync.Collections.Collection.SyncKey"); + + if (synckey) { + // This COULD be a cause of problems... + syncData.synckey = synckey; + syncData.currentFolderData.setFolderProperty("synckey", synckey); + } else { + throw eas.sync.finish("error", "wbxmlmissingfield::Sync.Collections.Collection.SyncKey"); + } + }, + + checkStatus: function (syncData, wbxmlData, path, rootpath = "", allowSoftFail = false) { + //path is relative to wbxmlData + //rootpath is the absolute path and must be specified, if wbxml is not the root node and thus path is not the rootpath + let status = eas.xmltools.getWbxmlDataField(wbxmlData, path); + let fullpath = (rootpath == "") ? path : rootpath; + let elements = fullpath.split("."); + let type = elements[0]; + + //check if fallback to main class status: the answer could just be a "Sync.Status" instead of a "Sync.Collections.Collections.Status" + if (status === false) { + let mainStatus = eas.xmltools.getWbxmlDataField(wbxmlData, type + "." + elements[elements.length - 1]); + if (mainStatus === false) { + //both possible status fields are missing, abort + throw eas.sync.finish("warning", "wbxmlmissingfield::" + fullpath, "Request:\n" + syncData.request + "\n\nResponse:\n" + syncData.response); + } else { + //the alternative status could be extracted + status = mainStatus; + fullpath = type + "." + elements[elements.length - 1]; + } + } + + //check if all is fine (not bad) + if (status == "1") { + return ""; + } + + TbSync.dump("wbxml status check", type + ": " + fullpath + " = " + status); + + //handle errrors based on type + let statusType = type + "." + status; + switch (statusType) { + case "Sync.3": /* + MUST return to SyncKey element value of 0 for the collection. The client SHOULD either delete any items that were added + since the last successful Sync or the client MUST add those items back to the server after completing the full resynchronization + */ + TbSync.eventlog.add("warning", syncData.eventLogInfo, "Forced Folder Resync", "Request:\n" + syncData.request + "\n\nResponse:\n" + syncData.response); + syncData.currentFolderData.remove(); + throw eas.sync.finish("resyncFolder", statusType); + + case "Sync.4": //Malformed request + case "Sync.5": //Temporary server issues or invalid item + case "Sync.6": //Invalid item + case "Sync.8": //Object not found + if (allowSoftFail) return statusType; + throw eas.sync.finish("warning", statusType, "Request:\n" + syncData.request + "\n\nResponse:\n" + syncData.response); + + case "Sync.7": //The client has changed an item for which the conflict policy indicates that the server's changes take precedence. + case "Sync.9": //User account could be out of disk space, also send if no write permission (TODO) + return ""; + + case "FolderDelete.3": // special system folder - fatal error + case "FolderDelete.6": // error on server + throw eas.sync.finish("warning", statusType, "Request:\n" + syncData.request + "\n\nResponse:\n" + syncData.response); + + case "FolderDelete.4": // folder does not exist - resync ( we allow delete only if folder is not subscribed ) + case "FolderDelete.9": // invalid synchronization key - resync + case "FolderSync.9": // invalid synchronization key - resync + case "Sync.12": // folder hierarchy changed + { + let folders = syncData.accountData.getAllFoldersIncludingCache(); + for (let folder of folders) { + folder.remove(); + } + // reset account + eas.Base.onEnableAccount(syncData.accountData); + throw eas.sync.finish("resyncAccount", statusType, "Request:\n" + syncData.request + "\n\nResponse:\n" + syncData.response); + } + } + + //handle global error (https://msdn.microsoft.com/en-us/library/ee218647(v=exchg.80).aspx) + let descriptions = {}; + switch (status) { + case "101": //invalid content + case "102": //invalid wbxml + case "103": //invalid xml + throw eas.sync.finish("error", "global." + status, "Request:\n" + syncData.request + "\n\nResponse:\n" + syncData.response); + + case "109": descriptions["109"] = "DeviceTypeMissingOrInvalid"; + case "112": descriptions["112"] = "ActiveDirectoryAccessDenied"; + case "126": descriptions["126"] = "UserDisabledForSync"; + case "127": descriptions["127"] = "UserOnNewMailboxCannotSync"; + case "128": descriptions["128"] = "UserOnLegacyMailboxCannotSync"; + case "129": descriptions["129"] = "DeviceIsBlockedForThisUser"; + case "130": descriptions["120"] = "AccessDenied"; + case "131": descriptions["131"] = "AccountDisabled"; + throw eas.sync.finish("error", "global.clientdenied" + "::" + status + "::" + descriptions[status]); + + case "110": //server error - abort and disable autoSync for 30 minutes + { + let noAutosyncUntil = 30 * 60000 + Date.now(); + let humanDate = new Date(noAutosyncUntil).toUTCString(); + syncData.accountData.setAccountProperty("noAutosyncUntil", noAutosyncUntil); + throw eas.sync.finish("error", "global." + status, "AutoSync disabled until: " + humanDate + " \n\nRequest:\n" + syncData.request + "\n\nResponse:\n" + syncData.response); + + /* // reset account + * let folders = syncData.accountData.getAllFoldersIncludingCache(); + * for (let folder of folders) { + * folder.remove(); + * } + * // reset account + * eas.Base.onEnableAccount(syncData.accountData); + * throw eas.sync.finish("resyncAccount", statusType, "Request:\n" + syncData.request + "\n\nResponse:\n" + syncData.response); + */ + } + + case "141": // The device is not provisionable + case "142": // DeviceNotProvisioned + case "143": // PolicyRefresh + case "144": // InvalidPolicyKey + //enable provision + syncData.accountData.setAccountProperty("provision", true); + syncData.accountData.resetAccountProperty("policykey"); + throw eas.sync.finish("resyncAccount", statusType); + + default: + if (allowSoftFail) return statusType; + throw eas.sync.finish("error", statusType, "Request:\n" + syncData.request + "\n\nResponse:\n" + syncData.response); + + } + }, + + + + + + + + + + + // WBXML COMM STUFF + + setDeviceInformation: async function (syncData) { + if (syncData.accountData.getAccountProperty("asversion") == "2.5" || !syncData.accountData.getAccountProperty("allowedEasCommands").split(",").includes("Settings")) { + return; + } + + syncData.setSyncState("prepare.request.setdeviceinfo"); + + let wbxml = wbxmltools.createWBXML(); + wbxml.switchpage("Settings"); + wbxml.otag("Settings"); + wbxml.otag("DeviceInformation"); + wbxml.otag("Set"); + wbxml.atag("Model", "Computer"); + wbxml.atag("FriendlyName", "TbSync on Device " + syncData.accountData.getAccountProperty("deviceId").substring(4)); + wbxml.atag("OS", Services.appinfo.OS); + wbxml.atag("UserAgent", syncData.accountData.getAccountProperty("useragent")); + wbxml.ctag(); + wbxml.ctag(); + wbxml.ctag(); + + syncData.setSyncState("send.request.setdeviceinfo"); + let response = await eas.network.sendRequest(wbxml.getBytes(), "Settings", syncData); + + syncData.setSyncState("eval.response.setdeviceinfo"); + let wbxmlData = eas.network.getDataFromResponse(response); + + eas.network.checkStatus(syncData, wbxmlData, "Settings.Status"); + }, + + getPolicykey: async function (syncData) { + //build WBXML to request provision + syncData.setSyncState("prepare.request.provision"); + let wbxml = eas.wbxmltools.createWBXML(); + wbxml.switchpage("Provision"); + wbxml.otag("Provision"); + wbxml.otag("Policies"); + wbxml.otag("Policy"); + wbxml.atag("PolicyType", (syncData.accountData.getAccountProperty("asversion") == "2.5") ? "MS-WAP-Provisioning-XML" : "MS-EAS-Provisioning-WBXML"); + wbxml.ctag(); + wbxml.ctag(); + wbxml.ctag(); + + for (let loop = 0; loop < 2; loop++) { + syncData.setSyncState("send.request.provision"); + let response = await eas.network.sendRequest(wbxml.getBytes(), "Provision", syncData); + + syncData.setSyncState("eval.response.provision"); + let wbxmlData = eas.network.getDataFromResponse(response); + let policyStatus = eas.xmltools.getWbxmlDataField(wbxmlData, "Provision.Policies.Policy.Status"); + let provisionStatus = eas.xmltools.getWbxmlDataField(wbxmlData, "Provision.Status"); + if (provisionStatus === false) { + throw eas.sync.finish("error", "wbxmlmissingfield::Provision.Status"); + } else if (provisionStatus != "1") { + //dump policy status as well + if (policyStatus) TbSync.dump("PolicyKey", "Received policy status: " + policyStatus); + throw eas.sync.finish("error", "provision::" + provisionStatus); + } + + //reaching this point: provision status was ok + let policykey = eas.xmltools.getWbxmlDataField(wbxmlData, "Provision.Policies.Policy.PolicyKey"); + switch (policyStatus) { + case false: + throw eas.sync.finish("error", "wbxmlmissingfield::Provision.Policies.Policy.Status"); + + case "2": + //server does not have a policy for this device: disable provisioning + syncData.accountData.setAccountProperty("provision", false) + syncData.accountData.resetAccountProperty("policykey"); + throw eas.sync.finish("resyncAccount", "NoPolicyForThisDevice"); + + case "1": + if (policykey === false) { + throw eas.sync.finish("error", "wbxmlmissingfield::Provision.Policies.Policy.PolicyKey"); + } + TbSync.dump("PolicyKey", "Received policykey (" + loop + "): " + policykey); + syncData.accountData.setAccountProperty("policykey", policykey); + break; + + default: + throw eas.sync.finish("error", "policy." + policyStatus); + } + + //build WBXML to acknowledge provision + syncData.setSyncState("prepare.request.provision"); + wbxml = eas.wbxmltools.createWBXML(); + wbxml.switchpage("Provision"); + wbxml.otag("Provision"); + wbxml.otag("Policies"); + wbxml.otag("Policy"); + wbxml.atag("PolicyType", (syncData.accountData.getAccountProperty("asversion") == "2.5") ? "MS-WAP-Provisioning-XML" : "MS-EAS-Provisioning-WBXML"); + wbxml.atag("PolicyKey", policykey); + wbxml.atag("Status", "1"); + wbxml.ctag(); + wbxml.ctag(); + wbxml.ctag(); + + //this wbxml will be used by Send at the top of this loop + } + }, + + getSynckey: async function (syncData) { + syncData.setSyncState("prepare.request.synckey"); + //build WBXML to request a new syncKey + let wbxml = eas.wbxmltools.createWBXML(); + wbxml.otag("Sync"); + wbxml.otag("Collections"); + wbxml.otag("Collection"); + if (syncData.accountData.getAccountProperty("asversion") == "2.5") wbxml.atag("Class", syncData.type); + wbxml.atag("SyncKey", "0"); + wbxml.atag("CollectionId", syncData.currentFolderData.getFolderProperty("serverID")); + wbxml.ctag(); + wbxml.ctag(); + wbxml.ctag(); + + syncData.setSyncState("send.request.synckey"); + let response = await eas.network.sendRequest(wbxml.getBytes(), "Sync", syncData); + + syncData.setSyncState("eval.response.synckey"); + // get data from wbxml response + let wbxmlData = eas.network.getDataFromResponse(response); + //check status + eas.network.checkStatus(syncData, wbxmlData, "Sync.Collections.Collection.Status"); + //update synckey + eas.network.updateSynckey(syncData, wbxmlData); + }, + + getItemEstimate: async function (syncData) { + syncData.progressData.reset(); + + if (!syncData.accountData.getAccountProperty("allowedEasCommands").split(",").includes("GetItemEstimate")) { + return; //do not throw, this is optional + } + + syncData.setSyncState("prepare.request.estimate"); + + // BUILD WBXML + let wbxml = eas.wbxmltools.createWBXML(); + wbxml.switchpage("GetItemEstimate"); + wbxml.otag("GetItemEstimate"); + wbxml.otag("Collections"); + wbxml.otag("Collection"); + if (syncData.accountData.getAccountProperty("asversion") == "2.5") { //got this order for 2.5 directly from Microsoft support + wbxml.atag("Class", syncData.type); //only 2.5 + wbxml.atag("CollectionId", syncData.currentFolderData.getFolderProperty("serverID")); + wbxml.switchpage("AirSync"); + // required ! + // https://docs.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-ascmd/ffbefa62-e315-40b9-9cc6-f8d74b5f65d4 + if (syncData.type == "Calendar") wbxml.atag("FilterType", syncData.currentFolderData.accountData.getAccountProperty("synclimit")); + else wbxml.atag("FilterType", "0"); // we may filter incomplete tasks + + wbxml.atag("SyncKey", syncData.synckey); + wbxml.switchpage("GetItemEstimate"); + } else { //14.0 + wbxml.switchpage("AirSync"); + wbxml.atag("SyncKey", syncData.synckey); + wbxml.switchpage("GetItemEstimate"); + wbxml.atag("CollectionId", syncData.currentFolderData.getFolderProperty("serverID")); + wbxml.switchpage("AirSync"); + wbxml.otag("Options"); + // optional + if (syncData.type == "Calendar") wbxml.atag("FilterType", syncData.currentFolderData.accountData.getAccountProperty("synclimit")); + wbxml.atag("Class", syncData.type); + wbxml.ctag(); + wbxml.switchpage("GetItemEstimate"); + } + wbxml.ctag(); + wbxml.ctag(); + wbxml.ctag(); + + //SEND REQUEST + syncData.setSyncState("send.request.estimate"); + let response = await eas.network.sendRequest(wbxml.getBytes(), "GetItemEstimate", syncData, /* allowSoftFail */ true); + + //VALIDATE RESPONSE + syncData.setSyncState("eval.response.estimate"); + + // get data from wbxml response, some servers send empty response if there are no changes, which is not an error + let wbxmlData = eas.network.getDataFromResponse(response, eas.flags.allowEmptyResponse); + if (wbxmlData === null) return; + + let status = eas.xmltools.getWbxmlDataField(wbxmlData, "GetItemEstimate.Response.Status"); + let estimate = eas.xmltools.getWbxmlDataField(wbxmlData, "GetItemEstimate.Response.Collection.Estimate"); + + if (status && status == "1") { //do not throw on error, with EAS v2.5 I get error 2 for tasks and calendars ??? + syncData.progressData.reset(0, estimate); + } + }, + + getUserInfo: async function (syncData) { + if (!syncData.accountData.getAccountProperty("allowedEasCommands").split(",").includes("Settings")) { + return; + } + + syncData.setSyncState("prepare.request.getuserinfo"); + + let wbxml = eas.wbxmltools.createWBXML(); + wbxml.switchpage("Settings"); + wbxml.otag("Settings"); + wbxml.otag("UserInformation"); + wbxml.atag("Get"); + wbxml.ctag(); + wbxml.ctag(); + + syncData.setSyncState("send.request.getuserinfo"); + let response = await eas.network.sendRequest(wbxml.getBytes(), "Settings", syncData); + + + syncData.setSyncState("eval.response.getuserinfo"); + let wbxmlData = eas.network.getDataFromResponse(response); + + eas.network.checkStatus(syncData, wbxmlData, "Settings.Status"); + }, + + + + + + + + + + + // SEARCH + + getSearchResults: async function (accountData, currentQuery) { + + let _wbxml = eas.wbxmltools.createWBXML(); + _wbxml.switchpage("Search"); + _wbxml.otag("Search"); + _wbxml.otag("Store"); + _wbxml.atag("Name", "GAL"); + _wbxml.atag("Query", currentQuery); + _wbxml.otag("Options"); + _wbxml.atag("Range", "0-99"); //Z-Push needs a Range + //Not valid for GAL: https://msdn.microsoft.com/en-us/library/gg675461(v=exchg.80).aspx + //_wbxml.atag("DeepTraversal"); + //_wbxml.atag("RebuildResults"); + _wbxml.ctag(); + _wbxml.ctag(); + _wbxml.ctag(); + + let wbxml = _wbxml.getBytes(); + + eas.network.logXML(wbxml, "Send (GAL Search)"); + let command = "Search"; + + let authData = eas.network.getAuthData(accountData); + let oauthData = eas.network.getOAuthObj({ accountData }); + let userAgent = accountData.getAccountProperty("useragent"); //plus calendar.useragent.extra = Lightning/5.4.5.2 + let deviceType = accountData.getAccountProperty("devicetype"); + let deviceId = accountData.getAccountProperty("deviceId"); + + TbSync.dump("Sending (EAS v" + accountData.getAccountProperty("asversion") + ")", "POST " + eas.network.getEasURL(accountData) + '?Cmd=' + command + '&User=' + encodeURIComponent(authData.user) + '&DeviceType=' + deviceType + '&DeviceId=' + deviceId, true); + + for (let i = 0; i < 2; i++) { + // check OAuth situation before connecting + if (oauthData && (!oauthData.getToken("accessToken") || oauthData.isExpired())) { + let _rv = {} + if (!(await oauthData.asyncConnect(_rv))) { + throw eas.sync.finish("error", _rv.error); + } + } + + try { + let contextData = eas.network.getContextData({ accountData }); + let uri = Services.io.newURI(eas.network.getEasURL(accountData) + '?Cmd=' + command + '&User=' + encodeURIComponent(authData.user) + '&DeviceType=' + encodeURIComponent(deviceType) + '&DeviceId=' + deviceId); + let response = await new Promise(function (resolve, reject) { + let req = getSandBoxedXHR(contextData, uri); + req.mozBackgroundRequest = true; + req.open("POST", uri.spec, true); + req.overrideMimeType("text/plain"); + req.setRequestHeader("User-Agent", userAgent); + req.setRequestHeader("Content-Type", "application/vnd.ms-sync.wbxml"); + + if (authData.password) { + if (eas.network.getOAuthObj({ accountData })) { + req.setRequestHeader("Authorization", 'Bearer ' + eas.network.getOAuthValue(authData.password, "access")); + } else { + req.setRequestHeader("Authorization", 'Basic ' + TbSync.tools.b64encode(authData.user + ':' + authData.password)); + } + } + + if (accountData.getAccountProperty("asversion") == "2.5") { + req.setRequestHeader("MS-ASProtocolVersion", "2.5"); + } else { + req.setRequestHeader("MS-ASProtocolVersion", "14.0"); + } + req.setRequestHeader("Content-Length", wbxml.length); + if (accountData.getAccountProperty("provision")) { + req.setRequestHeader("X-MS-PolicyKey", accountData.getAccountProperty("policykey")); + TbSync.dump("PolicyKey used", accountData.getAccountProperty("policykey")); + } + + req.timeout = eas.Base.getConnectionTimeout(); + + req.ontimeout = function () { + reject("GAL Search timeout"); + }; + + req.onerror = function () { + reject("GAL Search Error"); + }; + + req.onload = function () { + let response = req.responseText; + + // Debug: Log received cookies. + const channel = req.channel.QueryInterface(Ci.nsIHttpChannel); + const SET_COOKIE_REGEXP = /set-cookie/i; + channel.visitOriginalResponseHeaders({ + visitHeader(name, value) { + if (SET_COOKIE_REGEXP.test(name)) { + console.log("Received cookie", value); + } + }, + }); + + switch (req.status) { + + case 200: //OK + eas.network.logXML(response, "Received (GAL Search"); + + //What to do on error? IS this an error? Yes! + if (response.length !== 0 && response.substr(0, 4) !== String.fromCharCode(0x03, 0x01, 0x6A, 0x00)) { + TbSync.dump("Recieved Data", "Expecting WBXML but got junk (request status = " + req.status + ", ready state = " + req.readyState + "\n>>>>>>>>>>\n" + response + "\n<<<<<<<<<<\n"); + reject("GAL Search Response Invalid"); + } else { + resolve(response); + } + break; + + case 401: // bad auth + resolve("401"); + break; + + default: + reject("GAL Search Failed: " + req.status); + } + }; + + req.send(wbxml); + + }); + + if (response === "401") { + // try to recover from bad auth via token refresh + if (oauthData) { + await oauthData.setToken("accessToken", ""); + continue; + } + } + + return response; + } catch (e) { + Components.utils.reportError(e); + return; + } + } + }, + + + + + + + + + + + // OPTIONS + + getServerOptions: async function (syncData) { + syncData.setSyncState("prepare.request.options"); + let authData = eas.network.getAuthData(syncData.accountData); + + let userAgent = syncData.accountData.getAccountProperty("useragent"); //plus calendar.useragent.extra = Lightning/5.4.5.2 + TbSync.dump("Sending", "OPTIONS " + eas.network.getEasURL(syncData.accountData)); + + let allowedRetries = 5; + let retry; + let oauthData = eas.network.getOAuthObj({ accountData: syncData.accountData }); + + do { + retry = false; + + // Check OAuth situation before connecting + if (oauthData && (!oauthData.getToken("accessToken") || oauthData.isExpired())) { + let _rv = {}; + syncData.setSyncState("oauthprompt"); + if (!(await oauthData.asyncConnect(_rv))) { + throw eas.sync.finish("error", _rv.error); + } + } + + let contextData = eas.network.getContextData({ accountData: syncData.accountData }); + let uri = Services.io.newURI(eas.network.getEasURL(syncData.accountData)); + let result = await new Promise(function (resolve, reject) { + syncData.req = getSandBoxedXHR(contextData, uri); + syncData.req.mozBackgroundRequest = true; + syncData.req.open("OPTIONS", uri.spec, true); + syncData.req.overrideMimeType("text/plain"); + syncData.req.setRequestHeader("User-Agent", userAgent); + if (authData.password) { + if (eas.network.getOAuthObj({ accountData: syncData.accountData })) { + syncData.req.setRequestHeader("Authorization", 'Bearer ' + eas.network.getOAuthValue(authData.password, "access")); + } else { + syncData.req.setRequestHeader("Authorization", 'Basic ' + TbSync.tools.b64encode(authData.user + ':' + authData.password)); + } + } + syncData.req.timeout = eas.Base.getConnectionTimeout(); + + syncData.req.ontimeout = function () { + resolve(); + }; + + syncData.req.onerror = function () { + let responseData = {}; + responseData["MS-ASProtocolVersions"] = syncData.req.getResponseHeader("MS-ASProtocolVersions"); + responseData["MS-ASProtocolCommands"] = syncData.req.getResponseHeader("MS-ASProtocolCommands"); + + TbSync.dump("EAS OPTIONS with response (status: " + syncData.req.status + ")", "\n" + + "responseText: " + syncData.req.responseText + "\n" + + "responseHeader(MS-ASProtocolVersions): " + responseData["MS-ASProtocolVersions"] + "\n" + + "responseHeader(MS-ASProtocolCommands): " + responseData["MS-ASProtocolCommands"]); + resolve(); + }; + + syncData.req.onload = function () { + syncData.setSyncState("eval.request.options"); + let responseData = {}; + + // Debug: Log received cookies. + const channel = syncData.req.channel.QueryInterface(Ci.nsIHttpChannel); + const SET_COOKIE_REGEXP = /set-cookie/i; + channel.visitOriginalResponseHeaders({ + visitHeader(name, value) { + if (SET_COOKIE_REGEXP.test(name)) { + console.log("Received cookie", value); + } + }, + }); + + switch (syncData.req.status) { + case 401: // AuthError + let rv = {}; + rv.errorObj = eas.sync.finish("error", "401"); + rv.errorType = "PasswordPrompt"; + resolve(rv); + break; + + case 200: + responseData["MS-ASProtocolVersions"] = syncData.req.getResponseHeader("MS-ASProtocolVersions"); + responseData["MS-ASProtocolCommands"] = syncData.req.getResponseHeader("MS-ASProtocolCommands"); + + TbSync.dump("EAS OPTIONS with response (status: 200)", "\n" + + "responseText: " + syncData.req.responseText + "\n" + + "responseHeader(MS-ASProtocolVersions): " + responseData["MS-ASProtocolVersions"] + "\n" + + "responseHeader(MS-ASProtocolCommands): " + responseData["MS-ASProtocolCommands"]); + + if (responseData && responseData["MS-ASProtocolCommands"] && responseData["MS-ASProtocolVersions"]) { + syncData.accountData.setAccountProperty("allowedEasCommands", responseData["MS-ASProtocolCommands"]); + syncData.accountData.setAccountProperty("allowedEasVersions", responseData["MS-ASProtocolVersions"]); + syncData.accountData.setAccountProperty("lastEasOptionsUpdate", Date.now()); + } + resolve(); + break; + + default: + resolve(); + break; + + } + }; + + syncData.setSyncState("send.request.options"); + syncData.req.send(); + + }); + + if (result && result.hasOwnProperty("errorType") && result.errorType == "PasswordPrompt") { + if (allowedRetries > 0) { + if (oauthData) { + await oauthData.setToken("accessToken", ""); + retry = true; + } else { + syncData.setSyncState("passwordprompt"); + let authData = eas.network.getAuthData(syncData.accountData); + let promptData = { + windowID: "auth:" + syncData.accountData.accountID, + accountname: syncData.accountData.getAccountProperty("accountname"), + usernameLocked: syncData.accountData.isConnected(), + username: authData.user + } + let credentials = await TbSync.passwordManager.asyncPasswordPrompt(promptData, eas.openWindows); + if (credentials) { + await authData.updateLoginData(credentials.username, credentials.password); + retry = true; + } + } + } + + if (!retry) { + throw result.errorObj; + } + } + + allowedRetries--; + } while (retry); + }, + + + + + + + + + + + // AUTODISCOVER + + updateServerConnectionViaAutodiscover: async function (syncData) { + syncData.setSyncState("prepare.request.autodiscover"); + let authData = eas.network.getAuthData(syncData.accountData); + + syncData.setSyncState("send.request.autodiscover"); + let result = await eas.network.getServerConnectionViaAutodiscover(authData.accountname, authData.user, authData.password, 30 * 1000); + + syncData.setSyncState("eval.response.autodiscover"); + if (result.errorcode == 200) { + //update account + syncData.accountData.setAccountProperty("host", eas.network.stripAutodiscoverUrl(result.server)); + syncData.accountData.setAccountProperty("user", result.user); + syncData.accountData.setAccountProperty("https", (result.server.substring(0, 5) == "https")); + } + + return result.errorcode; + }, + + stripAutodiscoverUrl: function (url) { + let u = url; + while (u.endsWith("/")) { u = u.slice(0, -1); } + if (u.endsWith("/Microsoft-Server-ActiveSync")) u = u.slice(0, -28); + else TbSync.dump("Received non-standard EAS url via autodiscover:", url); + + return u.split("//")[1]; //cut off protocol + }, + + getServerConnectionViaAutodiscover: async function (accountname, user, password, maxtimeout) { + let urls = []; + let parts = user.split("@"); + + urls.push({ "url": "https://autodiscover." + parts[1] + "/autodiscover/autodiscover.xml", "user": user }); + urls.push({ "url": "https://" + parts[1] + "/autodiscover/autodiscover.xml", "user": user }); + urls.push({ "url": "https://autodiscover." + parts[1] + "/Autodiscover/Autodiscover.xml", "user": user }); + urls.push({ "url": "https://" + parts[1] + "/Autodiscover/Autodiscover.xml", "user": user }); + + urls.push({ "url": "http://autodiscover." + parts[1] + "/autodiscover/autodiscover.xml", "user": user }); + urls.push({ "url": "http://" + parts[1] + "/autodiscover/autodiscover.xml", "user": user }); + urls.push({ "url": "http://autodiscover." + parts[1] + "/Autodiscover/Autodiscover.xml", "user": user }); + urls.push({ "url": "http://" + parts[1] + "/Autodiscover/Autodiscover.xml", "user": user }); + + let requests = []; + let responses = []; //array of objects {url, error, server} + + for (let i = 0; i < urls.length; i++) { + await TbSync.tools.sleep(200); + requests.push(eas.network.getServerConnectionViaAutodiscoverRedirectWrapper( + accountname, + urls[i].url, + urls[i].user, + password, + maxtimeout + )); + } + + try { + responses = await Promise.all(requests); + } catch (e) { + responses.push(e.result); //this is actually a success, see return value of getServerConnectionViaAutodiscoverRedirectWrapper() + } + + let result; + let log = []; + for (let r = 0; r < responses.length; r++) { + log.push("* " + responses[r].url + " @ " + responses[r].user + " : " + (responses[r].server ? responses[r].server : responses[r].error)); + + if (responses[r].server) { + result = { "server": responses[r].server, "user": responses[r].user, "error": "", "errorcode": 200 }; + break; + } + + if (responses[r].error == 403 || responses[r].error == 401) { + //we could still find a valid server, so just store this state + result = { "server": "", "user": responses[r].user, "errorcode": responses[r].error, "error": TbSync.getString("status." + responses[r].error, "eas") }; + } + } + + //this is only reached on fail, if no result defined yet, use general error + if (!result) { + result = { "server": "", "user": user, "error": TbSync.getString("autodiscover.Failed", "eas").replace("##user##", user), "errorcode": 503 }; + } + + TbSync.eventlog.add("error", new TbSync.EventLogInfo("eas"), result.error, log.join("\n")); + return result; + }, + + getServerConnectionViaAutodiscoverRedirectWrapper: async function (accountname, url, user, password, maxtimeout) { + let result = {}; + let method = "POST"; + let connection = { accountname, url, user }; + + do { + await TbSync.tools.sleep(200); + result = await eas.network.getServerConnectionViaAutodiscoverRequest(method, connection, password, maxtimeout); + method = ""; + + if (result.error == "redirect found") { + TbSync.dump("EAS autodiscover URL redirect", "\n" + connection.url + " @ " + connection.user + " => \n" + result.url + " @ " + result.user); + connection.url = result.url; + connection.user = result.user; + method = "POST"; + } + + } while (method); + + //invert reject and resolve, so we exit the promise group on success right away + if (result.server) { + let e = new Error("Not an error (early exit from promise group)"); + e.result = result; + throw e; + } else { + return result; + } + }, + + getServerConnectionViaAutodiscoverRequest: function (method, connection, password, maxtimeout) { + TbSync.dump("Querry EAS autodiscover URL", connection.url + " @ " + connection.user); + + return new Promise(function (resolve, reject) { + + let xml = '\r\n'; + xml += '\r\n'; + xml += '\r\n'; + xml += '' + connection.user + '\r\n'; + xml += 'http://schemas.microsoft.com/exchange/autodiscover/mobilesync/responseschema/2006\r\n'; + xml += '\r\n'; + xml += '\r\n'; + + let userAgent = eas.prefs.getCharPref("clientID.useragent"); //plus calendar.useragent.extra = Lightning/5.4.5.2 + let uri = Services.io.newURI(connection.url); + let req = getSandBoxedXHR(connection, uri); + req.mozBackgroundRequest = true; + req.open(method, uri.spec, true); + req.timeout = maxtimeout; + req.setRequestHeader("User-Agent", userAgent); + + let secure = (connection.url.substring(0, 8).toLowerCase() == "https://"); + + if (method == "POST") { + req.setRequestHeader("Content-Length", xml.length); + req.setRequestHeader("Content-Type", "text/xml"); + if (secure && password) { + // OAUTH accounts cannot authenticate against the standard discovery services + // updateServerConnectionViaAutodiscover() is not passing them on + req.setRequestHeader("Authorization", "Basic " + TbSync.tools.b64encode(connection.user + ":" + password)); + } + } + + req.ontimeout = function () { + TbSync.dump("EAS autodiscover with timeout", "\n" + connection.url + " => \n" + req.responseURL); + resolve({ "url": req.responseURL, "error": "timeout", "server": "", "user": connection.user }); + }; + + req.onerror = function () { + let error = TbSync.network.createTCPErrorFromFailedXHR(req); + if (!error) error = req.responseText; + + // CORS violations can happen on redirects. They come back as NS_ERROR_DOM_BAD_URI. + if (error == "network::NS_ERROR_DOM_BAD_URI" && req.channel.URI.spec != uri.spec) { + resolve({ "url": req.channel.URI.spec, "error": "redirect found", "server": "", "user": connection.user }); + return; + } + + TbSync.dump("EAS autodiscover with error (" + error + ")", "\n" + connection.url + " => \n" + req.responseURL); + resolve({ "url": req.responseURL, "error": error, "server": "", "user": connection.user }); + }; + + req.onload = function () { + //initiate rerun on redirects + if (req.responseURL != connection.url) { + resolve({ "url": req.responseURL, "error": "redirect found", "server": "", "user": connection.user }); + return; + } + + //ignore POST without autherization (we just do them to get redirect information) + if (!secure) { + resolve({ "url": req.responseURL, "error": "unsecure POST", "server": "", "user": connection.user }); + return; + } + + //evaluate secure POST requests which have not been redirected + TbSync.dump("EAS autodiscover POST with status (" + req.status + ")", "\n" + connection.url + " => \n" + req.responseURL + "\n[" + req.responseText + "]"); + + if (req.status === 200) { + let data = null; + // getDataFromXMLString may throw an error which cannot be catched outside onload, + // because we are in an async callback of the surrounding Promise + // Alternatively we could just return the responseText and do any data analysis outside of the Promise + try { + data = eas.xmltools.getDataFromXMLString(req.responseText); + } catch (e) { + resolve({ "url": req.responseURL, "error": "bad response", "server": "", "user": connection.user }); + return; + } + + if (!(data === null) && data.Autodiscover && data.Autodiscover.Response && data.Autodiscover.Response.Action) { + // "Redirect" or "Settings" are possible + if (data.Autodiscover.Response.Action.Redirect) { + // redirect, start again with new user + let newuser = action.Redirect; + resolve({ "url": req.responseURL, "error": "redirect found", "server": "", "user": newuser }); + + } else if (data.Autodiscover.Response.Action.Settings) { + // get server settings + let server = eas.xmltools.nodeAsArray(data.Autodiscover.Response.Action.Settings.Server); + + for (let count = 0; count < server.length; count++) { + if (server[count].Type == "MobileSync" && server[count].Url) { + resolve({ "url": req.responseURL, "error": "", "server": server[count].Url, "user": connection.user }); + return; + } + } + } + } else { + resolve({ "url": req.responseURL, "error": "invalid", "server": "", "user": connection.user }); + } + } else { + resolve({ "url": req.responseURL, "error": req.status, "server": "", "user": connection.user }); + } + }; + + req.send(xml); + }); + }, + + getServerConnectionViaAutodiscoverV2JsonRequest: function (accountname, user, url, maxtimeout) { + TbSync.dump("Querry EAS autodiscover V2 URL", url); + + return new Promise(function (resolve, reject) { + + let userAgent = eas.prefs.getCharPref("clientID.useragent"); //plus calendar.useragent.extra = Lightning/5.4.5.2 + let uri = Services.io.newURI(url); + let req = getSandBoxedXHR({ accountname, user }, uri); + req.mozBackgroundRequest = true; + req.open("GET", uri.spec, true); + req.timeout = maxtimeout; + req.setRequestHeader("User-Agent", userAgent); + + req.ontimeout = function () { + TbSync.dump("EAS autodiscover V2 with timeout", "\n" + url + " => \n" + req.responseURL); + resolve({ "url": req.responseURL, "error": "timeout", "server": "" }); + }; + + req.onerror = function () { + let error = TbSync.network.createTCPErrorFromFailedXHR(req); + if (!error) error = req.responseText; + TbSync.dump("EAS autodiscover V2 with error (" + error + ")", "\n" + url + " => \n" + req.responseURL); + resolve({ "url": req.responseURL, "error": error, "server": "" }); + }; + + req.onload = function () { + if (req.status === 200) { + let data = JSON.parse(req.responseText); + + if (data && data.Url) { + resolve({ "url": req.responseURL, "error": "", "server": eas.network.stripAutodiscoverUrl(data.Url) }); + } else { + resolve({ "url": req.responseURL, "error": "invalid", "server": "" }); + } + return; + } + + resolve({ "url": req.responseURL, "error": req.status, "server": "" }); + }; + + req.send(); + }); + } +} diff -Nru eas4tbsync-4.11/content/includes/sync.js eas4tbsync-4.17/content/includes/sync.js --- eas4tbsync-4.11/content/includes/sync.js 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/content/includes/sync.js 2025-05-15 11:21:20.000000000 +0000 @@ -1,1505 +1,1510 @@ -/* - * This file is part of EAS-4-TbSync. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -"use strict"; - -var { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); -var { TbSync } = ChromeUtils.import("chrome://tbsync/content/tbsync.jsm"); - -XPCOMUtils.defineLazyModuleGetters(this, { - CalRecurrenceInfo: "resource:///modules/CalRecurrenceInfo.jsm", -}); - -// - https://dxr.mozilla.org/comm-central/source/calendar/base/public/calIEvent.idl -// - https://dxr.mozilla.org/comm-central/source/calendar/base/public/calIItemBase.idl -// - https://dxr.mozilla.org/comm-central/source/calendar/base/public/calICalendar.idl -// - https://dxr.mozilla.org/comm-central/source/calendar/base/modules/calAsyncUtils.jsm - -// https://msdn.microsoft.com/en-us/library/dd299454(v=exchg.80).aspx - -var sync = { - - - - finish: function (aStatus = "", msg = "", details = "") { - let status = TbSync.StatusData.SUCCESS - switch (aStatus) { - - case "": - case "ok": - status = TbSync.StatusData.SUCCESS; - break; - - case "info": - status = TbSync.StatusData.INFO; - break; - - case "resyncAccount": - status = TbSync.StatusData.ACCOUNT_RERUN; - break; - - case "resyncFolder": - status = TbSync.StatusData.FOLDER_RERUN; - break; - - case "warning": - status = TbSync.StatusData.WARNING; - break; - - case "error": - status = TbSync.StatusData.ERROR; - break; - - default: - console.log("TbSync/EAS: Unknown status <"+aStatus+">"); - status = TbSync.StatusData.ERROR; - break; - } - - let e = new Error(); - e.name = "eas4tbsync"; - e.message = status.toUpperCase() + ": " + msg.toString() + " (" + details.toString() + ")"; - e.statusData = new TbSync.StatusData(status, msg.toString(), details.toString()); - return e; - }, - - - resetFolderSyncInfo: function (folderData) { - folderData.resetFolderProperty("synckey"); - folderData.resetFolderProperty("lastsynctime"); - }, - - - // update folders avail on server and handle added, removed and renamed - // folders - folderList: async function(syncData) { - //should we recheck options/commands? Always check, if we have no info about asversion! - if (syncData.accountData.getAccountProperty("asversion", "") == "" || (Date.now() - syncData.accountData.getAccountProperty("lastEasOptionsUpdate")) > 86400000 ) { - await eas.network.getServerOptions(syncData); - } - - //only update the actual used asversion, if we are currently not connected or it has not yet been set - if (syncData.accountData.getAccountProperty("asversion", "") == "" || !syncData.accountData.isConnected()) { - //eval the currently in the UI selected EAS version - let asversionselected = syncData.accountData.getAccountProperty("asversionselected"); - let allowedVersionsString = syncData.accountData.getAccountProperty("allowedEasVersions").trim(); - let allowedVersionsArray = allowedVersionsString.split(","); - - if (asversionselected == "auto") { - if (allowedVersionsArray.includes("14.0")) syncData.accountData.setAccountProperty("asversion", "14.0"); - else if (allowedVersionsArray.includes("2.5")) syncData.accountData.setAccountProperty("asversion", "2.5"); - else if (allowedVersionsString == "") { - throw eas.sync.finish("error", "InvalidServerOptions"); - } else { - throw eas.sync.finish("error", "nosupportedeasversion::"+allowedVersionsArray.join(", ")); - } - } else if (allowedVersionsString != "" && !allowedVersionsArray.includes(asversionselected)) { - throw eas.sync.finish("error", "notsupportedeasversion::"+asversionselected+"::"+allowedVersionsArray.join(", ")); - } else { - //just use the value set by the user - syncData.accountData.setAccountProperty("asversion", asversionselected); - } - } - - //do we need to get a new policy key? - if (syncData.accountData.getAccountProperty("provision") && syncData.accountData.getAccountProperty("policykey") == "0") { - await eas.network.getPolicykey(syncData); - } - - //set device info - await eas.network.setDeviceInformation(syncData); - - syncData.setSyncState("prepare.request.folders"); - let foldersynckey = syncData.accountData.getAccountProperty("foldersynckey"); - - //build WBXML to request foldersync - let wbxml = eas.wbxmltools.createWBXML(); - wbxml.switchpage("FolderHierarchy"); - wbxml.otag("FolderSync"); - wbxml.atag("SyncKey", foldersynckey); - wbxml.ctag(); - - syncData.setSyncState("send.request.folders"); - let response = await eas.network.sendRequest(wbxml.getBytes(), "FolderSync", syncData); - - syncData.setSyncState("eval.response.folders"); - let wbxmlData = eas.network.getDataFromResponse(response); - eas.network.checkStatus(syncData, wbxmlData,"FolderSync.Status"); - - let synckey = eas.xmltools.getWbxmlDataField(wbxmlData,"FolderSync.SyncKey"); - if (synckey) { - syncData.accountData.setAccountProperty("foldersynckey", synckey); - } else { - throw eas.sync.finish("error", "wbxmlmissingfield::FolderSync.SyncKey"); - } - - // If we reach this point, wbxmlData contains FolderSync node, - // so the next "if" will not fail with an javascript error, no need - // to use save getWbxmlDataField function. - - // Are there any changes in folder hierarchy? - if (wbxmlData.FolderSync.Changes) { - // Looking for additions. - let add = eas.xmltools.nodeAsArray(wbxmlData.FolderSync.Changes.Add); - for (let count = 0; count < add.length; count++) { - // Only add allowed folder types to DB (include trash(4), so we can find trashed folders. - if (!["9","14","8","13","7","15", "4"].includes(add[count].Type)) - continue; - - let existingFolder = syncData.accountData.getFolder("serverID", add[count].ServerId); - if (existingFolder) { - // Server has send us an ADD for a folder we alreay have, treat as update. - existingFolder.setFolderProperty("foldername", add[count].DisplayName); - existingFolder.setFolderProperty("type", add[count].Type); - existingFolder.setFolderProperty("parentID", add[count].ParentId); - } else { - // Create folder obj for new folder settings. - let newFolder = syncData.accountData.createNewFolder(); - switch (add[count].Type) { - case "9": // contact - case "14": - newFolder.setFolderProperty("targetType", "addressbook"); - break; - case "8": // event - case "13": - newFolder.setFolderProperty("targetType", "calendar"); - break; - case "7": // todo - case "15": - newFolder.setFolderProperty("targetType", "calendar"); - break; - default: - newFolder.setFolderProperty("targetType", "unknown type ("+add[count].Type+")"); - break; - - } - - newFolder.setFolderProperty("serverID", add[count].ServerId); - newFolder.setFolderProperty("foldername", add[count].DisplayName); - newFolder.setFolderProperty("type", add[count].Type); - newFolder.setFolderProperty("parentID", add[count].ParentId); - - // Do we have a cached folder? - let cachedFolderData = syncData.accountData.getFolderFromCache("serverID", add[count].ServerId); - if (cachedFolderData) { - // Copy fields from cache which we want to re-use. - newFolder.setFolderProperty("targetColor", cachedFolderData.getFolderProperty("targetColor")); - newFolder.setFolderProperty("targetName", cachedFolderData.getFolderProperty("targetName")); - newFolder.setFolderProperty("downloadonly", cachedFolderData.getFolderProperty("downloadonly")); - } - } - } - - // Looking for updates. - let update = eas.xmltools.nodeAsArray(wbxmlData.FolderSync.Changes.Update); - for (let count = 0; count < update.length; count++) { - let existingFolder = syncData.accountData.getFolder("serverID", update[count].ServerId); - if (existingFolder) { - // Update folder. - existingFolder.setFolderProperty("foldername", update[count].DisplayName); - existingFolder.setFolderProperty("type", update[count].Type); - existingFolder.setFolderProperty("parentID", update[count].ParentId); - } - } - - // Looking for deletes. Do not delete the targets, - // but keep them as stale/unconnected elements. - let del = eas.xmltools.nodeAsArray(wbxmlData.FolderSync.Changes.Delete); - for (let count = 0; count < del.length; count++) { - let existingFolder = syncData.accountData.getFolder("serverID", del[count].ServerId); - if (existingFolder) { - existingFolder.remove("[deleted on server]"); - } - } - } - }, - - - - - - deleteFolder: async function (syncData) { - if (!syncData.currentFolderData) { - return; - } - - if (!syncData.accountData.getAccountProperty("allowedEasCommands").split(",").includes("FolderDelete")) { - throw eas.sync.finish("error", "notsupported::FolderDelete"); - } - - syncData.setSyncState("prepare.request.deletefolder"); - let foldersynckey = syncData.accountData.getAccountProperty("foldersynckey"); - - //request foldersync - let wbxml = eas.wbxmltools.createWBXML(); - wbxml.switchpage("FolderHierarchy"); - wbxml.otag("FolderDelete"); - wbxml.atag("SyncKey", foldersynckey); - wbxml.atag("ServerId", syncData.currentFolderData.getFolderProperty("serverID")); - wbxml.ctag(); - - syncData.setSyncState("send.request.deletefolder"); - let response = await eas.network.sendRequest(wbxml.getBytes(), "FolderDelete", syncData); - - syncData.setSyncState("eval.response.deletefolder"); - let wbxmlData = eas.network.getDataFromResponse(response); - - eas.network.checkStatus(syncData, wbxmlData,"FolderDelete.Status"); - - let synckey = eas.xmltools.getWbxmlDataField(wbxmlData,"FolderDelete.SyncKey"); - if (synckey) { - syncData.accountData.setAccountProperty("foldersynckey", synckey); - syncData.currentFolderData.remove(); - } else { - throw eas.sync.finish("error", "wbxmlmissingfield::FolderDelete.SyncKey"); - } - }, - - - - - - singleFolder: async function (syncData) { - // add target to syncData - try { - // accessing the target for the first time will check if it is avail and if not will create it (if possible) - syncData.target = await syncData.currentFolderData.targetData.getTarget(); - } catch (e) { - Components.utils.reportError(e); - throw eas.sync.finish("warning", e.message); - } - - //get syncData type, which is also used in WBXML for the CLASS element - syncData.type = null; - switch (syncData.currentFolderData.getFolderProperty("type")) { - case "9": //contact - case "14": - syncData.type = "Contacts"; - break; - case "8": //event - case "13": - syncData.type = "Calendar"; - break; - case "7": //todo - case "15": - syncData.type = "Tasks"; - break; - default: - throw eas.sync.finish("info", "skipped"); - break; - } - - syncData.setSyncState("preparing"); - - //get synckey if needed - syncData.synckey = syncData.currentFolderData.getFolderProperty("synckey"); - if (syncData.synckey == "") { - await eas.network.getSynckey(syncData); - } - - //sync folder - syncData.timeOfLastSync = syncData.currentFolderData.getFolderProperty( "lastsynctime") / 1000; - syncData.timeOfThisSync = (Date.now() / 1000) - 1; - - let lightningBatch = false; - let lightningReadOnly = ""; - let error = null; - - // We ned to intercept any throw error, because lightning needs a few operations after sync finished - try { - switch (syncData.type) { - case "Contacts": - await eas.sync.easFolder(syncData); - break; - - case "Calendar": - case "Tasks": - //save current value of readOnly (or take it from the setting) - lightningReadOnly = syncData.target.calendar.getProperty("readOnly") || syncData.currentFolderData.getFolderProperty( "downloadonly"); - syncData.target.calendar.setProperty("readOnly", false); - - lightningBatch = true; - syncData.target.calendar.startBatch(); - - await eas.sync.easFolder(syncData); - break; - } - } catch (report) { - error = report; - } - - if (lightningBatch) { - syncData.target.calendar.endBatch(); - syncData.target.calendar.setProperty("readOnly", lightningReadOnly); - } - - if (error) throw error; - }, - - - - - - - - - - - // --------------------------------------------------------------------------- - // MAIN FUNCTIONS TO SYNC AN EAS FOLDER - // --------------------------------------------------------------------------- - - easFolder: async function (syncData) { - syncData.progressData.reset(); - - if (syncData.currentFolderData.getFolderProperty("downloadonly")) { - await eas.sync.revertLocalChanges(syncData); - } - - await eas.network.getItemEstimate(syncData); - await eas.sync.requestRemoteChanges(syncData); - - if (!syncData.currentFolderData.getFolderProperty("downloadonly")) { - let sendChanges = await eas.sync.sendLocalChanges(syncData); - if (sendChanges) { - // This is ugly as hell, but Microsoft sometimes sets the state of the - // remote account to "changed" after we have send a local change (even - // though it has acked the change) and this will cause the server to - // send a change request with our next sync. Because we follow the - // "server wins" policy, this will overwrite any additional local change - // we have done in the meantime. This is stupid, but we wait 2s and - // hope it is enough to catch this second ack of the local change. - let timer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer); - await new Promise(function(resolve, reject) { - let event = { - notify: function(timer) { - resolve(); - } - } - timer.initWithCallback(event, 2000, Components.interfaces.nsITimer.TYPE_ONE_SHOT); - }); - await eas.sync.requestRemoteChanges(syncData); - } - } - }, - - - requestRemoteChanges: async function (syncData) { - do { - syncData.setSyncState("prepare.request.remotechanges"); - syncData.request = ""; - syncData.response = ""; - - // BUILD WBXML - let wbxml = eas.wbxmltools.createWBXML(); - wbxml.otag("Sync"); - wbxml.otag("Collections"); - wbxml.otag("Collection"); - if (syncData.accountData.getAccountProperty("asversion") == "2.5") wbxml.atag("Class", syncData.type); - wbxml.atag("SyncKey", syncData.synckey); - wbxml.atag("CollectionId", syncData.currentFolderData.getFolderProperty("serverID")); - wbxml.atag("DeletesAsMoves"); - wbxml.atag("GetChanges"); - wbxml.atag("WindowSize", eas.prefs.getIntPref("maxitems").toString()); - - if (syncData.accountData.getAccountProperty("asversion") != "2.5") { - wbxml.otag("Options"); - if (syncData.type == "Calendar") wbxml.atag("FilterType", syncData.currentFolderData.accountData.getAccountProperty("synclimit")); - wbxml.atag("Class", syncData.type); - wbxml.switchpage("AirSyncBase"); - wbxml.otag("BodyPreference"); - wbxml.atag("Type", "1"); - wbxml.ctag(); - wbxml.switchpage("AirSync"); - wbxml.ctag(); - } else if (syncData.type == "Calendar") { //in 2.5 we only send it to filter Calendar - wbxml.otag("Options"); - wbxml.atag("FilterType", syncData.currentFolderData.accountData.getAccountProperty("synclimit")); - wbxml.ctag(); - } - - wbxml.ctag(); - wbxml.ctag(); - wbxml.ctag(); - - //SEND REQUEST - syncData.setSyncState("send.request.remotechanges"); - let response = await eas.network.sendRequest(wbxml.getBytes(), "Sync", syncData); - - //VALIDATE RESPONSE - // get data from wbxml response, some servers send empty response if there are no changes, which is not an error - let wbxmlData = eas.network.getDataFromResponse(response, eas.flags.allowEmptyResponse); - if (wbxmlData === null) return; - - //check status, throw on error - eas.network.checkStatus(syncData, wbxmlData,"Sync.Collections.Collection.Status"); - - //PROCESS COMMANDS - await eas.sync.processCommands(wbxmlData, syncData); - - //Update count in UI - syncData.setSyncState("eval.response.remotechanges"); - - //update synckey - eas.network.updateSynckey(syncData, wbxmlData); - - if (!eas.xmltools.hasWbxmlDataField(wbxmlData,"Sync.Collections.Collection.MoreAvailable")) { - //Feedback from users: They want to see the final count - await TbSync.tools.sleep(100); - return; - } - } while (true); - - }, - - - sendLocalChanges: async function (syncData) { - let maxnumbertosend = eas.prefs.getIntPref("maxitems"); - syncData.progressData.reset(0, syncData.target.getItemsFromChangeLog().length); - - //keep track of failed items - syncData.failedItems = []; - - let done = false; - let numberOfItemsToSend = maxnumbertosend; - let sendChanges = false; - do { - syncData.setSyncState("prepare.request.localchanges"); - syncData.request = ""; - syncData.response = ""; - - //get changed items from ChangeLog - let changes = syncData.target.getItemsFromChangeLog(numberOfItemsToSend); - //console.log("chnages", changes); - let c=0; - let e=0; - - //keep track of send items during this request - let changedItems = []; - let addedItems = {}; - let sendItems = []; - - // BUILD WBXML - let wbxml = eas.wbxmltools.createWBXML(); - wbxml.otag("Sync"); - wbxml.otag("Collections"); - wbxml.otag("Collection"); - if (syncData.accountData.getAccountProperty("asversion") == "2.5") wbxml.atag("Class", syncData.type); - wbxml.atag("SyncKey", syncData.synckey); - wbxml.atag("CollectionId", syncData.currentFolderData.getFolderProperty("serverID")); - wbxml.otag("Commands"); - - for (let i=0; i 0) { //if there was at least one actual local change, send request - sendChanges = true; - //SEND REQUEST & VALIDATE RESPONSE - syncData.setSyncState("send.request.localchanges"); - let response = await eas.network.sendRequest(wbxml.getBytes(), "Sync", syncData); - - syncData.setSyncState("eval.response.localchanges"); - - //get data from wbxml response - let wbxmlData = eas.network.getDataFromResponse(response); - - //check status and manually handle error states which support softfails - let errorcause = eas.network.checkStatus(syncData, wbxmlData, "Sync.Collections.Collection.Status", "", true); - switch (errorcause) { - case "": - break; - - case "Sync.4": //Malformed request - case "Sync.6": //Invalid item - //some servers send a global error - to catch this, we reduce the number of items we send to the server - if (sendItems.length == 1) { - //the request contained only one item, so we know which one failed - if (sendItems[0].type == "deleted_by_user") { - //we failed to delete an item, discard and place message in log - syncData.target.removeItemFromChangeLog(sendItems[0].id); - TbSync.eventlog.add("warning", syncData.eventLogInfo, "ErrorOnDelete::"+sendItems[0].id); - } else { - let foundItem = await syncData.target.getItem(sendItems[0].id); - if (foundItem) { - eas.sync.updateFailedItems(syncData, errorcause, foundItem.primaryKey, foundItem.toString()); - } else { - //should not happen - syncData.target.removeItemFromChangeLog(sendItems[0].id); - } - } - syncData.progressData.inc(); - //restore numberOfItemsToSend - numberOfItemsToSend = maxnumbertosend; - } else if (sendItems.length > 1) { - //reduce further - numberOfItemsToSend = Math.min(1, Math.round(sendItems.length / 5)); - } else { - //sendItems.length == 0 ??? recheck but this time let it handle all cases - eas.network.checkStatus(syncData, wbxmlData, "Sync.Collections.Collection.Status"); - } - break; - - default: - //recheck but this time let it handle all cases - eas.network.checkStatus(syncData, wbxmlData, "Sync.Collections.Collection.Status"); - } - - await TbSync.tools.sleep(10, true); - - if (errorcause == "") { - //PROCESS RESPONSE - await eas.sync.processResponses(wbxmlData, syncData, addedItems, changedItems); - - //PROCESS COMMANDS - await eas.sync.processCommands(wbxmlData, syncData); - - //remove all items from changelog that did not fail - for (let a=0; a < changedItems.length; a++) { - syncData.target.removeItemFromChangeLog(changedItems[a]); - syncData.progressData.inc(); - } - - //update synckey - eas.network.updateSynckey(syncData, wbxmlData); - } - - } else if (e==0) { //if there was no local change and also no error (which will not happen twice) finish - - done = true; - - } - - } while (!done); - - //was there an error? - if (syncData.failedItems.length > 0) { - throw eas.sync.finish("warning", "ServerRejectedSomeItems::" + syncData.failedItems.length); - } - return sendChanges; - }, - - - - - revertLocalChanges: async function (syncData) { - let maxnumbertosend = eas.prefs.getIntPref("maxitems"); - syncData.progressData.reset(0, syncData.target.getItemsFromChangeLog().length); - if (syncData.progressData.todo == 0) { - return; - } - - let viaItemOperations = (syncData.accountData.getAccountProperty("allowedEasCommands").split(",").includes("ItemOperations")); - - //get changed items from ChangeLog - do { - syncData.setSyncState("prepare.request.revertlocalchanges"); - let changes = syncData.target.getItemsFromChangeLog(maxnumbertosend); - let c=0; - syncData.request = ""; - syncData.response = ""; - - // BUILD WBXML - let wbxml = eas.wbxmltools.createWBXML(); - if (viaItemOperations) { - wbxml.switchpage("ItemOperations"); - wbxml.otag("ItemOperations"); - } else { - wbxml.otag("Sync"); - wbxml.otag("Collections"); - wbxml.otag("Collection"); - if (syncData.accountData.getAccountProperty("asversion") == "2.5") wbxml.atag("Class", syncData.type); - wbxml.atag("SyncKey", syncData.synckey); - wbxml.atag("CollectionId", syncData.currentFolderData.getFolderProperty("serverID")); - wbxml.otag("Commands"); - } - - for (let i=0; i 0) { //if there was at least one actual local change, send request - let error = false; - let wbxmlData = ""; - - //SEND REQUEST & VALIDATE RESPONSE - try { - syncData.setSyncState("send.request.revertlocalchanges"); - let response = await eas.network.sendRequest(wbxml.getBytes(), (viaItemOperations) ? "ItemOperations" : "Sync", syncData); - - syncData.setSyncState("eval.response.revertlocalchanges"); - - //get data from wbxml response - wbxmlData = eas.network.getDataFromResponse(response); - } catch (e) { - //we do not handle errors, IF there was an error, wbxmlData is empty and will trigger the fallback - } - - let fetchPath = (viaItemOperations) ? "ItemOperations.Response.Fetch" : "Sync.Collections.Collection.Responses.Fetch"; - if (eas.xmltools.hasWbxmlDataField(wbxmlData, fetchPath)) { - - //looking for additions - let add = eas.xmltools.nodeAsArray(eas.xmltools.getWbxmlDataField(wbxmlData, fetchPath)); - for (let count = 0; count < add.length; count++) { - await TbSync.tools.sleep(10, true); - - let ServerId = add[count].ServerId; - let data = (viaItemOperations) ? add[count].Properties : add[count].ApplicationData; - - if (data && ServerId) { - let foundItem = await syncData.target.getItem(ServerId); - if (!foundItem) { //do NOT add, if an item with that ServerId was found - let newItem = eas.sync.createItem(syncData); - try { - eas.sync[syncData.type].setThunderbirdItemFromWbxml(newItem, data, ServerId, syncData); - await syncData.target.addItem(newItem); - } catch (e) { - eas.xmltools.printXmlData(add[count], true); //include application data in log - TbSync.eventlog.add("warning", syncData.eventLogInfo, "BadItemSkipped::JavaScriptError", newItem.toString()); - throw e; // unable to add item to Thunderbird - fatal error - } - } else { - //should not happen, since we deleted that item beforehand - syncData.target.removeItemFromChangeLog(ServerId); - } - syncData.progressData.inc(); - } else { - error = true; - break; - } - } - } else { - error = true; - } - - if (error) { - //if ItemOperations.Fetch fails, fall back to Sync.Fetch, if that fails, fall back to resync - if (viaItemOperations) { - viaItemOperations = false; - TbSync.eventlog.add("info", syncData.eventLogInfo, "Server returned error during ItemOperations.Fetch, falling back to Sync.Fetch."); - } else { - await eas.sync.revertLocalChangesViaResync(syncData); - return; - } - } - - } else { //if there was no more local change we need to revert, return - - return; - - } - - } while (true); - - }, - - revertLocalChangesViaResync: async function (syncData) { - TbSync.eventlog.add("info", syncData.eventLogInfo, "Server does not support ItemOperations.Fetch and/or Sync.Fetch, must revert via resync."); - let changes = syncData.target.getItemsFromChangeLog(); - - syncData.progressData.reset(0, changes.length); - syncData.setSyncState("prepare.request.revertlocalchanges"); - - //remove all changes, so we can get them fresh from the server - for (let i=0; i-1) changedItems.splice(p,1); - } - - } - } - - //looking for deletions - let del = eas.xmltools.nodeAsArray(wbxmlData.Sync.Collections.Collection.Responses.Delete); - for (let count = 0; count < del.length; count++) { - //What can we do about failed deletes? SyncLog - eas.network.checkStatus(syncData, del[count],"Status","Sync.Collections.Collection.Responses.Delete["+count+"].Status", true); - } - - } - }, - - - - - - - - - - - // --------------------------------------------------------------------------- - // HELPER FUNCTIONS AND DEFINITIONS - // --------------------------------------------------------------------------- - - MAP_EAS2TB : { - //EAS Importance: 0 = LOW | 1 = NORMAL | 2 = HIGH - Importance : { "0":"9", "1":"5", "2":"1"}, //to PRIORITY - //EAS Sensitivity : 0 = Normal | 1 = Personal | 2 = Private | 3 = Confidential - Sensitivity : { "0":"PUBLIC", "1":"PRIVATE", "2":"PRIVATE", "3":"CONFIDENTIAL"}, //to CLASS - //EAS BusyStatus: 0 = Free | 1 = Tentative | 2 = Busy | 3 = Work | 4 = Elsewhere - BusyStatus : {"0":"TRANSPARENT", "1":"unset", "2":"OPAQUE", "3":"OPAQUE", "4":"OPAQUE"}, //to TRANSP - //EAS AttendeeStatus: 0 =Response unknown (but needed) | 2 = Tentative | 3 = Accept | 4 = Decline | 5 = Not responded (and not needed) || 1 = Organizer in ResponseType - ATTENDEESTATUS : {"0": "NEEDS-ACTION", "1":"Orga", "2":"TENTATIVE", "3":"ACCEPTED", "4":"DECLINED", "5":"ACCEPTED"}, - }, - - MAP_TB2EAS : { - //TB PRIORITY: 9 = LOW | 5 = NORMAL | 1 = HIGH - PRIORITY : { "9":"0", "5":"1", "1":"2","unset":"1"}, //to Importance - //TB CLASS: PUBLIC, PRIVATE, CONFIDENTIAL) - CLASS : { "PUBLIC":"0", "PRIVATE":"2", "CONFIDENTIAL":"3", "unset":"0"}, //to Sensitivity - //TB TRANSP : free = TRANSPARENT, busy = OPAQUE) - TRANSP : {"TRANSPARENT":"0", "unset":"1", "OPAQUE":"2"}, // to BusyStatus - //TB STATUS: NEEDS-ACTION, ACCEPTED, DECLINED, TENTATIVE, (DELEGATED, COMPLETED, IN-PROCESS - for todo) - ATTENDEESTATUS : {"NEEDS-ACTION":"0", "ACCEPTED":"3", "DECLINED":"4", "TENTATIVE":"2", "DELEGATED":"5","COMPLETED":"5", "IN-PROCESS":"5"}, - }, - - mapEasPropertyToThunderbird : function (easProp, tbProp, data, item) { - if (data[easProp]) { - //store original EAS value - let easPropValue = eas.xmltools.checkString(data[easProp]); - item.setProperty("X-EAS-" + easProp, easPropValue); - //map EAS value to TB value (use setCalItemProperty if there is one option which can unset/delete the property) - eas.tools.setCalItemProperty(item, tbProp, eas.sync.MAP_EAS2TB[easProp][easPropValue]); - } - }, - - mapThunderbirdPropertyToEas: function (tbProp, easProp, item) { - if (item.hasProperty("X-EAS-" + easProp) && eas.tools.getCalItemProperty(item, tbProp) == eas.sync.MAP_EAS2TB[easProp][item.getProperty("X-EAS-" + easProp)]) { - //we can use our stored EAS value, because it still maps to the current TB value - return item.getProperty("X-EAS-" + easProp); - } else { - return eas.sync.MAP_TB2EAS[tbProp][eas.tools.getCalItemProperty(item, tbProp)]; - } - }, - - getEasItemType(aItem) { - if (aItem instanceof TbSync.addressbook.AbItem) { - return "Contacts"; - } else if (aItem instanceof TbSync.lightning.TbItem) { - return aItem.isTodo ? "Tasks" : "Calendar"; - } else { - throw "Unknown aItem."; - } - }, - - createItem(syncData) { - switch (syncData.type) { - case "Contacts": - return syncData.target.createNewCard(); - break; - - case "Tasks": - return syncData.target.createNewTodo(); - break; - - case "Calendar": - return syncData.target.createNewEvent(); - break; - - default: - throw "Unknown item type <" + syncData.type + ">"; - } - }, - - async getWbxmlFromThunderbirdItem(item, syncData, isException = false) { - try { - let wbxml = await eas.sync[syncData.type].getWbxmlFromThunderbirdItem(item, syncData, isException); - return wbxml; - } catch (e) { - TbSync.eventlog.add("warning", syncData.eventLogInfo, "BadItemSkipped::JavaScriptError", item.toString()); - throw e; // unable to read item from Thunderbird - fatal error - } - }, - - - - - - - - // --------------------------------------------------------------------------- - // LIGHTNING HELPER FUNCTIONS AND DEFINITIONS - // These functions are needed only by tasks and events, so they - // are placed here, even though they are not type independent, - // but I did not want to add another "lightning" sub layer. - // - // The item in these functions is a native lightning item. - // --------------------------------------------------------------------------- - - setItemSubject: function (item, syncData, data) { - if (data.Subject) item.title = eas.xmltools.checkString(data.Subject); - }, - - setItemLocation: function (item, syncData, data) { - if (data.Location) item.setProperty("location", eas.xmltools.checkString(data.Location)); - }, - - - setItemCategories: function (item, syncData, data) { - if (data.Categories && data.Categories.Category) { - let cats = []; - if (Array.isArray(data.Categories.Category)) cats = data.Categories.Category; - else cats.push(data.Categories.Category); - item.setCategories(cats); - } - }, - - getItemCategories: function (item, syncData) { - let asversion = syncData.accountData.getAccountProperty("asversion"); - let wbxml = eas.wbxmltools.createWBXML("", syncData.type); //init wbxml with "" and not with precodes, also activate type codePage (Calendar, Tasks, Contacts etc) - - //to properly "blank" categories, we need to always include the container - let categories = item.getCategories({}); - if (categories.length > 0) { - wbxml.otag("Categories"); - for (let i=0; i 0 && */ data.Body.Data) item.setProperty("description", eas.xmltools.checkString(data.Body.Data)); //EstimatedDataSize is optional - } - }, - - getItemBody: function (item, syncData) { - let asversion = syncData.accountData.getAccountProperty("asversion"); - let wbxml = eas.wbxmltools.createWBXML("", syncData.type); //init wbxml with "" and not with precodes, also activate type codePage (Calendar, Tasks, Contacts etc) - - let description = (item.hasProperty("description")) ? item.getProperty("description") : ""; - if (asversion == "2.5") { - wbxml.atag("Body", description); - } else { - wbxml.switchpage("AirSyncBase"); - wbxml.otag("Body"); - wbxml.atag("Type", "1"); - wbxml.atag("EstimatedDataSize", "" + description.length); - wbxml.atag("Data", description); - wbxml.ctag(); - //does not work with horde at the moment, does not work with task, does not work with exceptions - //if (syncData.accountData.getAccountProperty("horde") == "0") wbxml.atag("NativeBodyType", "1"); - - //return to code page of this type - wbxml.switchpage(syncData.type); - } - return wbxml.getBytes(); - }, - - //item is a native lightning item - setItemRecurrence: function (item, syncData, data, timezone) { - if (data.Recurrence) { - item.recurrenceInfo = new CalRecurrenceInfo(); - item.recurrenceInfo.item = item; - let recRule = TbSync.lightning.cal.createRecurrenceRule(); - switch (data.Recurrence.Type) { - case "0": - recRule.type = "DAILY"; - break; - case "1": - recRule.type = "WEEKLY"; - break; - case "2": - case "3": - recRule.type = "MONTHLY"; - break; - case "5": - case "6": - recRule.type = "YEARLY"; - break; - } - - if (data.Recurrence.CalendarType) { - // TODO - } - if (data.Recurrence.DayOfMonth) { - recRule.setComponent("BYMONTHDAY", [data.Recurrence.DayOfMonth]); - } - if (data.Recurrence.DayOfWeek) { - let DOW = data.Recurrence.DayOfWeek; - if (DOW == 127 && (recRule.type == "MONTHLY" || recRule.type == "YEARLY")) { - recRule.setComponent("BYMONTHDAY", [-1]); - } - else { - let days = []; - for (let i = 0; i < 7; ++i) { - if (DOW & 1 << i) days.push(i + 1); - } - if (data.Recurrence.WeekOfMonth) { - for (let i = 0; i < days.length; ++i) { - if (data.Recurrence.WeekOfMonth == 5) { - days[i] = -1 * (days[i] + 8); - } - else { - days[i] += 8 * (data.Recurrence.WeekOfMonth - 0); - } - } - } - recRule.setComponent("BYDAY", days); - } - } - if (data.Recurrence.FirstDayOfWeek) { - //recRule.setComponent("WKST", [data.Recurrence.FirstDayOfWeek]); // WKST is not a valid component - //recRule.weekStart = data.Recurrence.FirstDayOfWeek; // - (NS_ERROR_NOT_IMPLEMENTED) [calIRecurrenceRule.weekStart] - TbSync.eventlog.add("info", syncData.eventLogInfo, "FirstDayOfWeek tag ignored (not supported).", item.icalString); - } - - if (data.Recurrence.Interval) { - recRule.interval = data.Recurrence.Interval; - } - if (data.Recurrence.IsLeapMonth) { - // TODO - } - if (data.Recurrence.MonthOfYear) { - recRule.setComponent("BYMONTH", [data.Recurrence.MonthOfYear]); - } - if (data.Recurrence.Occurrences) { - recRule.count = data.Recurrence.Occurrences; - } - if (data.Recurrence.Until) { - //time string could be in compact/basic or extended form of ISO 8601, - //cal.createDateTime only supports compact/basic, our own method takes both styles - recRule.untilDate = eas.tools.createDateTime(data.Recurrence.Until); - } - if (data.Recurrence.Start) { - TbSync.eventlog.add("info", syncData.eventLogInfo, "Start tag in recurring task is ignored, recurrence will start with first entry.", item.icalString); - } - - item.recurrenceInfo.insertRecurrenceItemAt(recRule, 0); - - if (data.Exceptions && syncData.type == "Calendar") { // only events, tasks cannot have exceptions - // Exception could be an object or an array of objects - let exceptions = [].concat(data.Exceptions.Exception); - for (let exception of exceptions) { - //exception.ExceptionStartTime is in UTC, but the Recurrence Object is in local timezone - let dateTime = TbSync.lightning.cal.createDateTime(exception.ExceptionStartTime).getInTimezone(timezone); - if (data.AllDayEvent == "1") { - dateTime.isDate = true; - // Pass to replacement event unless overriden - if (!exception.AllDayEvent) { - exception.AllDayEvent = "1"; - } - } - if (exception.Deleted == "1") { - item.recurrenceInfo.removeOccurrenceAt(dateTime); - } - else { - let replacement = item.recurrenceInfo.getOccurrenceFor(dateTime); - // replacement is a native lightning item, so we can access its id via .id - eas.sync[syncData.type].setThunderbirdItemFromWbxml(replacement, exception, replacement.id, syncData, "recurrence"); - // Reminders should carry over from parent, but setThunderbirdItemFromWbxml clears all alarms - if (!exception.Reminder && item.getAlarms({}).length) { - replacement.addAlarm(item.getAlarms({})[0]); - } - // Removing a reminder requires EAS 16.0 - item.recurrenceInfo.modifyException(replacement, true); - } - } - } - } - }, - - getItemRecurrence: async function (item, syncData, localStartDate = null) { - let asversion = syncData.accountData.getAccountProperty("asversion"); - let wbxml = eas.wbxmltools.createWBXML("", syncData.type); //init wbxml with "" and not with precodes, also activate type codePage (Calendar, Tasks etc) - - if (item.recurrenceInfo && (syncData.type == "Calendar" || syncData.type == "Tasks")) { - let deleted = []; - let hasRecurrence = false; - let startDate = (syncData.type == "Calendar") ? item.startDate : item.entryDate; - - for (let recRule of item.recurrenceInfo.getRecurrenceItems({})) { - if (recRule.date) { - if (recRule.isNegative) { - // EXDATE - deleted.push(recRule); - } - else { - // RDATE - TbSync.eventlog.add("info", syncData.eventLogInfo, "Ignoring RDATE rule (not supported)", recRule.icalString); - } - continue; - } - if (recRule.isNegative) { - // EXRULE - TbSync.eventlog.add("info", syncData.eventLogInfo, "Ignoring EXRULE rule (not supported)", recRule.icalString); - continue; - } - - // RRULE - wbxml.otag("Recurrence"); - hasRecurrence = true; - - let type = 0; - let monthDays = recRule.getComponent("BYMONTHDAY", {}); - let weekDays = recRule.getComponent("BYDAY", {}); - let months = recRule.getComponent("BYMONTH", {}); - let weeks = []; - - // Unpack 1MO style days - for (let i = 0; i < weekDays.length; ++i) { - if (weekDays[i] > 8) { - weeks[i] = Math.floor(weekDays[i] / 8); - weekDays[i] = weekDays[i] % 8; - } - else if (weekDays[i] < -8) { - // EAS only supports last week as a special value, treat - // all as last week or assume every month has 5 weeks? - // Change to last week - //weeks[i] = 5; - // Assumes 5 weeks per month for week <= -2 - weeks[i] = 6 - Math.floor(-weekDays[i] / 8); - weekDays[i] = -weekDays[i] % 8; - } - } - if (monthDays[0] && monthDays[0] == -1) { - weeks = [5]; - weekDays = [1, 2, 3, 4, 5, 6, 7]; // 127 - monthDays[0] = null; - } - // Type - if (recRule.type == "WEEKLY") { - type = 1; - if (!weekDays.length) { - weekDays = [startDate.weekday + 1]; - } - } - else if (recRule.type == "MONTHLY" && weeks.length) { - type = 3; - } - else if (recRule.type == "MONTHLY") { - type = 2; - if (!monthDays.length) { - monthDays = [startDate.day]; - } - } - else if (recRule.type == "YEARLY" && weeks.length) { - type = 6; - } - else if (recRule.type == "YEARLY") { - type = 5; - if (!monthDays.length) { - monthDays = [startDate.day]; - } - if (!months.length) { - months = [startDate.month + 1]; - } - } - wbxml.atag("Type", type.toString()); - - //Tasks need a Start tag, but we cannot allow a start date different from the start of the main item (thunderbird does not support that) - if (localStartDate) wbxml.atag("Start", localStartDate); - - // TODO: CalendarType: 14.0 and up - // DayOfMonth - if (monthDays[0]) { - // TODO: Multiple days of month - multiple Recurrence tags? - wbxml.atag("DayOfMonth", monthDays[0].toString()); - } - // DayOfWeek - if (weekDays.length) { - let bitfield = 0; - for (let day of weekDays) { - bitfield |= 1 << (day - 1); - } - wbxml.atag("DayOfWeek", bitfield.toString()); - } - // FirstDayOfWeek: 14.1 and up - //wbxml.atag("FirstDayOfWeek", recRule.weekStart); - (NS_ERROR_NOT_IMPLEMENTED) [calIRecurrenceRule.weekStart] - // Interval - wbxml.atag("Interval", recRule.interval.toString()); - // TODO: IsLeapMonth: 14.0 and up - // MonthOfYear - if (months.length) { - wbxml.atag("MonthOfYear", months[0].toString()); - } - // Occurrences - if (recRule.isByCount) { - wbxml.atag("Occurrences", recRule.count.toString()); - } - // Until - else if (recRule.untilDate != null) { - //Events need the Until data in compact form, Tasks in the basic form - wbxml.atag("Until", eas.tools.getIsoUtcString(recRule.untilDate, (syncData.type == "Tasks"))); - } - // WeekOfMonth - if (weeks.length) { - wbxml.atag("WeekOfMonth", weeks[0].toString()); - } - wbxml.ctag(); - } - - if (syncData.type == "Calendar" && hasRecurrence) { //Exceptions only allowed in Calendar and only if a valid Recurrence was added - let modifiedIds = item.recurrenceInfo.getExceptionIds({}); - if (deleted.length || modifiedIds.length) { - wbxml.otag("Exceptions"); - for (let exception of deleted) { - wbxml.otag("Exception"); - wbxml.atag("ExceptionStartTime", eas.tools.getIsoUtcString(exception.date)); - wbxml.atag("Deleted", "1"); - //Docs say it is allowed, but if present, it does not work - //if (asversion == "2.5") { - // wbxml.atag("UID", item.id); //item.id is not valid, use UID or primaryKey - //} - wbxml.ctag(); - } - for (let exceptionId of modifiedIds) { - let replacement = item.recurrenceInfo.getExceptionFor(exceptionId); - wbxml.otag("Exception"); - wbxml.atag("ExceptionStartTime", eas.tools.getIsoUtcString(exceptionId)); - wbxml.append(await eas.sync.getWbxmlFromThunderbirdItem(replacement, syncData, true)); - wbxml.ctag(); - } - wbxml.ctag(); - } - } - } - - return wbxml.getBytes(); - } - -} +/* + * This file is part of EAS-4-TbSync. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +var { ExtensionParent } = ChromeUtils.importESModule( + "resource://gre/modules/ExtensionParent.sys.mjs" +); + +var tbsyncExtension = ExtensionParent.GlobalManager.getExtension( + "tbsync@jobisoft.de" +); +var { TbSync } = ChromeUtils.importESModule( + `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}` +); + +ChromeUtils.defineESModuleGetters(this, { + CalRecurrenceInfo: "resource:///modules/CalRecurrenceInfo.sys.mjs", +}); + +// - https://dxr.mozilla.org/comm-central/source/calendar/base/public/calIEvent.idl +// - https://dxr.mozilla.org/comm-central/source/calendar/base/public/calIItemBase.idl +// - https://dxr.mozilla.org/comm-central/source/calendar/base/public/calICalendar.idl +// - https://dxr.mozilla.org/comm-central/source/calendar/base/modules/calAsyncUtils.sys.mjs + +// https://msdn.microsoft.com/en-us/library/dd299454(v=exchg.80).aspx + +var sync = { + finish: function (aStatus = "", msg = "", details = "") { + let status = TbSync.StatusData.SUCCESS + switch (aStatus) { + + case "": + case "ok": + status = TbSync.StatusData.SUCCESS; + break; + + case "info": + status = TbSync.StatusData.INFO; + break; + + case "resyncAccount": + status = TbSync.StatusData.ACCOUNT_RERUN; + break; + + case "resyncFolder": + status = TbSync.StatusData.FOLDER_RERUN; + break; + + case "warning": + status = TbSync.StatusData.WARNING; + break; + + case "error": + status = TbSync.StatusData.ERROR; + break; + + default: + console.log("TbSync/EAS: Unknown status <" + aStatus + ">"); + status = TbSync.StatusData.ERROR; + break; + } + + let e = new Error(); + e.name = "eas4tbsync"; + e.message = status.toUpperCase() + ": " + msg.toString() + " (" + details.toString() + ")"; + e.statusData = new TbSync.StatusData(status, msg.toString(), details.toString()); + return e; + }, + + + resetFolderSyncInfo: function (folderData) { + folderData.resetFolderProperty("synckey"); + folderData.resetFolderProperty("lastsynctime"); + }, + + + // update folders avail on server and handle added, removed and renamed + // folders + folderList: async function (syncData) { + //should we recheck options/commands? Always check, if we have no info about asversion! + if (syncData.accountData.getAccountProperty("asversion", "") == "" || (Date.now() - syncData.accountData.getAccountProperty("lastEasOptionsUpdate")) > 86400000) { + await eas.network.getServerOptions(syncData); + } + + //only update the actual used asversion, if we are currently not connected or it has not yet been set + if (syncData.accountData.getAccountProperty("asversion", "") == "" || !syncData.accountData.isConnected()) { + //eval the currently in the UI selected EAS version + let asversionselected = syncData.accountData.getAccountProperty("asversionselected"); + let allowedVersionsString = syncData.accountData.getAccountProperty("allowedEasVersions").trim(); + let allowedVersionsArray = allowedVersionsString.split(","); + + if (asversionselected == "auto") { + if (allowedVersionsArray.includes("14.0")) syncData.accountData.setAccountProperty("asversion", "14.0"); + else if (allowedVersionsArray.includes("2.5")) syncData.accountData.setAccountProperty("asversion", "2.5"); + else if (allowedVersionsString == "") { + throw eas.sync.finish("error", "InvalidServerOptions"); + } else { + throw eas.sync.finish("error", "nosupportedeasversion::" + allowedVersionsArray.join(", ")); + } + } else if (allowedVersionsString != "" && !allowedVersionsArray.includes(asversionselected)) { + throw eas.sync.finish("error", "notsupportedeasversion::" + asversionselected + "::" + allowedVersionsArray.join(", ")); + } else { + //just use the value set by the user + syncData.accountData.setAccountProperty("asversion", asversionselected); + } + } + + //do we need to get a new policy key? + if (syncData.accountData.getAccountProperty("provision") && syncData.accountData.getAccountProperty("policykey") == "0") { + await eas.network.getPolicykey(syncData); + } + + //set device info + await eas.network.setDeviceInformation(syncData); + + syncData.setSyncState("prepare.request.folders"); + let foldersynckey = syncData.accountData.getAccountProperty("foldersynckey"); + + //build WBXML to request foldersync + let wbxml = eas.wbxmltools.createWBXML(); + wbxml.switchpage("FolderHierarchy"); + wbxml.otag("FolderSync"); + wbxml.atag("SyncKey", foldersynckey); + wbxml.ctag(); + + syncData.setSyncState("send.request.folders"); + let response = await eas.network.sendRequest(wbxml.getBytes(), "FolderSync", syncData); + + syncData.setSyncState("eval.response.folders"); + let wbxmlData = eas.network.getDataFromResponse(response); + eas.network.checkStatus(syncData, wbxmlData, "FolderSync.Status"); + + let synckey = eas.xmltools.getWbxmlDataField(wbxmlData, "FolderSync.SyncKey"); + if (synckey) { + syncData.accountData.setAccountProperty("foldersynckey", synckey); + } else { + throw eas.sync.finish("error", "wbxmlmissingfield::FolderSync.SyncKey"); + } + + // If we reach this point, wbxmlData contains FolderSync node, + // so the next "if" will not fail with an javascript error, no need + // to use save getWbxmlDataField function. + + // Are there any changes in folder hierarchy? + if (wbxmlData.FolderSync.Changes) { + // Looking for additions. + let add = eas.xmltools.nodeAsArray(wbxmlData.FolderSync.Changes.Add); + for (let count = 0; count < add.length; count++) { + // Only add allowed folder types to DB (include trash(4), so we can find trashed folders. + if (!["9", "14", "8", "13", "7", "15", "4"].includes(add[count].Type)) + continue; + + let existingFolder = syncData.accountData.getFolder("serverID", add[count].ServerId); + if (existingFolder) { + // Server has send us an ADD for a folder we alreay have, treat as update. + existingFolder.setFolderProperty("foldername", add[count].DisplayName); + existingFolder.setFolderProperty("type", add[count].Type); + existingFolder.setFolderProperty("parentID", add[count].ParentId); + } else { + // Create folder obj for new folder settings. + let newFolder = syncData.accountData.createNewFolder(); + switch (add[count].Type) { + case "9": // contact + case "14": + newFolder.setFolderProperty("targetType", "addressbook"); + break; + case "8": // event + case "13": + newFolder.setFolderProperty("targetType", "calendar"); + break; + case "7": // todo + case "15": + newFolder.setFolderProperty("targetType", "calendar"); + break; + default: + newFolder.setFolderProperty("targetType", "unknown type (" + add[count].Type + ")"); + break; + + } + + newFolder.setFolderProperty("serverID", add[count].ServerId); + newFolder.setFolderProperty("foldername", add[count].DisplayName); + newFolder.setFolderProperty("type", add[count].Type); + newFolder.setFolderProperty("parentID", add[count].ParentId); + + // Do we have a cached folder? + let cachedFolderData = syncData.accountData.getFolderFromCache("serverID", add[count].ServerId); + if (cachedFolderData) { + // Copy fields from cache which we want to re-use. + newFolder.setFolderProperty("targetColor", cachedFolderData.getFolderProperty("targetColor")); + newFolder.setFolderProperty("targetName", cachedFolderData.getFolderProperty("targetName")); + newFolder.setFolderProperty("downloadonly", cachedFolderData.getFolderProperty("downloadonly")); + } + } + } + + // Looking for updates. + let update = eas.xmltools.nodeAsArray(wbxmlData.FolderSync.Changes.Update); + for (let count = 0; count < update.length; count++) { + let existingFolder = syncData.accountData.getFolder("serverID", update[count].ServerId); + if (existingFolder) { + // Update folder. + existingFolder.setFolderProperty("foldername", update[count].DisplayName); + existingFolder.setFolderProperty("type", update[count].Type); + existingFolder.setFolderProperty("parentID", update[count].ParentId); + } + } + + // Looking for deletes. Do not delete the targets, + // but keep them as stale/unconnected elements. + let del = eas.xmltools.nodeAsArray(wbxmlData.FolderSync.Changes.Delete); + for (let count = 0; count < del.length; count++) { + let existingFolder = syncData.accountData.getFolder("serverID", del[count].ServerId); + if (existingFolder) { + existingFolder.remove("[deleted on server]"); + } + } + } + }, + + + + + + deleteFolder: async function (syncData) { + if (!syncData.currentFolderData) { + return; + } + + if (!syncData.accountData.getAccountProperty("allowedEasCommands").split(",").includes("FolderDelete")) { + throw eas.sync.finish("error", "notsupported::FolderDelete"); + } + + syncData.setSyncState("prepare.request.deletefolder"); + let foldersynckey = syncData.accountData.getAccountProperty("foldersynckey"); + + //request foldersync + let wbxml = eas.wbxmltools.createWBXML(); + wbxml.switchpage("FolderHierarchy"); + wbxml.otag("FolderDelete"); + wbxml.atag("SyncKey", foldersynckey); + wbxml.atag("ServerId", syncData.currentFolderData.getFolderProperty("serverID")); + wbxml.ctag(); + + syncData.setSyncState("send.request.deletefolder"); + let response = await eas.network.sendRequest(wbxml.getBytes(), "FolderDelete", syncData); + + syncData.setSyncState("eval.response.deletefolder"); + let wbxmlData = eas.network.getDataFromResponse(response); + + eas.network.checkStatus(syncData, wbxmlData, "FolderDelete.Status"); + + let synckey = eas.xmltools.getWbxmlDataField(wbxmlData, "FolderDelete.SyncKey"); + if (synckey) { + syncData.accountData.setAccountProperty("foldersynckey", synckey); + syncData.currentFolderData.remove(); + } else { + throw eas.sync.finish("error", "wbxmlmissingfield::FolderDelete.SyncKey"); + } + }, + + + + + + singleFolder: async function (syncData) { + // add target to syncData + try { + // accessing the target for the first time will check if it is avail and if not will create it (if possible) + syncData.target = await syncData.currentFolderData.targetData.getTarget(); + } catch (e) { + Components.utils.reportError(e); + throw eas.sync.finish("warning", e.message); + } + + //get syncData type, which is also used in WBXML for the CLASS element + syncData.type = null; + switch (syncData.currentFolderData.getFolderProperty("type")) { + case "9": //contact + case "14": + syncData.type = "Contacts"; + break; + case "8": //event + case "13": + syncData.type = "Calendar"; + break; + case "7": //todo + case "15": + syncData.type = "Tasks"; + break; + default: + throw eas.sync.finish("info", "skipped"); + break; + } + + syncData.setSyncState("preparing"); + + //get synckey if needed + syncData.synckey = syncData.currentFolderData.getFolderProperty("synckey"); + if (syncData.synckey == "") { + await eas.network.getSynckey(syncData); + } + + //sync folder + syncData.timeOfLastSync = syncData.currentFolderData.getFolderProperty("lastsynctime") / 1000; + syncData.timeOfThisSync = (Date.now() / 1000) - 1; + + let lightningBatch = false; + let lightningReadOnly = ""; + let error = null; + + // We ned to intercept any throw error, because lightning needs a few operations after sync finished + try { + switch (syncData.type) { + case "Contacts": + await eas.sync.easFolder(syncData); + break; + + case "Calendar": + case "Tasks": + //save current value of readOnly (or take it from the setting) + lightningReadOnly = syncData.target.calendar.getProperty("readOnly") || syncData.currentFolderData.getFolderProperty("downloadonly"); + syncData.target.calendar.setProperty("readOnly", false); + + lightningBatch = true; + syncData.target.calendar.startBatch(); + + await eas.sync.easFolder(syncData); + break; + } + } catch (report) { + error = report; + } + + if (lightningBatch) { + syncData.target.calendar.endBatch(); + syncData.target.calendar.setProperty("readOnly", lightningReadOnly); + } + + if (error) throw error; + }, + + + + + + + + + + + // --------------------------------------------------------------------------- + // MAIN FUNCTIONS TO SYNC AN EAS FOLDER + // --------------------------------------------------------------------------- + + easFolder: async function (syncData) { + syncData.progressData.reset(); + + if (syncData.currentFolderData.getFolderProperty("downloadonly")) { + await eas.sync.revertLocalChanges(syncData); + } + + await eas.network.getItemEstimate(syncData); + await eas.sync.requestRemoteChanges(syncData); + + if (!syncData.currentFolderData.getFolderProperty("downloadonly")) { + let sendChanges = await eas.sync.sendLocalChanges(syncData); + if (sendChanges) { + // This is ugly as hell, but Microsoft sometimes sets the state of the + // remote account to "changed" after we have send a local change (even + // though it has acked the change) and this will cause the server to + // send a change request with our next sync. Because we follow the + // "server wins" policy, this will overwrite any additional local change + // we have done in the meantime. This is stupid, but we wait 2s and + // hope it is enough to catch this second ack of the local change. + let timer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer); + await new Promise(function (resolve, reject) { + let event = { + notify: function (timer) { + resolve(); + } + } + timer.initWithCallback(event, 2000, Components.interfaces.nsITimer.TYPE_ONE_SHOT); + }); + await eas.sync.requestRemoteChanges(syncData); + } + } + }, + + + requestRemoteChanges: async function (syncData) { + do { + syncData.setSyncState("prepare.request.remotechanges"); + syncData.request = ""; + syncData.response = ""; + + // BUILD WBXML + let wbxml = eas.wbxmltools.createWBXML(); + wbxml.otag("Sync"); + wbxml.otag("Collections"); + wbxml.otag("Collection"); + if (syncData.accountData.getAccountProperty("asversion") == "2.5") wbxml.atag("Class", syncData.type); + wbxml.atag("SyncKey", syncData.synckey); + wbxml.atag("CollectionId", syncData.currentFolderData.getFolderProperty("serverID")); + wbxml.atag("DeletesAsMoves"); + wbxml.atag("GetChanges"); + wbxml.atag("WindowSize", eas.prefs.getIntPref("maxitems").toString()); + + if (syncData.accountData.getAccountProperty("asversion") != "2.5") { + wbxml.otag("Options"); + if (syncData.type == "Calendar") wbxml.atag("FilterType", syncData.currentFolderData.accountData.getAccountProperty("synclimit")); + wbxml.atag("Class", syncData.type); + wbxml.switchpage("AirSyncBase"); + wbxml.otag("BodyPreference"); + wbxml.atag("Type", "1"); + wbxml.ctag(); + wbxml.switchpage("AirSync"); + wbxml.ctag(); + } else if (syncData.type == "Calendar") { //in 2.5 we only send it to filter Calendar + wbxml.otag("Options"); + wbxml.atag("FilterType", syncData.currentFolderData.accountData.getAccountProperty("synclimit")); + wbxml.ctag(); + } + + wbxml.ctag(); + wbxml.ctag(); + wbxml.ctag(); + + //SEND REQUEST + syncData.setSyncState("send.request.remotechanges"); + let response = await eas.network.sendRequest(wbxml.getBytes(), "Sync", syncData); + + //VALIDATE RESPONSE + // get data from wbxml response, some servers send empty response if there are no changes, which is not an error + let wbxmlData = eas.network.getDataFromResponse(response, eas.flags.allowEmptyResponse); + if (wbxmlData === null) return; + + //check status, throw on error + eas.network.checkStatus(syncData, wbxmlData, "Sync.Collections.Collection.Status"); + + //PROCESS COMMANDS + await eas.sync.processCommands(wbxmlData, syncData); + + //Update count in UI + syncData.setSyncState("eval.response.remotechanges"); + + //update synckey + eas.network.updateSynckey(syncData, wbxmlData); + + if (!eas.xmltools.hasWbxmlDataField(wbxmlData, "Sync.Collections.Collection.MoreAvailable")) { + //Feedback from users: They want to see the final count + await TbSync.tools.sleep(100); + return; + } + } while (true); + + }, + + + sendLocalChanges: async function (syncData) { + let maxnumbertosend = eas.prefs.getIntPref("maxitems"); + syncData.progressData.reset(0, syncData.target.getItemsFromChangeLog().length); + + //keep track of failed items + syncData.failedItems = []; + + let done = false; + let numberOfItemsToSend = maxnumbertosend; + let sendChanges = false; + do { + syncData.setSyncState("prepare.request.localchanges"); + syncData.request = ""; + syncData.response = ""; + + //get changed items from ChangeLog + let changes = syncData.target.getItemsFromChangeLog(numberOfItemsToSend); + //console.log("chnages", changes); + let c = 0; + let e = 0; + + //keep track of send items during this request + let changedItems = []; + let addedItems = {}; + let sendItems = []; + + // BUILD WBXML + let wbxml = eas.wbxmltools.createWBXML(); + wbxml.otag("Sync"); + wbxml.otag("Collections"); + wbxml.otag("Collection"); + if (syncData.accountData.getAccountProperty("asversion") == "2.5") wbxml.atag("Class", syncData.type); + wbxml.atag("SyncKey", syncData.synckey); + wbxml.atag("CollectionId", syncData.currentFolderData.getFolderProperty("serverID")); + wbxml.otag("Commands"); + + for (let i = 0; i < changes.length; i++) if (!syncData.failedItems.includes(changes[i].itemId)) { + //TbSync.dump("CHANGES",(i+1) + "/" + changes.length + " ("+changes[i].status+"," + changes[i].itemId + ")"); + let item = null; + switch (changes[i].status) { + + case "added_by_user": + item = await syncData.target.getItem(changes[i].itemId); + if (item) { + //filter out bad object types for this folder + if (syncData.type == "Contacts" && item.isMailList) { + // Mailing lists are not supported, this is not an error + TbSync.eventlog.add("warning", syncData.eventLogInfo, "MailingListNotSupportedItemSkipped"); + syncData.target.removeItemFromChangeLog(changes[i].itemId); + } else if (syncData.type == eas.sync.getEasItemType(item)) { + //create a temp clientId, to cope with too long or invalid clientIds (for EAS) + let clientId = Date.now() + "-" + c; + addedItems[clientId] = changes[i].itemId; + sendItems.push({ type: changes[i].status, id: changes[i].itemId }); + + wbxml.otag("Add"); + wbxml.atag("ClientId", clientId); //Our temp clientId will get replaced by an id generated by the server + wbxml.otag("ApplicationData"); + wbxml.switchpage(syncData.type); + + /*wbxml.atag("TimeZone", "xP///0UAdQByAG8AcABlAC8AQgBlAHIAbABpAG4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAFAAIAAAAAAAAAAAAAAEUAdQByAG8AcABlAC8AQgBlAHIAbABpAG4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAEAAAAAAAAAxP///w=="); + wbxml.atag("AllDayEvent", "0"); + wbxml.switchpage("AirSyncBase"); + wbxml.otag("Body"); + wbxml.atag("Type", "1"); + wbxml.atag("EstimatedDataSize", "0"); + wbxml.atag("Data"); + wbxml.ctag(); + + wbxml.switchpage(syncData.type); + wbxml.atag("BusyStatus", "2"); + wbxml.atag("OrganizerName", "REDACTED.REDACTED"); + wbxml.atag("OrganizerEmail", "REDACTED.REDACTED@REDACTED"); + wbxml.atag("DtStamp", "20190131T091024Z"); + wbxml.atag("EndTime", "20180906T083000Z"); + wbxml.atag("Location"); + wbxml.atag("Reminder", "5"); + wbxml.atag("Sensitivity", "0"); + wbxml.atag("Subject", "SE-CN weekly sync"); + wbxml.atag("StartTime", "20180906T080000Z"); + wbxml.atag("UID", "1D51E503-9DFE-4A46-A6C2-9129E5E00C1D"); + wbxml.atag("MeetingStatus", "3"); + wbxml.otag("Attendees"); + wbxml.otag("Attendee"); + wbxml.atag("Email", "REDACTED.REDACTED@REDACTED"); + wbxml.atag("Name", "REDACTED.REDACTED"); + wbxml.atag("AttendeeType", "1"); + wbxml.ctag(); + wbxml.ctag(); + wbxml.atag("Categories"); + wbxml.otag("Recurrence"); + wbxml.atag("Type", "1"); + wbxml.atag("DayOfWeek", "16"); + wbxml.atag("Interval", "1"); + wbxml.ctag(); + wbxml.otag("Exceptions"); + wbxml.otag("Exception"); + wbxml.atag("ExceptionStartTime", "20181227T090000Z"); + wbxml.atag("Deleted", "1"); + wbxml.ctag(); + wbxml.ctag();*/ + + wbxml.append(await eas.sync.getWbxmlFromThunderbirdItem(item, syncData)); + wbxml.switchpage("AirSync"); + wbxml.ctag(); + wbxml.ctag(); + c++; + } else { + eas.sync.updateFailedItems(syncData, "forbidden" + eas.sync.getEasItemType(item) + "ItemIn" + syncData.type + "Folder", item.primaryKey, item.toString()); + e++; + } + } else { + syncData.target.removeItemFromChangeLog(changes[i].itemId); + } + break; + + case "modified_by_user": + item = await syncData.target.getItem(changes[i].itemId); + if (item) { + //filter out bad object types for this folder + if (syncData.type == eas.sync.getEasItemType(item)) { + wbxml.otag("Change"); + wbxml.atag("ServerId", changes[i].itemId); + wbxml.otag("ApplicationData"); + wbxml.switchpage(syncData.type); + wbxml.append(await eas.sync.getWbxmlFromThunderbirdItem(item, syncData)); + wbxml.switchpage("AirSync"); + wbxml.ctag(); + wbxml.ctag(); + changedItems.push(changes[i].itemId); + sendItems.push({ type: changes[i].status, id: changes[i].itemId }); + c++; + } else { + eas.sync.updateFailedItems(syncData, "forbidden" + eas.sync.getEasItemType(item) + "ItemIn" + syncData.type + "Folder", item.primaryKey, item.toString()); + e++; + } + } else { + syncData.target.removeItemFromChangeLog(changes[i].itemId); + } + break; + + case "deleted_by_user": + wbxml.otag("Delete"); + wbxml.atag("ServerId", changes[i].itemId); + wbxml.ctag(); + changedItems.push(changes[i].itemId); + sendItems.push({ type: changes[i].status, id: changes[i].itemId }); + c++; + break; + } + } + + wbxml.ctag(); //Commands + wbxml.ctag(); //Collection + wbxml.ctag(); //Collections + wbxml.ctag(); //Sync + + + if (c > 0) { //if there was at least one actual local change, send request + sendChanges = true; + //SEND REQUEST & VALIDATE RESPONSE + syncData.setSyncState("send.request.localchanges"); + let response = await eas.network.sendRequest(wbxml.getBytes(), "Sync", syncData); + + syncData.setSyncState("eval.response.localchanges"); + + //get data from wbxml response + let wbxmlData = eas.network.getDataFromResponse(response); + + //check status and manually handle error states which support softfails + let errorcause = eas.network.checkStatus(syncData, wbxmlData, "Sync.Collections.Collection.Status", "", true); + switch (errorcause) { + case "": + break; + + case "Sync.4": //Malformed request + case "Sync.6": //Invalid item + //some servers send a global error - to catch this, we reduce the number of items we send to the server + if (sendItems.length == 1) { + //the request contained only one item, so we know which one failed + if (sendItems[0].type == "deleted_by_user") { + //we failed to delete an item, discard and place message in log + syncData.target.removeItemFromChangeLog(sendItems[0].id); + TbSync.eventlog.add("warning", syncData.eventLogInfo, "ErrorOnDelete::" + sendItems[0].id); + } else { + let foundItem = await syncData.target.getItem(sendItems[0].id); + if (foundItem) { + eas.sync.updateFailedItems(syncData, errorcause, foundItem.primaryKey, foundItem.toString()); + } else { + //should not happen + syncData.target.removeItemFromChangeLog(sendItems[0].id); + } + } + syncData.progressData.inc(); + //restore numberOfItemsToSend + numberOfItemsToSend = maxnumbertosend; + } else if (sendItems.length > 1) { + //reduce further + numberOfItemsToSend = Math.min(1, Math.round(sendItems.length / 5)); + } else { + //sendItems.length == 0 ??? recheck but this time let it handle all cases + eas.network.checkStatus(syncData, wbxmlData, "Sync.Collections.Collection.Status"); + } + break; + + default: + //recheck but this time let it handle all cases + eas.network.checkStatus(syncData, wbxmlData, "Sync.Collections.Collection.Status"); + } + + await TbSync.tools.sleep(10, true); + + if (errorcause == "") { + //PROCESS RESPONSE + await eas.sync.processResponses(wbxmlData, syncData, addedItems, changedItems); + + //PROCESS COMMANDS + await eas.sync.processCommands(wbxmlData, syncData); + + //remove all items from changelog that did not fail + for (let a = 0; a < changedItems.length; a++) { + syncData.target.removeItemFromChangeLog(changedItems[a]); + syncData.progressData.inc(); + } + + //update synckey + eas.network.updateSynckey(syncData, wbxmlData); + } + + } else if (e == 0) { //if there was no local change and also no error (which will not happen twice) finish + + done = true; + + } + + } while (!done); + + //was there an error? + if (syncData.failedItems.length > 0) { + throw eas.sync.finish("warning", "ServerRejectedSomeItems::" + syncData.failedItems.length); + } + return sendChanges; + }, + + + + + revertLocalChanges: async function (syncData) { + let maxnumbertosend = eas.prefs.getIntPref("maxitems"); + syncData.progressData.reset(0, syncData.target.getItemsFromChangeLog().length); + if (syncData.progressData.todo == 0) { + return; + } + + let viaItemOperations = (syncData.accountData.getAccountProperty("allowedEasCommands").split(",").includes("ItemOperations")); + + //get changed items from ChangeLog + do { + syncData.setSyncState("prepare.request.revertlocalchanges"); + let changes = syncData.target.getItemsFromChangeLog(maxnumbertosend); + let c = 0; + syncData.request = ""; + syncData.response = ""; + + // BUILD WBXML + let wbxml = eas.wbxmltools.createWBXML(); + if (viaItemOperations) { + wbxml.switchpage("ItemOperations"); + wbxml.otag("ItemOperations"); + } else { + wbxml.otag("Sync"); + wbxml.otag("Collections"); + wbxml.otag("Collection"); + if (syncData.accountData.getAccountProperty("asversion") == "2.5") wbxml.atag("Class", syncData.type); + wbxml.atag("SyncKey", syncData.synckey); + wbxml.atag("CollectionId", syncData.currentFolderData.getFolderProperty("serverID")); + wbxml.otag("Commands"); + } + + for (let i = 0; i < changes.length; i++) { + let item = null; + let ServerId = changes[i].itemId; + let foundItem = await syncData.target.getItem(ServerId); + + switch (changes[i].status) { + case "added_by_user": //remove + if (foundItem) { + await syncData.target.deleteItem(foundItem); + } + break; + + case "modified_by_user": + if (foundItem) { //delete item so it can be replaced with a fresh copy, the changelog entry will be changed from modified to deleted + await syncData.target.deleteItem(foundItem); + } + case "deleted_by_user": + if (viaItemOperations) { + wbxml.otag("Fetch"); + wbxml.atag("Store", "Mailbox"); + wbxml.switchpage("AirSync"); + wbxml.atag("CollectionId", syncData.currentFolderData.getFolderProperty("serverID")); + wbxml.atag("ServerId", ServerId); + wbxml.switchpage("ItemOperations"); + wbxml.otag("Options"); + wbxml.switchpage("AirSyncBase"); + wbxml.otag("BodyPreference"); + wbxml.atag("Type", "1"); + wbxml.ctag(); + wbxml.switchpage("ItemOperations"); + wbxml.ctag(); + wbxml.ctag(); + } else { + wbxml.otag("Fetch"); + wbxml.atag("ServerId", ServerId); + wbxml.ctag(); + } + c++; + break; + } + } + + if (viaItemOperations) { + wbxml.ctag(); //ItemOperations + } else { + wbxml.ctag(); //Commands + wbxml.ctag(); //Collection + wbxml.ctag(); //Collections + wbxml.ctag(); //Sync + } + + if (c > 0) { //if there was at least one actual local change, send request + let error = false; + let wbxmlData = ""; + + //SEND REQUEST & VALIDATE RESPONSE + try { + syncData.setSyncState("send.request.revertlocalchanges"); + let response = await eas.network.sendRequest(wbxml.getBytes(), (viaItemOperations) ? "ItemOperations" : "Sync", syncData); + + syncData.setSyncState("eval.response.revertlocalchanges"); + + //get data from wbxml response + wbxmlData = eas.network.getDataFromResponse(response); + } catch (e) { + //we do not handle errors, IF there was an error, wbxmlData is empty and will trigger the fallback + } + + let fetchPath = (viaItemOperations) ? "ItemOperations.Response.Fetch" : "Sync.Collections.Collection.Responses.Fetch"; + if (eas.xmltools.hasWbxmlDataField(wbxmlData, fetchPath)) { + + //looking for additions + let add = eas.xmltools.nodeAsArray(eas.xmltools.getWbxmlDataField(wbxmlData, fetchPath)); + for (let count = 0; count < add.length; count++) { + await TbSync.tools.sleep(10, true); + + let ServerId = add[count].ServerId; + let data = (viaItemOperations) ? add[count].Properties : add[count].ApplicationData; + + if (data && ServerId) { + let foundItem = await syncData.target.getItem(ServerId); + if (!foundItem) { //do NOT add, if an item with that ServerId was found + let newItem = eas.sync.createItem(syncData); + try { + eas.sync[syncData.type].setThunderbirdItemFromWbxml(newItem, data, ServerId, syncData); + await syncData.target.addItem(newItem); + } catch (e) { + eas.xmltools.printXmlData(add[count], true); //include application data in log + TbSync.eventlog.add("warning", syncData.eventLogInfo, "BadItemSkipped::JavaScriptError", newItem.toString()); + throw e; // unable to add item to Thunderbird - fatal error + } + } else { + //should not happen, since we deleted that item beforehand + syncData.target.removeItemFromChangeLog(ServerId); + } + syncData.progressData.inc(); + } else { + error = true; + break; + } + } + } else { + error = true; + } + + if (error) { + //if ItemOperations.Fetch fails, fall back to Sync.Fetch, if that fails, fall back to resync + if (viaItemOperations) { + viaItemOperations = false; + TbSync.eventlog.add("info", syncData.eventLogInfo, "Server returned error during ItemOperations.Fetch, falling back to Sync.Fetch."); + } else { + await eas.sync.revertLocalChangesViaResync(syncData); + return; + } + } + + } else { //if there was no more local change we need to revert, return + + return; + + } + + } while (true); + + }, + + revertLocalChangesViaResync: async function (syncData) { + TbSync.eventlog.add("info", syncData.eventLogInfo, "Server does not support ItemOperations.Fetch and/or Sync.Fetch, must revert via resync."); + let changes = syncData.target.getItemsFromChangeLog(); + + syncData.progressData.reset(0, changes.length); + syncData.setSyncState("prepare.request.revertlocalchanges"); + + //remove all changes, so we can get them fresh from the server + for (let i = 0; i < changes.length; i++) { + let item = null; + let ServerId = changes[i].itemId; + syncData.target.removeItemFromChangeLog(ServerId); + let foundItem = await syncData.target.getItem(ServerId); + if (foundItem) { //delete item with that ServerId + await syncData.target.deleteItem(foundItem); + } + syncData.progressData.inc(); + } + + //This will resync all missing items fresh from the server + TbSync.eventlog.add("info", syncData.eventLogInfo, "RevertViaFolderResync"); + eas.sync.resetFolderSyncInfo(syncData.currentFolderData); + throw eas.sync.finish("resyncFolder", "RevertViaFolderResync"); + }, + + + + + // --------------------------------------------------------------------------- + // SUB FUNCTIONS CALLED BY MAIN FUNCTION + // --------------------------------------------------------------------------- + + processCommands: async function (wbxmlData, syncData) { + //any commands for us to work on? If we reach this point, Sync.Collections.Collection is valid, + //no need to use the save getWbxmlDataField function + if (wbxmlData.Sync.Collections.Collection.Commands) { + + //looking for additions + let add = eas.xmltools.nodeAsArray(wbxmlData.Sync.Collections.Collection.Commands.Add); + for (let count = 0; count < add.length; count++) { + await TbSync.tools.sleep(10, true); + + let ServerId = add[count].ServerId; + let data = add[count].ApplicationData; + + let foundItem = await syncData.target.getItem(ServerId); + if (!foundItem) { + //do NOT add, if an item with that ServerId was found + let newItem = eas.sync.createItem(syncData); + try { + eas.sync[syncData.type].setThunderbirdItemFromWbxml(newItem, data, ServerId, syncData); + await syncData.target.addItem(newItem); + } catch (e) { + eas.xmltools.printXmlData(add[count], true); //include application data in log + TbSync.eventlog.add("warning", syncData.eventLogInfo, "BadItemSkipped::JavaScriptError", newItem.toString()); + throw e; // unable to add item to Thunderbird - fatal error + } + } else { + TbSync.eventlog.add("info", syncData.eventLogInfo, "Add request, but element exists already, skipped.", ServerId); + } + syncData.progressData.inc(); + } + + //looking for changes + let upd = eas.xmltools.nodeAsArray(wbxmlData.Sync.Collections.Collection.Commands.Change); + //inject custom change object for debug + //upd = JSON.parse('[{"ServerId":"2tjoanTeS0CJ3QTsq5vdNQAAAAABDdrY6Gp03ktAid0E7Kub3TUAAAoZy4A1","ApplicationData":{"DtStamp":"20171109T142149Z"}}]'); + for (let count = 0; count < upd.length; count++) { + await TbSync.tools.sleep(10, true); + + let ServerId = upd[count].ServerId; + let data = upd[count].ApplicationData; + + syncData.progressData.inc(); + let foundItem = await syncData.target.getItem(ServerId); + if (foundItem) { //only update, if an item with that ServerId was found + + let keys = Object.keys(data); + //replace by smart merge + if (keys.length == 1 && keys[0] == "DtStamp") TbSync.dump("DtStampOnly", keys); //ignore DtStamp updates (fix with smart merge) + else { + + if (foundItem.changelogStatus !== null) { + TbSync.eventlog.add("info", syncData.eventLogInfo, "Change request from server, but also local modifications, server wins!", ServerId); + foundItem.changelogStatus = null; + } + + let newItem = foundItem.clone(); + try { + eas.sync[syncData.type].setThunderbirdItemFromWbxml(newItem, data, ServerId, syncData); + await syncData.target.modifyItem(newItem, foundItem); + } catch (e) { + TbSync.eventlog.add("warning", syncData.eventLogInfo, "BadItemSkipped::JavaScriptError", newItem.toString()); + eas.xmltools.printXmlData(upd[count], true); //include application data in log + throw e; // unable to mod item to Thunderbird - fatal error + } + } + + } + } + + //looking for deletes + let del = eas.xmltools.nodeAsArray(wbxmlData.Sync.Collections.Collection.Commands.Delete).concat(eas.xmltools.nodeAsArray(wbxmlData.Sync.Collections.Collection.Commands.SoftDelete)); + for (let count = 0; count < del.length; count++) { + await TbSync.tools.sleep(10, true); + + let ServerId = del[count].ServerId; + + let foundItem = await syncData.target.getItem(ServerId); + if (foundItem) { //delete item with that ServerId + await syncData.target.deleteItem(foundItem); + } + syncData.progressData.inc(); + } + + } + }, + + + updateFailedItems: function (syncData, cause, id, data) { + //something is wrong with this item, move it to the end of changelog and go on + if (!syncData.failedItems.includes(id)) { + //the extra parameter true will re-add the item to the end of the changelog + syncData.target.removeItemFromChangeLog(id, true); + syncData.failedItems.push(id); + TbSync.eventlog.add("info", syncData.eventLogInfo, "BadItemSkipped::" + TbSync.getString("status." + cause, "eas"), "\n\nRequest:\n" + syncData.request + "\n\nResponse:\n" + syncData.response + "\n\nElement:\n" + data); + } + }, + + + processResponses: async function (wbxmlData, syncData, addedItems, changedItems) { + //any responses for us to work on? If we reach this point, Sync.Collections.Collection is valid, + //no need to use the save getWbxmlDataField function + if (wbxmlData.Sync.Collections.Collection.Responses) { + + //looking for additions (Add node contains, status, old ClientId and new ServerId) + let add = eas.xmltools.nodeAsArray(wbxmlData.Sync.Collections.Collection.Responses.Add); + for (let count = 0; count < add.length; count++) { + await TbSync.tools.sleep(10, true); + + //get the true Thunderbird UID of this added item (we created a temp clientId during add) + add[count].ClientId = addedItems[add[count].ClientId]; + + //look for an item identfied by ClientId and update its id to the new id received from the server + let foundItem = await syncData.target.getItem(add[count].ClientId); + if (foundItem) { + + //Check status, stop sync if bad, allow soft fail + let errorcause = eas.network.checkStatus(syncData, add[count], "Status", "Sync.Collections.Collection.Responses.Add[" + count + "].Status", true); + if (errorcause !== "") { + //something is wrong with this item, move it to the end of changelog and go on + eas.sync.updateFailedItems(syncData, errorcause, foundItem.primaryKey, foundItem.toString()); + } else { + let newItem = foundItem.clone(); + newItem.primaryKey = add[count].ServerId; + syncData.target.removeItemFromChangeLog(add[count].ClientId); + await syncData.target.modifyItem(newItem, foundItem); + syncData.progressData.inc(); + } + + } + } + + //looking for modifications + let upd = eas.xmltools.nodeAsArray(wbxmlData.Sync.Collections.Collection.Responses.Change); + for (let count = 0; count < upd.length; count++) { + let foundItem = await syncData.target.getItem(upd[count].ServerId); + if (foundItem) { + + //Check status, stop sync if bad, allow soft fail + let errorcause = eas.network.checkStatus(syncData, upd[count], "Status", "Sync.Collections.Collection.Responses.Change[" + count + "].Status", true); + if (errorcause !== "") { + //something is wrong with this item, move it to the end of changelog and go on + eas.sync.updateFailedItems(syncData, errorcause, foundItem.primaryKey, foundItem.toString()); + //also remove from changedItems + let p = changedItems.indexOf(upd[count].ServerId); + if (p > -1) changedItems.splice(p, 1); + } + + } + } + + //looking for deletions + let del = eas.xmltools.nodeAsArray(wbxmlData.Sync.Collections.Collection.Responses.Delete); + for (let count = 0; count < del.length; count++) { + //What can we do about failed deletes? SyncLog + eas.network.checkStatus(syncData, del[count], "Status", "Sync.Collections.Collection.Responses.Delete[" + count + "].Status", true); + } + + } + }, + + + + + + + + + + + // --------------------------------------------------------------------------- + // HELPER FUNCTIONS AND DEFINITIONS + // --------------------------------------------------------------------------- + + MAP_EAS2TB: { + //EAS Importance: 0 = LOW | 1 = NORMAL | 2 = HIGH + Importance: { "0": "9", "1": "5", "2": "1" }, //to PRIORITY + //EAS Sensitivity : 0 = Normal | 1 = Personal | 2 = Private | 3 = Confidential + Sensitivity: { "0": "PUBLIC", "1": "PRIVATE", "2": "PRIVATE", "3": "CONFIDENTIAL" }, //to CLASS + //EAS BusyStatus: 0 = Free | 1 = Tentative | 2 = Busy | 3 = Work | 4 = Elsewhere + BusyStatus: { "0": "TRANSPARENT", "1": "unset", "2": "OPAQUE", "3": "OPAQUE", "4": "OPAQUE" }, //to TRANSP + //EAS AttendeeStatus: 0 =Response unknown (but needed) | 2 = Tentative | 3 = Accept | 4 = Decline | 5 = Not responded (and not needed) || 1 = Organizer in ResponseType + ATTENDEESTATUS: { "0": "NEEDS-ACTION", "1": "Orga", "2": "TENTATIVE", "3": "ACCEPTED", "4": "DECLINED", "5": "ACCEPTED" }, + }, + + MAP_TB2EAS: { + //TB PRIORITY: 9 = LOW | 5 = NORMAL | 1 = HIGH + PRIORITY: { "9": "0", "5": "1", "1": "2", "unset": "1" }, //to Importance + //TB CLASS: PUBLIC, PRIVATE, CONFIDENTIAL) + CLASS: { "PUBLIC": "0", "PRIVATE": "2", "CONFIDENTIAL": "3", "unset": "0" }, //to Sensitivity + //TB TRANSP : free = TRANSPARENT, busy = OPAQUE) + TRANSP: { "TRANSPARENT": "0", "unset": "1", "OPAQUE": "2" }, // to BusyStatus + //TB STATUS: NEEDS-ACTION, ACCEPTED, DECLINED, TENTATIVE, (DELEGATED, COMPLETED, IN-PROCESS - for todo) + ATTENDEESTATUS: { "NEEDS-ACTION": "0", "ACCEPTED": "3", "DECLINED": "4", "TENTATIVE": "2", "DELEGATED": "5", "COMPLETED": "5", "IN-PROCESS": "5" }, + }, + + mapEasPropertyToThunderbird: function (easProp, tbProp, data, item) { + if (data[easProp]) { + //store original EAS value + let easPropValue = eas.xmltools.checkString(data[easProp]); + item.setProperty("X-EAS-" + easProp, easPropValue); + //map EAS value to TB value (use setCalItemProperty if there is one option which can unset/delete the property) + eas.tools.setCalItemProperty(item, tbProp, eas.sync.MAP_EAS2TB[easProp][easPropValue]); + } + }, + + mapThunderbirdPropertyToEas: function (tbProp, easProp, item) { + if (item.hasProperty("X-EAS-" + easProp) && eas.tools.getCalItemProperty(item, tbProp) == eas.sync.MAP_EAS2TB[easProp][item.getProperty("X-EAS-" + easProp)]) { + //we can use our stored EAS value, because it still maps to the current TB value + return item.getProperty("X-EAS-" + easProp); + } else { + return eas.sync.MAP_TB2EAS[tbProp][eas.tools.getCalItemProperty(item, tbProp)]; + } + }, + + getEasItemType(aItem) { + if (aItem instanceof TbSync.addressbook.AbItem) { + return "Contacts"; + } else if (aItem instanceof TbSync.lightning.TbItem) { + return aItem.isTodo ? "Tasks" : "Calendar"; + } else { + throw "Unknown aItem."; + } + }, + + createItem(syncData) { + switch (syncData.type) { + case "Contacts": + return syncData.target.createNewCard(); + break; + + case "Tasks": + return syncData.target.createNewTodo(); + break; + + case "Calendar": + return syncData.target.createNewEvent(); + break; + + default: + throw "Unknown item type <" + syncData.type + ">"; + } + }, + + async getWbxmlFromThunderbirdItem(item, syncData, isException = false) { + try { + let wbxml = await eas.sync[syncData.type].getWbxmlFromThunderbirdItem(item, syncData, isException); + return wbxml; + } catch (e) { + TbSync.eventlog.add("warning", syncData.eventLogInfo, "BadItemSkipped::JavaScriptError", item.toString()); + throw e; // unable to read item from Thunderbird - fatal error + } + }, + + + + + + + + // --------------------------------------------------------------------------- + // LIGHTNING HELPER FUNCTIONS AND DEFINITIONS + // These functions are needed only by tasks and events, so they + // are placed here, even though they are not type independent, + // but I did not want to add another "lightning" sub layer. + // + // The item in these functions is a native lightning item. + // --------------------------------------------------------------------------- + + setItemSubject: function (item, syncData, data) { + if (data.Subject) item.title = eas.xmltools.checkString(data.Subject); + }, + + setItemLocation: function (item, syncData, data) { + if (data.Location) item.setProperty("location", eas.xmltools.checkString(data.Location)); + }, + + + setItemCategories: function (item, syncData, data) { + if (data.Categories && data.Categories.Category) { + let cats = []; + if (Array.isArray(data.Categories.Category)) cats = data.Categories.Category; + else cats.push(data.Categories.Category); + item.setCategories(cats); + } + }, + + getItemCategories: function (item, syncData) { + let asversion = syncData.accountData.getAccountProperty("asversion"); + let wbxml = eas.wbxmltools.createWBXML("", syncData.type); //init wbxml with "" and not with precodes, also activate type codePage (Calendar, Tasks, Contacts etc) + + //to properly "blank" categories, we need to always include the container + let categories = item.getCategories({}); + if (categories.length > 0) { + wbxml.otag("Categories"); + for (let i = 0; i < categories.length; i++) wbxml.atag("Category", categories[i]); + wbxml.ctag(); + } else { + wbxml.atag("Categories"); + } + return wbxml.getBytes(); + }, + + + setItemBody: function (item, syncData, data) { + let asversion = syncData.accountData.getAccountProperty("asversion"); + if (asversion == "2.5") { + if (data.Body) item.setProperty("description", eas.xmltools.checkString(data.Body)); + } else { + if (data.Body && /* data.Body.EstimatedDataSize > 0 && */ data.Body.Data) item.setProperty("description", eas.xmltools.checkString(data.Body.Data)); //EstimatedDataSize is optional + } + }, + + getItemBody: function (item, syncData) { + let asversion = syncData.accountData.getAccountProperty("asversion"); + let wbxml = eas.wbxmltools.createWBXML("", syncData.type); //init wbxml with "" and not with precodes, also activate type codePage (Calendar, Tasks, Contacts etc) + + let description = (item.hasProperty("description")) ? item.getProperty("description") : ""; + if (asversion == "2.5") { + wbxml.atag("Body", description); + } else { + wbxml.switchpage("AirSyncBase"); + wbxml.otag("Body"); + wbxml.atag("Type", "1"); + wbxml.atag("EstimatedDataSize", "" + description.length); + wbxml.atag("Data", description); + wbxml.ctag(); + //does not work with horde at the moment, does not work with task, does not work with exceptions + //if (syncData.accountData.getAccountProperty("horde") == "0") wbxml.atag("NativeBodyType", "1"); + + //return to code page of this type + wbxml.switchpage(syncData.type); + } + return wbxml.getBytes(); + }, + + //item is a native lightning item + setItemRecurrence: function (item, syncData, data, timezone) { + if (data.Recurrence) { + item.recurrenceInfo = new CalRecurrenceInfo(); + item.recurrenceInfo.item = item; + let recRule = TbSync.lightning.cal.createRecurrenceRule(); + switch (data.Recurrence.Type) { + case "0": + recRule.type = "DAILY"; + break; + case "1": + recRule.type = "WEEKLY"; + break; + case "2": + case "3": + recRule.type = "MONTHLY"; + break; + case "5": + case "6": + recRule.type = "YEARLY"; + break; + } + + if (data.Recurrence.CalendarType) { + // TODO + } + if (data.Recurrence.DayOfMonth) { + recRule.setComponent("BYMONTHDAY", [data.Recurrence.DayOfMonth]); + } + if (data.Recurrence.DayOfWeek) { + let DOW = data.Recurrence.DayOfWeek; + if (DOW == 127 && (recRule.type == "MONTHLY" || recRule.type == "YEARLY")) { + recRule.setComponent("BYMONTHDAY", [-1]); + } + else { + let days = []; + for (let i = 0; i < 7; ++i) { + if (DOW & 1 << i) days.push(i + 1); + } + if (data.Recurrence.WeekOfMonth) { + for (let i = 0; i < days.length; ++i) { + if (data.Recurrence.WeekOfMonth == 5) { + days[i] = -1 * (days[i] + 8); + } + else { + days[i] += 8 * (data.Recurrence.WeekOfMonth - 0); + } + } + } + recRule.setComponent("BYDAY", days); + } + } + if (data.Recurrence.FirstDayOfWeek) { + //recRule.setComponent("WKST", [data.Recurrence.FirstDayOfWeek]); // WKST is not a valid component + //recRule.weekStart = data.Recurrence.FirstDayOfWeek; // - (NS_ERROR_NOT_IMPLEMENTED) [calIRecurrenceRule.weekStart] + TbSync.eventlog.add("info", syncData.eventLogInfo, "FirstDayOfWeek tag ignored (not supported).", item.icalString); + } + + if (data.Recurrence.Interval) { + recRule.interval = data.Recurrence.Interval; + } + if (data.Recurrence.IsLeapMonth) { + // TODO + } + if (data.Recurrence.MonthOfYear) { + recRule.setComponent("BYMONTH", [data.Recurrence.MonthOfYear]); + } + if (data.Recurrence.Occurrences) { + recRule.count = data.Recurrence.Occurrences; + } + if (data.Recurrence.Until) { + //time string could be in compact/basic or extended form of ISO 8601, + //cal.createDateTime only supports compact/basic, our own method takes both styles + recRule.untilDate = eas.tools.createDateTime(data.Recurrence.Until); + } + if (data.Recurrence.Start) { + TbSync.eventlog.add("info", syncData.eventLogInfo, "Start tag in recurring task is ignored, recurrence will start with first entry.", item.icalString); + } + + item.recurrenceInfo.insertRecurrenceItemAt(recRule, 0); + + if (data.Exceptions && syncData.type == "Calendar") { // only events, tasks cannot have exceptions + // Exception could be an object or an array of objects + let exceptions = [].concat(data.Exceptions.Exception); + for (let exception of exceptions) { + //exception.ExceptionStartTime is in UTC, but the Recurrence Object is in local timezone + let dateTime = TbSync.lightning.cal.createDateTime(exception.ExceptionStartTime).getInTimezone(timezone); + if (data.AllDayEvent == "1") { + dateTime.isDate = true; + // Pass to replacement event unless overriden + if (!exception.AllDayEvent) { + exception.AllDayEvent = "1"; + } + } + if (exception.Deleted == "1") { + item.recurrenceInfo.removeOccurrenceAt(dateTime); + } + else { + let replacement = item.recurrenceInfo.getOccurrenceFor(dateTime); + // replacement is a native lightning item, so we can access its id via .id + eas.sync[syncData.type].setThunderbirdItemFromWbxml(replacement, exception, replacement.id, syncData, "recurrence"); + // Reminders should carry over from parent, but setThunderbirdItemFromWbxml clears all alarms + if (!exception.Reminder && item.getAlarms({}).length) { + replacement.addAlarm(item.getAlarms({})[0]); + } + // Removing a reminder requires EAS 16.0 + item.recurrenceInfo.modifyException(replacement, true); + } + } + } + } + }, + + getItemRecurrence: async function (item, syncData, localStartDate = null) { + let asversion = syncData.accountData.getAccountProperty("asversion"); + let wbxml = eas.wbxmltools.createWBXML("", syncData.type); //init wbxml with "" and not with precodes, also activate type codePage (Calendar, Tasks etc) + + if (item.recurrenceInfo && (syncData.type == "Calendar" || syncData.type == "Tasks")) { + let deleted = []; + let hasRecurrence = false; + let startDate = (syncData.type == "Calendar") ? item.startDate : item.entryDate; + + for (let recRule of item.recurrenceInfo.getRecurrenceItems({})) { + if (recRule.date) { + if (recRule.isNegative) { + // EXDATE + deleted.push(recRule); + } + else { + // RDATE + TbSync.eventlog.add("info", syncData.eventLogInfo, "Ignoring RDATE rule (not supported)", recRule.icalString); + } + continue; + } + if (recRule.isNegative) { + // EXRULE + TbSync.eventlog.add("info", syncData.eventLogInfo, "Ignoring EXRULE rule (not supported)", recRule.icalString); + continue; + } + + // RRULE + wbxml.otag("Recurrence"); + hasRecurrence = true; + + let type = 0; + let monthDays = recRule.getComponent("BYMONTHDAY", {}); + let weekDays = recRule.getComponent("BYDAY", {}); + let months = recRule.getComponent("BYMONTH", {}); + let weeks = []; + + // Unpack 1MO style days + for (let i = 0; i < weekDays.length; ++i) { + if (weekDays[i] > 8) { + weeks[i] = Math.floor(weekDays[i] / 8); + weekDays[i] = weekDays[i] % 8; + } + else if (weekDays[i] < -8) { + // EAS only supports last week as a special value, treat + // all as last week or assume every month has 5 weeks? + // Change to last week + //weeks[i] = 5; + // Assumes 5 weeks per month for week <= -2 + weeks[i] = 6 - Math.floor(-weekDays[i] / 8); + weekDays[i] = -weekDays[i] % 8; + } + } + if (monthDays[0] && monthDays[0] == -1) { + weeks = [5]; + weekDays = [1, 2, 3, 4, 5, 6, 7]; // 127 + monthDays[0] = null; + } + // Type + if (recRule.type == "WEEKLY") { + type = 1; + if (!weekDays.length) { + weekDays = [startDate.weekday + 1]; + } + } + else if (recRule.type == "MONTHLY" && weeks.length) { + type = 3; + } + else if (recRule.type == "MONTHLY") { + type = 2; + if (!monthDays.length) { + monthDays = [startDate.day]; + } + } + else if (recRule.type == "YEARLY" && weeks.length) { + type = 6; + } + else if (recRule.type == "YEARLY") { + type = 5; + if (!monthDays.length) { + monthDays = [startDate.day]; + } + if (!months.length) { + months = [startDate.month + 1]; + } + } + wbxml.atag("Type", type.toString()); + + //Tasks need a Start tag, but we cannot allow a start date different from the start of the main item (thunderbird does not support that) + if (localStartDate) wbxml.atag("Start", localStartDate); + + // TODO: CalendarType: 14.0 and up + // DayOfMonth + if (monthDays[0]) { + // TODO: Multiple days of month - multiple Recurrence tags? + wbxml.atag("DayOfMonth", monthDays[0].toString()); + } + // DayOfWeek + if (weekDays.length) { + let bitfield = 0; + for (let day of weekDays) { + bitfield |= 1 << (day - 1); + } + wbxml.atag("DayOfWeek", bitfield.toString()); + } + // FirstDayOfWeek: 14.1 and up + //wbxml.atag("FirstDayOfWeek", recRule.weekStart); - (NS_ERROR_NOT_IMPLEMENTED) [calIRecurrenceRule.weekStart] + // Interval + wbxml.atag("Interval", recRule.interval.toString()); + // TODO: IsLeapMonth: 14.0 and up + // MonthOfYear + if (months.length) { + wbxml.atag("MonthOfYear", months[0].toString()); + } + // Occurrences + if (recRule.isByCount) { + wbxml.atag("Occurrences", recRule.count.toString()); + } + // Until + else if (recRule.untilDate != null) { + //Events need the Until data in compact form, Tasks in the basic form + wbxml.atag("Until", eas.tools.getIsoUtcString(recRule.untilDate, (syncData.type == "Tasks"))); + } + // WeekOfMonth + if (weeks.length) { + wbxml.atag("WeekOfMonth", weeks[0].toString()); + } + wbxml.ctag(); + } + + if (syncData.type == "Calendar" && hasRecurrence) { //Exceptions only allowed in Calendar and only if a valid Recurrence was added + let modifiedIds = item.recurrenceInfo.getExceptionIds({}); + if (deleted.length || modifiedIds.length) { + wbxml.otag("Exceptions"); + for (let exception of deleted) { + wbxml.otag("Exception"); + wbxml.atag("ExceptionStartTime", eas.tools.getIsoUtcString(exception.date)); + wbxml.atag("Deleted", "1"); + //Docs say it is allowed, but if present, it does not work + //if (asversion == "2.5") { + // wbxml.atag("UID", item.id); //item.id is not valid, use UID or primaryKey + //} + wbxml.ctag(); + } + for (let exceptionId of modifiedIds) { + let replacement = item.recurrenceInfo.getExceptionFor(exceptionId); + wbxml.otag("Exception"); + wbxml.atag("ExceptionStartTime", eas.tools.getIsoUtcString(exceptionId)); + wbxml.append(await eas.sync.getWbxmlFromThunderbirdItem(replacement, syncData, true)); + wbxml.ctag(); + } + wbxml.ctag(); + } + } + } + + return wbxml.getBytes(); + } + +} diff -Nru eas4tbsync-4.11/content/includes/tasksync.js eas4tbsync-4.17/content/includes/tasksync.js --- eas4tbsync-4.11/content/includes/tasksync.js 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/content/includes/tasksync.js 2025-05-15 11:21:20.000000000 +0000 @@ -1,212 +1,217 @@ -/* - * This file is part of EAS-4-TbSync. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -"use strict"; - -var { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); -var { TbSync } = ChromeUtils.import("chrome://tbsync/content/tbsync.jsm"); - -XPCOMUtils.defineLazyModuleGetters(this, { - CalAlarm: "resource:///modules/CalAlarm.jsm", - CalAttachment: "resource:///modules/CalAttachment.jsm", - CalAttendee: "resource:///modules/CalAttendee.jsm", - CalEvent: "resource:///modules/CalEvent.jsm", - CalTodo: "resource:///modules/CalTodo.jsm", -}); - -var Tasks = { - - // --------------------------------------------------------------------------- // - // Read WBXML and set Thunderbird item - // --------------------------------------------------------------------------- // - setThunderbirdItemFromWbxml: function (tbItem, data, id, syncdata, mode = "standard") { - - let item = tbItem instanceof TbSync.lightning.TbItem ? tbItem.nativeItem : tbItem; - - let asversion = syncdata.accountData.getAccountProperty("asversion"); - item.id = id; - eas.sync.setItemSubject(item, syncdata, data); - if (TbSync.prefs.getIntPref("log.userdatalevel") > 2) TbSync.dump("Processing " + mode + " task item", item.title + " (" + id + ")"); - - eas.sync.setItemBody(item, syncdata, data); - eas.sync.setItemCategories(item, syncdata, data); - eas.sync.setItemRecurrence(item, syncdata, data); - - let dueDate = null; - if (data.DueDate && data.UtcDueDate) { - //extract offset from EAS data - let DueDate = new Date(data.DueDate); - let UtcDueDate = new Date(data.UtcDueDate); - let offset = (UtcDueDate.getTime() - DueDate.getTime())/60000; - - //timezone is identified by its offset - let utc = cal.createDateTime(eas.tools.dateToBasicISOString(UtcDueDate)); //format "19800101T000000Z" - UTC - dueDate = utc.getInTimezone(eas.tools.guessTimezoneByCurrentOffset(offset, utc)); - item.dueDate = dueDate; - } - - if (data.StartDate && data.UtcStartDate) { - //extract offset from EAS data - let StartDate = new Date(data.StartDate); - let UtcStartDate = new Date(data.UtcStartDate); - let offset = (UtcStartDate.getTime() - StartDate.getTime())/60000; - - //timezone is identified by its offset - let utc = cal.createDateTime(eas.tools.dateToBasicISOString(UtcStartDate)); //format "19800101T000000Z" - UTC - item.entryDate = utc.getInTimezone(eas.tools.guessTimezoneByCurrentOffset(offset, utc)); - } else { - //there is no start date? if this is a recurring item, we MUST add an entryDate, otherwise Thunderbird will not display the recurring items - if (data.Recurrence) { - if (dueDate) { - item.entryDate = dueDate; - TbSync.eventlog.add("info", syncdata, "Copy task dueData to task startDate, because Thunderbird needs a startDate for recurring items.", item.icalString); - } else { - TbSync.eventlog.add("info", syncdata, "Task without startDate and without dueDate but with recurrence info is not supported by Thunderbird. Recurrence will be lost.", item.icalString); - } - } - } - - eas.sync.mapEasPropertyToThunderbird ("Sensitivity", "CLASS", data, item); - eas.sync.mapEasPropertyToThunderbird ("Importance", "PRIORITY", data, item); - - let msTodoCompat = eas.prefs.getBoolPref("msTodoCompat"); - - item.clearAlarms(); - if (data.ReminderSet && data.ReminderTime) { - let UtcAlarmDate = eas.tools.createDateTime(data.ReminderTime); - let alarm = new CalAlarm(); - alarm.action = "DISPLAY"; - - if (msTodoCompat) - { - // Microsoft To-Do only uses due dates (no start dates) an doesn't have a time part in the due date - // dirty hack: Use the reminder date as due date and set a reminder exactly to the due date - // drawback: only works if due date and reminder is set to the same day - this could maybe checked here but I don't know how - item.entryDate = UtcAlarmDate; - item.dueDate = UtcAlarmDate; - alarm.related = Components.interfaces.calIAlarm.ALARM_RELATED_START; - alarm.offset = TbSync.lightning.cal.createDuration(); - alarm.offset.inSeconds = 0; - } - else if (data.UtcStartDate) - { - let UtcDate = eas.tools.createDateTime(data.UtcStartDate); - alarm.related = Components.interfaces.calIAlarm.ALARM_RELATED_START; - alarm.offset = UtcAlarmDate.subtractDate(UtcDate); - } - else - { - // Alternative solution for Microsoft To-Do: - // alarm correctly set but because time part of due date is always "0:00", all tasks for today are shown as overdue - alarm.related = Components.interfaces.calIAlarm.ALARM_RELATED_ABSOLUTE; - alarm.alarmDate = UtcAlarmDate; - } - item.addAlarm(alarm); - } - - //status/percentage cannot be mapped - if (data.Complete) { - if (data.Complete == "0") { - item.isCompleted = false; - } else { - item.isCompleted = true; - if (data.DateCompleted) item.completedDate = eas.tools.createDateTime(data.DateCompleted); - } - } - }, - -/* - Regenerate: After complete, the completed task is removed from the series and stored as an new entry. The series starts an week (as set) after complete date with one less occurence - - */ - - - - - - - - // --------------------------------------------------------------------------- // - //read TB event and return its data as WBXML - // --------------------------------------------------------------------------- // - getWbxmlFromThunderbirdItem: async function (tbItem, syncdata) { - let item = tbItem instanceof TbSync.lightning.TbItem ? tbItem.nativeItem : tbItem; - - let asversion = syncdata.accountData.getAccountProperty("asversion"); - let wbxml = eas.wbxmltools.createWBXML("", syncdata.type); //init wbxml with "" and not with precodes, and set initial codepage - - //Order of tags taken from: https://msdn.microsoft.com/en-us/library/dn338924(v=exchg.80).aspx - - //Subject - wbxml.atag("Subject", (item.title) ? item.title : ""); - - //Body - wbxml.append(eas.sync.getItemBody(item, syncdata)); - - //Importance - wbxml.atag("Importance", eas.sync.mapThunderbirdPropertyToEas("PRIORITY", "Importance", item)); - - //tasks is using extended ISO 8601 (2019-01-18T00:00:00.000Z) instead of basic (20190118T000000Z), - //eas.tools.getIsoUtcString returns extended if true as second parameter is present - - // TB will enforce a StartDate if it has a recurrence - let localStartDate = null; - if (item.entryDate) { - wbxml.atag("UtcStartDate", eas.tools.getIsoUtcString(item.entryDate, true)); - //to fake the local time as UTC, getIsoUtcString needs the third parameter to be true - localStartDate = eas.tools.getIsoUtcString(item.entryDate, true, true); - wbxml.atag("StartDate", localStartDate); - } - - // Tasks without DueDate are breaking O365 - use StartDate as DueDate - if (item.entryDate || item.dueDate) { - wbxml.atag("UtcDueDate", eas.tools.getIsoUtcString(item.dueDate ? item.dueDate : item.entryDate, true)); - //to fake the local time as UTC, getIsoUtcString needs the third parameter to be true - wbxml.atag("DueDate", eas.tools.getIsoUtcString(item.dueDate ? item.dueDate : item.entryDate, true, true)); - } - - //Categories - wbxml.append(eas.sync.getItemCategories(item, syncdata)); - - //Recurrence (only if localStartDate has been set) - if (localStartDate) wbxml.append(await eas.sync.getItemRecurrence(item, syncdata, localStartDate)); - - //Complete - if (item.isCompleted) { - wbxml.atag("Complete", "1"); - wbxml.atag("DateCompleted", eas.tools.getIsoUtcString(item.completedDate, true)); - } else { - wbxml.atag("Complete", "0"); - } - - //Sensitivity - wbxml.atag("Sensitivity", eas.sync.mapThunderbirdPropertyToEas("CLASS", "Sensitivity", item)); - - //ReminderTime and ReminderSet - let alarms = item.getAlarms({}); - if (alarms.length>0 && (item.entryDate || item.dueDate)) { - let reminderTime; - if (alarms[0].offset) { - //create Date obj from entryDate by converting item.entryDate to an extended UTC ISO string, which can be parsed by Date - //if entryDate is missing, the startDate of this object is set to its dueDate - let UtcDate = new Date(eas.tools.getIsoUtcString(item.entryDate ? item.entryDate : item.dueDate, true)); - //add offset - UtcDate.setSeconds(UtcDate.getSeconds() + alarms[0].offset.inSeconds); - reminderTime = UtcDate.toISOString(); - } else { - reminderTime = eas.tools.getIsoUtcString(alarms[0].alarmDate, true); - } - wbxml.atag("ReminderTime", reminderTime); - wbxml.atag("ReminderSet", "1"); - } else { - wbxml.atag("ReminderSet", "0"); - } - - return wbxml.getBytes(); - }, -} +/* + * This file is part of EAS-4-TbSync. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +var { ExtensionParent } = ChromeUtils.importESModule( + "resource://gre/modules/ExtensionParent.sys.mjs" +); + +var tbsyncExtension = ExtensionParent.GlobalManager.getExtension( + "tbsync@jobisoft.de" +); +var { TbSync } = ChromeUtils.importESModule( + `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}` +); + +ChromeUtils.defineESModuleGetters(this, { + CalAlarm: "resource:///modules/CalAlarm.sys.mjs", + CalAttachment: "resource:///modules/CalAttachment.sys.mjs", + CalAttendee: "resource:///modules/CalAttendee.sys.mjs", + CalEvent: "resource:///modules/CalEvent.sys.mjs", + CalTodo: "resource:///modules/CalTodo.sys.mjs", +}); + +var Tasks = { + + // --------------------------------------------------------------------------- // + // Read WBXML and set Thunderbird item + // --------------------------------------------------------------------------- // + setThunderbirdItemFromWbxml: function (tbItem, data, id, syncdata, mode = "standard") { + + let item = tbItem instanceof TbSync.lightning.TbItem ? tbItem.nativeItem : tbItem; + + let asversion = syncdata.accountData.getAccountProperty("asversion"); + item.id = id; + eas.sync.setItemSubject(item, syncdata, data); + if (TbSync.prefs.getIntPref("log.userdatalevel") > 2) TbSync.dump("Processing " + mode + " task item", item.title + " (" + id + ")"); + + eas.sync.setItemBody(item, syncdata, data); + eas.sync.setItemCategories(item, syncdata, data); + eas.sync.setItemRecurrence(item, syncdata, data); + + let dueDate = null; + if (data.DueDate && data.UtcDueDate) { + //extract offset from EAS data + let DueDate = new Date(data.DueDate); + let UtcDueDate = new Date(data.UtcDueDate); + let offset = (UtcDueDate.getTime() - DueDate.getTime()) / 60000; + + //timezone is identified by its offset + let utc = cal.createDateTime(eas.tools.dateToBasicISOString(UtcDueDate)); //format "19800101T000000Z" - UTC + dueDate = utc.getInTimezone(eas.tools.guessTimezoneByCurrentOffset(offset, utc)); + item.dueDate = dueDate; + } + + if (data.StartDate && data.UtcStartDate) { + //extract offset from EAS data + let StartDate = new Date(data.StartDate); + let UtcStartDate = new Date(data.UtcStartDate); + let offset = (UtcStartDate.getTime() - StartDate.getTime()) / 60000; + + //timezone is identified by its offset + let utc = cal.createDateTime(eas.tools.dateToBasicISOString(UtcStartDate)); //format "19800101T000000Z" - UTC + item.entryDate = utc.getInTimezone(eas.tools.guessTimezoneByCurrentOffset(offset, utc)); + } else { + //there is no start date? if this is a recurring item, we MUST add an entryDate, otherwise Thunderbird will not display the recurring items + if (data.Recurrence) { + if (dueDate) { + item.entryDate = dueDate; + TbSync.eventlog.add("info", syncdata, "Copy task dueData to task startDate, because Thunderbird needs a startDate for recurring items.", item.icalString); + } else { + TbSync.eventlog.add("info", syncdata, "Task without startDate and without dueDate but with recurrence info is not supported by Thunderbird. Recurrence will be lost.", item.icalString); + } + } + } + + eas.sync.mapEasPropertyToThunderbird("Sensitivity", "CLASS", data, item); + eas.sync.mapEasPropertyToThunderbird("Importance", "PRIORITY", data, item); + + let msTodoCompat = eas.prefs.getBoolPref("msTodoCompat"); + + item.clearAlarms(); + if (data.ReminderSet && data.ReminderTime) { + let UtcAlarmDate = eas.tools.createDateTime(data.ReminderTime); + let alarm = new CalAlarm(); + alarm.action = "DISPLAY"; + + if (msTodoCompat) { + // Microsoft To-Do only uses due dates (no start dates) an doesn't have a time part in the due date + // dirty hack: Use the reminder date as due date and set a reminder exactly to the due date + // drawback: only works if due date and reminder is set to the same day - this could maybe checked here but I don't know how + item.entryDate = UtcAlarmDate; + item.dueDate = UtcAlarmDate; + alarm.related = Components.interfaces.calIAlarm.ALARM_RELATED_START; + alarm.offset = TbSync.lightning.cal.createDuration(); + alarm.offset.inSeconds = 0; + } + else if (data.UtcStartDate) { + let UtcDate = eas.tools.createDateTime(data.UtcStartDate); + alarm.related = Components.interfaces.calIAlarm.ALARM_RELATED_START; + alarm.offset = UtcAlarmDate.subtractDate(UtcDate); + } + else { + // Alternative solution for Microsoft To-Do: + // alarm correctly set but because time part of due date is always "0:00", all tasks for today are shown as overdue + alarm.related = Components.interfaces.calIAlarm.ALARM_RELATED_ABSOLUTE; + alarm.alarmDate = UtcAlarmDate; + } + item.addAlarm(alarm); + } + + //status/percentage cannot be mapped + if (data.Complete) { + if (data.Complete == "0") { + item.isCompleted = false; + } else { + item.isCompleted = true; + if (data.DateCompleted) item.completedDate = eas.tools.createDateTime(data.DateCompleted); + } + } + }, + + /* + Regenerate: After complete, the completed task is removed from the series and stored as an new entry. The series starts an week (as set) after complete date with one less occurence + + */ + + + + + + + + // --------------------------------------------------------------------------- // + //read TB event and return its data as WBXML + // --------------------------------------------------------------------------- // + getWbxmlFromThunderbirdItem: async function (tbItem, syncdata) { + let item = tbItem instanceof TbSync.lightning.TbItem ? tbItem.nativeItem : tbItem; + + let asversion = syncdata.accountData.getAccountProperty("asversion"); + let wbxml = eas.wbxmltools.createWBXML("", syncdata.type); //init wbxml with "" and not with precodes, and set initial codepage + + //Order of tags taken from: https://msdn.microsoft.com/en-us/library/dn338924(v=exchg.80).aspx + + //Subject + wbxml.atag("Subject", (item.title) ? item.title : ""); + + //Body + wbxml.append(eas.sync.getItemBody(item, syncdata)); + + //Importance + wbxml.atag("Importance", eas.sync.mapThunderbirdPropertyToEas("PRIORITY", "Importance", item)); + + //tasks is using extended ISO 8601 (2019-01-18T00:00:00.000Z) instead of basic (20190118T000000Z), + //eas.tools.getIsoUtcString returns extended if true as second parameter is present + + // TB will enforce a StartDate if it has a recurrence + let localStartDate = null; + if (item.entryDate) { + wbxml.atag("UtcStartDate", eas.tools.getIsoUtcString(item.entryDate, true)); + //to fake the local time as UTC, getIsoUtcString needs the third parameter to be true + localStartDate = eas.tools.getIsoUtcString(item.entryDate, true, true); + wbxml.atag("StartDate", localStartDate); + } + + // Tasks without DueDate are breaking O365 - use StartDate as DueDate + if (item.entryDate || item.dueDate) { + wbxml.atag("UtcDueDate", eas.tools.getIsoUtcString(item.dueDate ? item.dueDate : item.entryDate, true)); + //to fake the local time as UTC, getIsoUtcString needs the third parameter to be true + wbxml.atag("DueDate", eas.tools.getIsoUtcString(item.dueDate ? item.dueDate : item.entryDate, true, true)); + } + + //Categories + wbxml.append(eas.sync.getItemCategories(item, syncdata)); + + //Recurrence (only if localStartDate has been set) + if (localStartDate) wbxml.append(await eas.sync.getItemRecurrence(item, syncdata, localStartDate)); + + //Complete + if (item.isCompleted) { + wbxml.atag("Complete", "1"); + wbxml.atag("DateCompleted", eas.tools.getIsoUtcString(item.completedDate, true)); + } else { + wbxml.atag("Complete", "0"); + } + + //Sensitivity + wbxml.atag("Sensitivity", eas.sync.mapThunderbirdPropertyToEas("CLASS", "Sensitivity", item)); + + //ReminderTime and ReminderSet + let alarms = item.getAlarms({}); + if (alarms.length > 0 && (item.entryDate || item.dueDate)) { + let reminderTime; + if (alarms[0].offset) { + //create Date obj from entryDate by converting item.entryDate to an extended UTC ISO string, which can be parsed by Date + //if entryDate is missing, the startDate of this object is set to its dueDate + let UtcDate = new Date(eas.tools.getIsoUtcString(item.entryDate ? item.entryDate : item.dueDate, true)); + //add offset + UtcDate.setSeconds(UtcDate.getSeconds() + alarms[0].offset.inSeconds); + reminderTime = UtcDate.toISOString(); + } else { + reminderTime = eas.tools.getIsoUtcString(alarms[0].alarmDate, true); + } + wbxml.atag("ReminderTime", reminderTime); + wbxml.atag("ReminderSet", "1"); + } else { + wbxml.atag("ReminderSet", "0"); + } + + return wbxml.getBytes(); + }, +} diff -Nru eas4tbsync-4.11/content/includes/tools.js eas4tbsync-4.17/content/includes/tools.js --- eas4tbsync-4.11/content/includes/tools.js 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/content/includes/tools.js 2025-05-15 11:21:20.000000000 +0000 @@ -1,535 +1,548 @@ -/* - * This file is part of EAS-4-TbSync. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -"use strict"; - -var { TbSync } = ChromeUtils.import("chrome://tbsync/content/tbsync.jsm"); -var { MailServices } = ChromeUtils.import("resource:///modules/MailServices.jsm"); -var { NetUtil } = ChromeUtils.importESModule( - "resource://gre/modules/NetUtil.sys.mjs" -); - -var tools = { - - setCalItemProperty: function (item, prop, value) { - if (value == "unset") item.deleteProperty(prop); - else item.setProperty(prop, value); - }, - - getCalItemProperty: function (item, prop) { - if (item.hasProperty(prop)) return item.getProperty(prop); - else return "unset"; - }, - - isString: function (s) { - return (typeof s == 'string' || s instanceof String); - }, - - getIdentityKey: function (email) { - for (let account of MailServices.accounts.accounts) { - if (account.defaultIdentity && account.defaultIdentity.email == email) return account.defaultIdentity.key; - } - return ""; - }, - - parentIsTrash: function (folderData) { - let parentID = folderData.getFolderProperty("parentID"); - if (parentID == "0") return false; - - let parentFolder = folderData.accountData.getFolder("serverID", parentID); - if (parentFolder && parentFolder.getFolderProperty("type") == "4") return true; - - return false; - }, - - getNewDeviceId: function () { - //taken from https://jsfiddle.net/briguy37/2MVFd/ - let d = new Date().getTime(); - let uuid = 'xxxxxxxxxxxxxxxxyxxxxxxxxxxx'.replace(/[xy]/g, function(c) { - let r = (d + Math.random()*16)%16 | 0; - d = Math.floor(d/16); - return (c=='x' ? r : (r&0x3|0x8)).toString(16); - }); - return "MZTB" + uuid; - }, - - getUriFromDirectoryId: function(ownerId) { - let directories = MailServices.ab.directories; - for (let directory of directories) { - if (directory instanceof Components.interfaces.nsIAbDirectory) { - if (ownerId.startsWith(directory.dirPrefId)) return directory.URI; - } - } - return null; - }, - - //function to get correct uri of current card for global book as well for mailLists - getSelectedUri : function(aUri, aCard) { - if (aUri == "moz-abdirectory://?") { - //get parent via card owner - return eas.tools.getUriFromDirectoryId(aCard.directoryId); - } else if (MailServices.ab.getDirectory(aUri).isMailList) { - //MailList suck, we have to cut the url to get the parent - return aUri.substring(0, aUri.lastIndexOf("/")) - } else { - return aUri; - } - }, - - //read file from within the XPI package - fetchFile: function (aURL, returnType = "Array") { - return new Promise((resolve, reject) => { - let uri = Services.io.newURI(aURL); - let channel = Services.io.newChannelFromURI(uri, - null, - Services.scriptSecurityManager.getSystemPrincipal(), - null, - Components.interfaces.nsILoadInfo.SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT, - Components.interfaces.nsIContentPolicy.TYPE_OTHER); - - NetUtil.asyncFetch(channel, (inputStream, status) => { - if (!Components.isSuccessCode(status)) { - reject(status); - return; - } - - try { - let data = NetUtil.readInputStreamToString(inputStream, inputStream.available()); - if (returnType == "Array") { - resolve(data.replace("\r","").split("\n")) - } else { - resolve(data); - } - } catch (ex) { - reject(ex); - } - }); - }); - }, - - - - - - - - - - - // TIMEZONE STUFF - - TimeZoneDataStructure : class { - constructor() { - this.buf = new DataView(new ArrayBuffer(172)); - } - -/* - Buffer structure: - @000 utcOffset (4x8bit as 1xLONG) - - @004 standardName (64x8bit as 32xWCHAR) - @068 standardDate (16x8 as 1xSYSTEMTIME) - @084 standardBias (4x8bit as 1xLONG) - - @088 daylightName (64x8bit as 32xWCHAR) - @152 daylightDate (16x8 as 1xSTRUCT) - @168 daylightBias (4x8bit as 1xLONG) -*/ - - set easTimeZone64 (b64) { - //clear buffer - for (let i=0; i<172; i++) this.buf.setUint8(i, 0); - //load content into buffer - let content = (b64 == "") ? "" : atob(b64); - for (let i=0; i if found, does the stdOffset match? -> if so, done - 2. Try to parse our own format, split name and test each chunk for IANA -> if found, does the stdOffset match? -> if so, done - 3. Try if one of the chunks matches international code -> if found, does the stdOffset match? -> if so, done - 4. Fallback: Use just the offsets */ - - - //check for windows timezone name - if (eas.windowsToIanaTimezoneMap[stdName] && eas.cachedTimezoneData.iana[eas.windowsToIanaTimezoneMap[stdName]] && eas.cachedTimezoneData.iana[eas.windowsToIanaTimezoneMap[stdName]].std.offset == stdOffset ) { - //the windows timezone maps multiple IANA zones to one (Berlin*, Rome, Bruessel) - //check the windowsZoneName of the default TZ and of the winning, if they match, use default TZ - //so Rome could win, even Berlin is the default IANA zone - if (eas.defaultTimezoneInfo.std.windowsZoneName && eas.windowsToIanaTimezoneMap[stdName] != eas.defaultTimezoneInfo.std.id && eas.cachedTimezoneData.iana[eas.windowsToIanaTimezoneMap[stdName]].std.offset == eas.defaultTimezoneInfo.std.offset && stdName == eas.defaultTimezoneInfo.std.windowsZoneName) { - TbSync.dump("Timezone matched via windows timezone name ("+stdName+") with default TZ overtake", eas.windowsToIanaTimezoneMap[stdName] + " -> " + eas.defaultTimezoneInfo.std.id); - return eas.defaultTimezoneInfo.timezone; - } - - TbSync.dump("Timezone matched via windows timezone name ("+stdName+")", eas.windowsToIanaTimezoneMap[stdName]); - return eas.cachedTimezoneData.iana[eas.windowsToIanaTimezoneMap[stdName]].timezone; - } - - let parts = stdName.replace(/[;,()\[\]]/g," ").split(" "); - for (let i = 0; i < parts.length; i++) { - //check for IANA - if (eas.cachedTimezoneData.iana[parts[i]] && eas.cachedTimezoneData.iana[parts[i]].std.offset == stdOffset) { - TbSync.dump("Timezone matched via IANA", parts[i]); - return eas.cachedTimezoneData.iana[parts[i]].timezone; - } - - //check for international abbreviation for standard period (CET, CAT, ...) - if (eas.cachedTimezoneData.abbreviations[parts[i]] && eas.cachedTimezoneData.iana[eas.cachedTimezoneData.abbreviations[parts[i]]] && eas.cachedTimezoneData.iana[eas.cachedTimezoneData.abbreviations[parts[i]]].std.offset == stdOffset) { - TbSync.dump("Timezone matched via international abbreviation (" + parts[i] +")", eas.cachedTimezoneData.abbreviations[parts[i]]); - return eas.cachedTimezoneData.iana[eas.cachedTimezoneData.abbreviations[parts[i]]].timezone; - } - } - - //fallback to zone based on stdOffset and dstOffset, if we have that cached - if (eas.cachedTimezoneData.bothOffsets[stdOffset+":"+dstOffset]) { - TbSync.dump("Timezone matched via both offsets (std:" + stdOffset +", dst:" + dstOffset + ")", eas.cachedTimezoneData.bothOffsets[stdOffset+":"+dstOffset].tzid); - return eas.cachedTimezoneData.bothOffsets[stdOffset+":"+dstOffset]; - } - - //fallback to zone based on stdOffset only, if we have that cached - if (eas.cachedTimezoneData.stdOffset[stdOffset]) { - TbSync.dump("Timezone matched via std offset (" + stdOffset +")", eas.cachedTimezoneData.stdOffset[stdOffset].tzid); - return eas.cachedTimezoneData.stdOffset[stdOffset]; - } - - //return default timezone, if everything else fails - TbSync.dump("Timezone could not be matched via offsets (std:" + stdOffset +", dst:" + dstOffset + "), using default timezone", eas.defaultTimezoneInfo.std.id); - return eas.defaultTimezoneInfo.timezone; - }, - - - //extract standard and daylight timezone data - getTimezoneInfo: function (timezone) { - let tzInfo = {}; - - tzInfo.std = eas.tools.getTimezoneInfoObject(timezone, "standard"); - tzInfo.dst = eas.tools.getTimezoneInfoObject(timezone, "daylight"); - - if (tzInfo.dst === null) tzInfo.dst = tzInfo.std; - - tzInfo.timezone = timezone; - return tzInfo; - }, - - - //get timezone info for standard/daylight - getTimezoneInfoObject: function (timezone, standardOrDaylight) { - - //handle UTC - if (timezone.isUTC) { - let obj = {} - obj.id = "UTC"; - obj.offset = 0; - obj.abbreviation = "UTC"; - obj.displayname = "Coordinated Universal Time (UTC)"; - return obj; - } - - //we could parse the icalstring by ourself, but I wanted to use ICAL.parse - TODO try catch - let info = TbSync.lightning.ICAL.parse("BEGIN:VCALENDAR\r\n" + timezone.icalComponent.toString() + "\r\nEND:VCALENDAR"); - let comp = new TbSync.lightning.ICAL.Component(info); - let vtimezone =comp.getFirstSubcomponent("vtimezone"); - let id = vtimezone.getFirstPropertyValue("tzid").toString(); - let zone = vtimezone.getFirstSubcomponent(standardOrDaylight); - - if (zone) { - let obj = {}; - obj.id = id; - - //get offset - let utcOffset = zone.getFirstPropertyValue("tzoffsetto").toString(); - let o = parseInt(utcOffset.replace(":","")); //-330 = - 3h 30min - let h = Math.floor(o / 100); //-3 -> -180min - let m = o - (h*100) //-330 - -300 = -30 - obj.offset = -1*((h*60) + m); - - //get international abbreviation (CEST, CET, CAT ... ) - obj.abbreviation = ""; - try { - obj.abbreviation = zone.getFirstPropertyValue("tzname").toString(); - } catch(e) { - TbSync.dump("Failed TZ", timezone.icalComponent.toString()); - } - - //get displayname - obj.displayname = /*"("+utcOffset+") " +*/ obj.id;// + ", " + obj.abbreviation; - - //get DST switch date - let rrule = zone.getFirstPropertyValue("rrule"); - let dtstart = zone.getFirstPropertyValue("dtstart"); - if (rrule && dtstart) { - /* - - THE switchdate PART OF THE OBJECT IS MICROSOFT SPECIFIC, EVERYTHING ELSE IS THUNDERBIRD GENERIC, I LET IT SIT HERE ANYHOW - - https://msdn.microsoft.com/en-us/library/windows/desktop/ms725481(v=vs.85).aspx - - To select the correct day in the month, set the wYear member to zero, the wHour and wMinute members to - the transition time, the wDayOfWeek member to the appropriate weekday, and the wDay member to indicate - the occurrence of the day of the week within the month (1 to 5, where 5 indicates the final occurrence during the - month if that day of the week does not occur 5 times). - - Using this notation, specify 02:00 on the first Sunday in April as follows: - wHour = 2, wMonth = 4, wDayOfWeek = 0, wDay = 1. - Specify 02:00 on the last Thursday in October as follows: - wHour = 2, wMonth = 10, wDayOfWeek = 4, wDay = 5. - - So we have to parse the RRULE to exract wDay - RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10 */ - - let parts =rrule.toString().split(";"); - let rules = {}; - for (let i = 0; i< parts.length; i++) { - let sub = parts[i].split("="); - if (sub.length == 2) rules[sub[0]] = sub[1]; - } - - if (rules.FREQ == "YEARLY" && rules.BYDAY && rules.BYMONTH && rules.BYDAY.length > 2) { - obj.switchdate = {}; - obj.switchdate.month = parseInt(rules.BYMONTH); - - let days = ["SU","MO","TU","WE","TH","FR","SA"]; - obj.switchdate.dayOfWeek = days.indexOf(rules.BYDAY.substring(rules.BYDAY.length-2)); - obj.switchdate.weekOfMonth = parseInt(rules.BYDAY.substring(0, rules.BYDAY.length-2)); - if (obj.switchdate.weekOfMonth<0 || obj.switchdate.weekOfMonth>5) obj.switchdate.weekOfMonth = 5; - - //get switch time from dtstart - let dttime = eas.tools.createDateTime(dtstart.toString()); - obj.switchdate.hour = dttime.hour; - obj.switchdate.minute = dttime.minute; - obj.switchdate.second = dttime.second; - } - } - - return obj; - } - return null; - }, -} - -//TODO: Invites -/* - cal.itip.checkAndSendOrigial = cal.itip.checkAndSend; - cal.itip.checkAndSend = function(aOpType, aItem, aOriginalItem) { - //if this item is added_by_user, do not call checkAndSend yet, because the UID is wrong, we need to sync first to get the correct ID - TODO - TbSync.dump("cal.checkAndSend", aOpType); - cal.itip.checkAndSendOrigial(aOpType, aItem, aOriginalItem); - } -*/ +/* + * This file is part of EAS-4-TbSync. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +var { ExtensionParent } = ChromeUtils.importESModule( + "resource://gre/modules/ExtensionParent.sys.mjs" +); +var { MailServices } = ChromeUtils.importESModule( + "resource:///modules/MailServices.sys.mjs" +); +var { NetUtil } = ChromeUtils.importESModule( + "resource://gre/modules/NetUtil.sys.mjs" +); + +var tbsyncExtension = ExtensionParent.GlobalManager.getExtension( + "tbsync@jobisoft.de" +); +var { TbSync } = ChromeUtils.importESModule( + `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}` +); + +var tools = { + + setCalItemProperty: function (item, prop, value) { + if (value == "unset") item.deleteProperty(prop); + else item.setProperty(prop, value); + }, + + getCalItemProperty: function (item, prop) { + if (item.hasProperty(prop)) return item.getProperty(prop); + else return "unset"; + }, + + isString: function (s) { + return (typeof s == 'string' || s instanceof String); + }, + + getIdentityKey: function (email) { + for (let account of MailServices.accounts.accounts) { + if (account.defaultIdentity && account.defaultIdentity.email == email) return account.defaultIdentity.key; + } + return ""; + }, + + parentIsTrash: function (folderData) { + let parentID = folderData.getFolderProperty("parentID"); + if (parentID == "0") return false; + + let parentFolder = folderData.accountData.getFolder("serverID", parentID); + if (parentFolder && parentFolder.getFolderProperty("type") == "4") return true; + + return false; + }, + + getNewDeviceId: function () { + //taken from https://jsfiddle.net/briguy37/2MVFd/ + let d = new Date().getTime(); + let uuid = 'xxxxxxxxxxxxxxxxyxxxxxxxxxxx'.replace(/[xy]/g, function (c) { + let r = (d + Math.random() * 16) % 16 | 0; + d = Math.floor(d / 16); + return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16); + }); + return "MZTB" + uuid; + }, + + getUriFromDirectoryId: function (ownerId) { + let directories = MailServices.ab.directories; + for (let directory of directories) { + if (directory instanceof Components.interfaces.nsIAbDirectory) { + if (ownerId.startsWith(directory.dirPrefId)) return directory.URI; + } + } + return null; + }, + + //function to get correct uri of current card for global book as well for mailLists + getSelectedUri: function (aUri, aCard) { + if (aUri == "moz-abdirectory://?") { + //get parent via card owner + return eas.tools.getUriFromDirectoryId(aCard.directoryId); + } else if (MailServices.ab.getDirectory(aUri).isMailList) { + //MailList suck, we have to cut the url to get the parent + return aUri.substring(0, aUri.lastIndexOf("/")) + } else { + return aUri; + } + }, + + //read file from within the XPI package + fetchFile: function (aURL, returnType = "Array") { + return new Promise((resolve, reject) => { + let uri = Services.io.newURI(aURL); + let channel = Services.io.newChannelFromURI(uri, + null, + Services.scriptSecurityManager.getSystemPrincipal(), + null, + Components.interfaces.nsILoadInfo.SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT, + Components.interfaces.nsIContentPolicy.TYPE_OTHER); + + NetUtil.asyncFetch(channel, (inputStream, status) => { + if (!Components.isSuccessCode(status)) { + reject(status); + return; + } + + try { + let data = NetUtil.readInputStreamToString(inputStream, inputStream.available()); + if (returnType == "Array") { + resolve(data.replace("\r", "").split("\n")) + } else { + resolve(data); + } + } catch (ex) { + reject(ex); + } + }); + }); + }, + + + + + + + + + + + // TIMEZONE STUFF + + TimeZoneDataStructure: class { + constructor() { + this.buf = new DataView(new ArrayBuffer(172)); + } + + /* + Buffer structure: + @000 utcOffset (4x8bit as 1xLONG) + + @004 standardName (64x8bit as 32xWCHAR) + @068 standardDate (16x8 as 1xSYSTEMTIME) + @084 standardBias (4x8bit as 1xLONG) + + @088 daylightName (64x8bit as 32xWCHAR) + @152 daylightDate (16x8 as 1xSTRUCT) + @168 daylightBias (4x8bit as 1xLONG) + */ + + set easTimeZone64(b64) { + //clear buffer + for (let i = 0; i < 172; i++) this.buf.setUint8(i, 0); + //load content into buffer + let content = (b64 == "") ? "" : atob(b64); + for (let i = 0; i < content.length; i++) this.buf.setUint8(i, content.charCodeAt(i)); + } + + get easTimeZone64() { + let content = ""; + for (let i = 0; i < 172; i++) content += String.fromCharCode(this.buf.getUint8(i)); + return (btoa(content)); + } + + getstr(byteoffset) { + let str = ""; + //walk thru the buffer in 32 steps of 16bit (wchars) + for (let i = 0; i < 32; i++) { + let cc = this.buf.getUint16(byteoffset + i * 2, true); + if (cc == 0) break; + str += String.fromCharCode(cc); + } + return str; + } + + setstr(byteoffset, str) { + //clear first + for (let i = 0; i < 32; i++) this.buf.setUint16(byteoffset + i * 2, 0); + //walk thru the buffer in steps of 16bit (wchars) + for (let i = 0; i < str.length && i < 32; i++) this.buf.setUint16(byteoffset + i * 2, str.charCodeAt(i), true); + } + + getsystemtime(buf, offset) { + let systemtime = { + get wYear() { return buf.getUint16(offset + 0, true); }, + get wMonth() { return buf.getUint16(offset + 2, true); }, + get wDayOfWeek() { return buf.getUint16(offset + 4, true); }, + get wDay() { return buf.getUint16(offset + 6, true); }, + get wHour() { return buf.getUint16(offset + 8, true); }, + get wMinute() { return buf.getUint16(offset + 10, true); }, + get wSecond() { return buf.getUint16(offset + 12, true); }, + get wMilliseconds() { return buf.getUint16(offset + 14, true); }, + toString() { return [this.wYear, this.wMonth, this.wDay].join("-") + ", " + this.wDayOfWeek + ", " + [this.wHour, this.wMinute, this.wSecond].join(":") + "." + this.wMilliseconds }, + + set wYear(v) { buf.setUint16(offset + 0, v, true); }, + set wMonth(v) { buf.setUint16(offset + 2, v, true); }, + set wDayOfWeek(v) { buf.setUint16(offset + 4, v, true); }, + set wDay(v) { buf.setUint16(offset + 6, v, true); }, + set wHour(v) { buf.setUint16(offset + 8, v, true); }, + set wMinute(v) { buf.setUint16(offset + 10, v, true); }, + set wSecond(v) { buf.setUint16(offset + 12, v, true); }, + set wMilliseconds(v) { buf.setUint16(offset + 14, v, true); }, + }; + return systemtime; + } + + get standardDate() { return this.getsystemtime(this.buf, 68); } + get daylightDate() { return this.getsystemtime(this.buf, 152); } + + get utcOffset() { return this.buf.getInt32(0, true); } + set utcOffset(v) { this.buf.setInt32(0, v, true); } + + get standardBias() { return this.buf.getInt32(84, true); } + set standardBias(v) { this.buf.setInt32(84, v, true); } + get daylightBias() { return this.buf.getInt32(168, true); } + set daylightBias(v) { this.buf.setInt32(168, v, true); } + + get standardName() { return this.getstr(4); } + set standardName(v) { return this.setstr(4, v); } + get daylightName() { return this.getstr(88); } + set daylightName(v) { return this.setstr(88, v); } + + toString() { + return ["", + "utcOffset: " + this.utcOffset, + "standardName: " + this.standardName, + "standardDate: " + this.standardDate.toString(), + "standardBias: " + this.standardBias, + "daylightName: " + this.daylightName, + "daylightDate: " + this.daylightDate.toString(), + "daylightBias: " + this.daylightBias].join("\n"); + } + }, + + + //Date has a toISOString method, which returns the Date obj as extended ISO 8601, + //however EAS MS-ASCAL uses compact/basic ISO 8601, + dateToBasicISOString: function (date) { + function pad(number) { + if (number < 10) { + return '0' + number; + } + return number.toString(); + } + + return pad(date.getUTCFullYear()) + + pad(date.getUTCMonth() + 1) + + pad(date.getUTCDate()) + + 'T' + + pad(date.getUTCHours()) + + pad(date.getUTCMinutes()) + + pad(date.getUTCSeconds()) + + 'Z'; + }, + + + //Save replacement for cal.createDateTime, which accepts compact/basic and also extended ISO 8601, + //cal.createDateTime only supports compact/basic + createDateTime: function (str) { + let datestring = str; + if (str.indexOf("-") == 4) { + //this looks like extended ISO 8601 + let tempDate = new Date(str); + datestring = eas.tools.dateToBasicISOString(tempDate); + } + return TbSync.lightning.cal.createDateTime(datestring); + }, + + + // Convert TB date to UTC and return it as basic or extended ISO 8601 String + getIsoUtcString: function (origdate, requireExtendedISO = false, fakeUTC = false) { + let date = origdate.clone(); + //floating timezone cannot be converted to UTC (cause they float) - we have to overwrite it with the local timezone + if (date.timezone.tzid == "floating") date.timezone = eas.defaultTimezoneInfo.timezone; + //to get the UTC string we could use icalString (which does not work on allDayEvents, or calculate it from nativeTime) + date.isDate = 0; + let UTC = date.getInTimezone(eas.utcTimezone); + if (fakeUTC) UTC = date.clone(); + + function pad(number) { + if (number < 10) { + return '0' + number; + } + return number; + } + + if (requireExtendedISO) { + return UTC.year + + "-" + pad(UTC.month + 1) + + "-" + pad(UTC.day) + + "T" + pad(UTC.hour) + + ":" + pad(UTC.minute) + + ":" + pad(UTC.second) + + "." + "000" + + "Z"; + } else { + return UTC.icalString; + } + }, + + getNowUTC: function () { + return TbSync.lightning.cal.dtz.jsDateToDateTime(new Date()).getInTimezone(TbSync.lightning.cal.dtz.UTC); + }, + + //guess the IANA timezone (used by TB) based on the current offset (standard or daylight) + guessTimezoneByCurrentOffset: function (curOffset, utcDateTime) { + //if we only now the current offset and the current date, we need to actually try each TZ. + let tzService = TbSync.lightning.cal.timezoneService; + + //first try default tz + let test = utcDateTime.getInTimezone(eas.defaultTimezoneInfo.timezone); + TbSync.dump("Matching TZ via current offset: " + test.timezone.tzid + " @ " + curOffset, test.timezoneOffset / -60); + if (test.timezoneOffset / -60 == curOffset) return test.timezone; + + //second try UTC + test = utcDateTime.getInTimezone(eas.utcTimezone); + TbSync.dump("Matching TZ via current offset: " + test.timezone.tzid + " @ " + curOffset, test.timezoneOffset / -60); + if (test.timezoneOffset / -60 == curOffset) return test.timezone; + + //third try all others + for (let timezoneId of tzService.timezoneIds) { + let test = utcDateTime.getInTimezone(tzService.getTimezone(timezoneId)); + TbSync.dump("Matching TZ via current offset: " + test.timezone.tzid + " @ " + curOffset, test.timezoneOffset / -60); + if (test.timezoneOffset / -60 == curOffset) return test.timezone; + } + + //return default TZ as fallback + return eas.defaultTimezoneInfo.timezone; + }, + + + //guess the IANA timezone (used by TB) based on stdandard offset, daylight offset and standard name + guessTimezoneByStdDstOffset: function (stdOffset, dstOffset, stdName = "") { + + //get a list of all zones + //alternativly use cal.fromRFC3339 - but this is only doing this: + //https://dxr.mozilla.org/comm-central/source/calendar/base/modules/calProviderUtils.sys.mjs + + //cache timezone data on first attempt + if (eas.cachedTimezoneData === null) { + eas.cachedTimezoneData = {}; + eas.cachedTimezoneData.iana = {}; + eas.cachedTimezoneData.abbreviations = {}; + eas.cachedTimezoneData.stdOffset = {}; + eas.cachedTimezoneData.bothOffsets = {}; + + let tzService = TbSync.lightning.cal.timezoneService; + + //cache timezones data from internal IANA data + for (let timezoneId of tzService.timezoneIds) { + let timezone = tzService.getTimezone(timezoneId); + let tzInfo = eas.tools.getTimezoneInfo(timezone); + + eas.cachedTimezoneData.bothOffsets[tzInfo.std.offset + ":" + tzInfo.dst.offset] = timezone; + eas.cachedTimezoneData.stdOffset[tzInfo.std.offset] = timezone; + + eas.cachedTimezoneData.abbreviations[tzInfo.std.abbreviation] = timezoneId; + eas.cachedTimezoneData.iana[timezoneId] = tzInfo; + + //TbSync.dump("TZ ("+ tzInfo.std.id + " :: " + tzInfo.dst.id + " :: " + tzInfo.std.displayname + " :: " + tzInfo.dst.displayname + " :: " + tzInfo.std.offset + " :: " + tzInfo.dst.offset + ")", tzService.getTimezone(id)); + } + + //make sure, that UTC timezone is there + eas.cachedTimezoneData.bothOffsets["0:0"] = eas.utcTimezone; + + //multiple TZ share the same offset and abbreviation, make sure the default timezone is present + eas.cachedTimezoneData.abbreviations[eas.defaultTimezoneInfo.std.abbreviation] = eas.defaultTimezoneInfo.std.id; + eas.cachedTimezoneData.bothOffsets[eas.defaultTimezoneInfo.std.offset + ":" + eas.defaultTimezoneInfo.dst.offset] = eas.defaultTimezoneInfo.timezone; + eas.cachedTimezoneData.stdOffset[eas.defaultTimezoneInfo.std.offset] = eas.defaultTimezoneInfo.timezone; + + } + + /* + 1. Try to find name in Windows names and map to IANA -> if found, does the stdOffset match? -> if so, done + 2. Try to parse our own format, split name and test each chunk for IANA -> if found, does the stdOffset match? -> if so, done + 3. Try if one of the chunks matches international code -> if found, does the stdOffset match? -> if so, done + 4. Fallback: Use just the offsets */ + + + //check for windows timezone name + if (eas.windowsToIanaTimezoneMap[stdName] && eas.cachedTimezoneData.iana[eas.windowsToIanaTimezoneMap[stdName]] && eas.cachedTimezoneData.iana[eas.windowsToIanaTimezoneMap[stdName]].std.offset == stdOffset) { + //the windows timezone maps multiple IANA zones to one (Berlin*, Rome, Bruessel) + //check the windowsZoneName of the default TZ and of the winning, if they match, use default TZ + //so Rome could win, even Berlin is the default IANA zone + if (eas.defaultTimezoneInfo.std.windowsZoneName && eas.windowsToIanaTimezoneMap[stdName] != eas.defaultTimezoneInfo.std.id && eas.cachedTimezoneData.iana[eas.windowsToIanaTimezoneMap[stdName]].std.offset == eas.defaultTimezoneInfo.std.offset && stdName == eas.defaultTimezoneInfo.std.windowsZoneName) { + TbSync.dump("Timezone matched via windows timezone name (" + stdName + ") with default TZ overtake", eas.windowsToIanaTimezoneMap[stdName] + " -> " + eas.defaultTimezoneInfo.std.id); + return eas.defaultTimezoneInfo.timezone; + } + + TbSync.dump("Timezone matched via windows timezone name (" + stdName + ")", eas.windowsToIanaTimezoneMap[stdName]); + return eas.cachedTimezoneData.iana[eas.windowsToIanaTimezoneMap[stdName]].timezone; + } + + let parts = stdName.replace(/[;,()\[\]]/g, " ").split(" "); + for (let i = 0; i < parts.length; i++) { + //check for IANA + if (eas.cachedTimezoneData.iana[parts[i]] && eas.cachedTimezoneData.iana[parts[i]].std.offset == stdOffset) { + TbSync.dump("Timezone matched via IANA", parts[i]); + return eas.cachedTimezoneData.iana[parts[i]].timezone; + } + + //check for international abbreviation for standard period (CET, CAT, ...) + if (eas.cachedTimezoneData.abbreviations[parts[i]] && eas.cachedTimezoneData.iana[eas.cachedTimezoneData.abbreviations[parts[i]]] && eas.cachedTimezoneData.iana[eas.cachedTimezoneData.abbreviations[parts[i]]].std.offset == stdOffset) { + TbSync.dump("Timezone matched via international abbreviation (" + parts[i] + ")", eas.cachedTimezoneData.abbreviations[parts[i]]); + return eas.cachedTimezoneData.iana[eas.cachedTimezoneData.abbreviations[parts[i]]].timezone; + } + } + + //fallback to zone based on stdOffset and dstOffset, if we have that cached + if (eas.cachedTimezoneData.bothOffsets[stdOffset + ":" + dstOffset]) { + TbSync.dump("Timezone matched via both offsets (std:" + stdOffset + ", dst:" + dstOffset + ")", eas.cachedTimezoneData.bothOffsets[stdOffset + ":" + dstOffset].tzid); + return eas.cachedTimezoneData.bothOffsets[stdOffset + ":" + dstOffset]; + } + + //fallback to zone based on stdOffset only, if we have that cached + if (eas.cachedTimezoneData.stdOffset[stdOffset]) { + TbSync.dump("Timezone matched via std offset (" + stdOffset + ")", eas.cachedTimezoneData.stdOffset[stdOffset].tzid); + return eas.cachedTimezoneData.stdOffset[stdOffset]; + } + + //return default timezone, if everything else fails + TbSync.dump("Timezone could not be matched via offsets (std:" + stdOffset + ", dst:" + dstOffset + "), using default timezone", eas.defaultTimezoneInfo.std.id); + return eas.defaultTimezoneInfo.timezone; + }, + + + //extract standard and daylight timezone data + getTimezoneInfo: function (timezone) { + let tzInfo = {}; + + tzInfo.std = eas.tools.getTimezoneInfoObject(timezone, "standard"); + tzInfo.dst = eas.tools.getTimezoneInfoObject(timezone, "daylight"); + + if (tzInfo.dst === null) tzInfo.dst = tzInfo.std; + + tzInfo.timezone = timezone; + return tzInfo; + }, + + + //get timezone info for standard/daylight + getTimezoneInfoObject: function (timezone, standardOrDaylight) { + + //handle UTC + if (timezone.isUTC) { + let obj = {} + obj.id = "UTC"; + obj.offset = 0; + obj.abbreviation = "UTC"; + obj.displayname = "Coordinated Universal Time (UTC)"; + return obj; + } + + //we could parse the icalstring by ourself, but I wanted to use ICAL.parse - TODO try catch + let info = TbSync.lightning.ICAL.parse("BEGIN:VCALENDAR\r\n" + timezone.icalComponent.toString() + "\r\nEND:VCALENDAR"); + let comp = new TbSync.lightning.ICAL.Component(info); + let vtimezone = comp.getFirstSubcomponent("vtimezone"); + let id = vtimezone.getFirstPropertyValue("tzid").toString(); + let zone = vtimezone.getFirstSubcomponent(standardOrDaylight); + + if (zone) { + let obj = {}; + obj.id = id; + + //get offset + let utcOffset = zone.getFirstPropertyValue("tzoffsetto").toString(); + let o = parseInt(utcOffset.replace(":", "")); //-330 = - 3h 30min + let h = Math.floor(o / 100); //-3 -> -180min + let m = o - (h * 100) //-330 - -300 = -30 + obj.offset = -1 * ((h * 60) + m); + + //get international abbreviation (CEST, CET, CAT ... ) + obj.abbreviation = ""; + try { + obj.abbreviation = zone.getFirstPropertyValue("tzname").toString(); + } catch (e) { + TbSync.dump("Failed TZ", timezone.icalComponent.toString()); + } + + //get displayname + obj.displayname = /*"("+utcOffset+") " +*/ obj.id;// + ", " + obj.abbreviation; + + //get DST switch date + let rrule = zone.getFirstPropertyValue("rrule"); + let dtstart = zone.getFirstPropertyValue("dtstart"); + if (rrule && dtstart) { + /* + + THE switchdate PART OF THE OBJECT IS MICROSOFT SPECIFIC, EVERYTHING ELSE IS THUNDERBIRD GENERIC, I LET IT SIT HERE ANYHOW + + https://msdn.microsoft.com/en-us/library/windows/desktop/ms725481(v=vs.85).aspx + + To select the correct day in the month, set the wYear member to zero, the wHour and wMinute members to + the transition time, the wDayOfWeek member to the appropriate weekday, and the wDay member to indicate + the occurrence of the day of the week within the month (1 to 5, where 5 indicates the final occurrence during the + month if that day of the week does not occur 5 times). + + Using this notation, specify 02:00 on the first Sunday in April as follows: + wHour = 2, wMonth = 4, wDayOfWeek = 0, wDay = 1. + Specify 02:00 on the last Thursday in October as follows: + wHour = 2, wMonth = 10, wDayOfWeek = 4, wDay = 5. + + So we have to parse the RRULE to exract wDay + RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10 */ + + let parts = rrule.toString().split(";"); + let rules = {}; + for (let i = 0; i < parts.length; i++) { + let sub = parts[i].split("="); + if (sub.length == 2) rules[sub[0]] = sub[1]; + } + + if (rules.FREQ == "YEARLY" && rules.BYDAY && rules.BYMONTH && rules.BYDAY.length > 2) { + obj.switchdate = {}; + obj.switchdate.month = parseInt(rules.BYMONTH); + + let days = ["SU", "MO", "TU", "WE", "TH", "FR", "SA"]; + obj.switchdate.dayOfWeek = days.indexOf(rules.BYDAY.substring(rules.BYDAY.length - 2)); + obj.switchdate.weekOfMonth = parseInt(rules.BYDAY.substring(0, rules.BYDAY.length - 2)); + if (obj.switchdate.weekOfMonth < 0 || obj.switchdate.weekOfMonth > 5) obj.switchdate.weekOfMonth = 5; + + //get switch time from dtstart + let dttime = eas.tools.createDateTime(dtstart.toString()); + obj.switchdate.hour = dttime.hour; + obj.switchdate.minute = dttime.minute; + obj.switchdate.second = dttime.second; + } + } + + return obj; + } + return null; + }, +} + +//TODO: Invites +/* + cal.itip.checkAndSendOrigial = cal.itip.checkAndSend; + cal.itip.checkAndSend = function(aOpType, aItem, aOriginalItem) { + //if this item is added_by_user, do not call checkAndSend yet, because the UID is wrong, we need to sync first to get the correct ID - TODO + TbSync.dump("cal.checkAndSend", aOpType); + cal.itip.checkAndSendOrigial(aOpType, aItem, aOriginalItem); + } +*/ diff -Nru eas4tbsync-4.11/content/includes/wbxmltools.js eas4tbsync-4.17/content/includes/wbxmltools.js --- eas4tbsync-4.11/content/includes/wbxmltools.js 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/content/includes/wbxmltools.js 2025-05-15 11:21:20.000000000 +0000 @@ -1,878 +1,888 @@ -/* - * This file is part of EAS-4-TbSync. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -"use strict"; - -var { TbSync } = ChromeUtils.import("chrome://tbsync/content/tbsync.jsm"); -var wbxmltools = { - - // Convert a WBXML (WAP Binary XML) to plain XML - returns save xml with all special chars in the user data encoded by encodeURIComponent - convert2xml: function (wbxml) { - - let num = 4; //skip the 4 first bytes which are mostly 0x03 (WBXML Version 1.3), 0x01 (unknown public identifier), 0x6A (utf-8), 0x00 (Length of string table) - - //the main code page will be set to the the first codepage used - let mainCodePage = null; - - let tagStack = []; - let xml = ""; - let codepage = 0; - - while (num < wbxml.length) { - let data = wbxml.substr(num, 1).charCodeAt(0); - let token = data & 0x3F; //removes content bit(6) and attribute bit(7) - let tokenHasContent = ((data & 0x40) != 0); //checks if content bit is set - let tokenHasAttributes = ((data & 0x80) != 0); //checks if attribute bit is set - - switch(token) { - case 0x00: // switch of codepage (new codepage is next byte) - num = num + 1; - codepage = (wbxml.substr(num, 1)).charCodeAt(0) & 0xFF; - break; - - case 0x01: // Indicates the end of an attribute list or the end of an element - // tagStack contains a list of opened tags, which await to be closed - xml = xml + tagStack.pop(); - break; - - case 0x02: // A character entity. Followed by a mb_u_int32 encoding the character entity number. - TbSync.dump("wbxml", "Encoded character entity has not yet been implemented. Sorry."); - return false; - break; - - case 0x03: // Inline string followed by a termstr. (0x00) - let termpos = wbxml.indexOf(String.fromCharCode(0x00), num); - //encode all special chars in the user data by encodeURIComponent which does not encode the apostrophe, so we need to do that by hand - xml = xml + encodeURIComponent(wbxml.substring(num + 1, termpos)).replace(/'/g, "%27"); - num = termpos; - break; - - case 0x04: // An unknown tag or attribute name. Followed by an mb_u_int32 that encodes an offset into the string table. - case 0x40: // Inline string document-type-specific extension token. Token is followed by a termstr. - case 0x41: // Inline string document-type-specific extension token. Token is followed by a termstr. - case 0x42: // Inline string document-type-specific extension token. Token is followed by a termstr. - case 0x43: // Processing instruction. - case 0x44: // Unknown tag, with content. - case 0x80: // Inline integer document-type-specific extension token. Token is followed by a mb_uint_32. - case 0x81: // Inline integer document-type-specific extension token. Token is followed by a mb_uint_32. - case 0x82: // Inline integer document-type-specific extension token. Token is followed by a mb_uint_32. - case 0x83: // String table reference. Followed by a mb_u_int32 encoding a byte offset from the beginning of the string table. - case 0x84: // Unknown tag, with attributes. - case 0xC0: // Single-byte document-type-specific extension token. - case 0xC1: // Single-byte document-type-specific extension token. - case 0xC2: // Single-byte document-type-specific extension token. - case 0xC3: // Opaque document-type-specific data. - case 0xC4: // Unknown tag, with content and attributes. - TbSync.dump("wbxml", "Global token <" + token + "> has not yet been implemented. Sorry."); - return false; - break; - - default: - // if this code page is not the mainCodePage (or mainCodePage is not yet set = very first tag), add codePageTag with current codepage - let codePageTag = (codepage != mainCodePage) ? " xmlns='" + this.getNamespace(codepage) + "'" : ""; - - // if no mainCodePage has been defined yet, use the current codepage, which is either the initialized/default value of codepage or a value set by SWITCH_PAGE - if (mainCodePage === null) mainCodePage = codepage; - - if (!tokenHasContent) { - xml = xml + "<" + this. getCodepageToken(codepage, token) + codePageTag + "/>"; - } else { - xml = xml + "<" +this. getCodepageToken(codepage, token) + codePageTag +">"; - //add the closing tag to the stack, so it can get properly closed later - tagStack.push(""); - } - - if (this.isUnknownToken(codepage, token)) { - TbSync.eventlog.add("warning", null, "WBXML: Unknown token <" + token + "> for codepage <"+codepage+">."); - } - } - num = num + 1; - } - return (xml == "") ? "" : '' + xml; - }, - - isUnknownToken: function (codepage, token) { - if (this.codepages[codepage] && token in this.codepages[codepage]) return false; - else return true; - }, - - getNamespace: function (codepage) { - return (this.namespaces[codepage]) ? this.namespaces[codepage] : "UnknownCodePage" + codepage ; - }, - - getCodepageToken: function (codepage, token) { - return this.isUnknownToken(codepage, token) ? "Unknown." + codepage + "." + token : this.codepages[codepage][token]; - }, - - // This returns a wbxml object, which allows to add tags (using names), switch codepages, or open and close tags, it is also possible to append pure (binary) wbxml - // If no wbxmlstring is present, default to the "init" string ( WBXML Version 1.3, unknown public identifier, UTF-8, Length of string table) - createWBXML: function (wbxmlstring = String.fromCharCode(0x03, 0x01, 0x6A, 0x00), initialCodepage = "") { - let wbxml = { - _codepage : 0, - _wbxml : wbxmlstring, - - append : function (wbxmlstring) { - this._wbxml = this._wbxml + wbxmlstring; - }, - - // adding a string content tag as contentstring - atag : function (tokenname, content = "") { - //check if tokenname is in current codepage - if ((this._codepage in wbxmltools.codepages2) == false) throw "[wbxmltools] Unknown codepage <"+this._codepage+">"; - if ((tokenname in wbxmltools.codepages2[this._codepage]) == false) throw "[wbxmltools] Unknown tokenname <"+tokenname+"> for codepage <"+wbxmltools.namespaces[this._codepage]+">"; - - if (content == "") { - //empty, just add token - this._wbxml += String.fromCharCode(wbxmltools.codepages2[this._codepage][tokenname]); - } else { - //not empty,add token with enabled content bit and also add inlinestringidentifier - this._wbxml += String.fromCharCode(wbxmltools.codepages2[this._codepage][tokenname] | 0x40, 0x03); - //add content - for (let i=0; i< content.length; i++) this._wbxml += String.fromCharCode(content.charCodeAt(i)); - //add string termination and tag close - this._wbxml += String.fromCharCode(0x00, 0x01); - } - }, - - switchpage : function (name) { - let codepage = wbxmltools.namespaces.indexOf(name); - if (codepage == -1) throw "[wbxmltools] Unknown codepage <"+ name +">"; - this._codepage = codepage; - this._wbxml += String.fromCharCode(0x00, codepage); - }, - - ctag : function () { - this._wbxml += String.fromCharCode(0x01); - }, - - //opentag is assumed to add a token with content, otherwise use addtag - otag : function (tokenname) { - this._wbxml += String.fromCharCode(wbxmltools.codepages2[this._codepage][tokenname] | 0x40); - }, - - getCharCodes : function () { - let value = ""; - for (let i=0; i has not yet been implemented. Sorry."); + return false; + break; + + default: + // if this code page is not the mainCodePage (or mainCodePage is not yet set = very first tag), add codePageTag with current codepage + let codePageTag = (codepage != mainCodePage) ? " xmlns='" + this.getNamespace(codepage) + "'" : ""; + + // if no mainCodePage has been defined yet, use the current codepage, which is either the initialized/default value of codepage or a value set by SWITCH_PAGE + if (mainCodePage === null) mainCodePage = codepage; + + if (!tokenHasContent) { + xml = xml + "<" + this.getCodepageToken(codepage, token) + codePageTag + "/>"; + } else { + xml = xml + "<" + this.getCodepageToken(codepage, token) + codePageTag + ">"; + //add the closing tag to the stack, so it can get properly closed later + tagStack.push(""); + } + + if (this.isUnknownToken(codepage, token)) { + TbSync.eventlog.add("warning", null, "WBXML: Unknown token <" + token + "> for codepage <" + codepage + ">."); + } + } + num = num + 1; + } + return (xml == "") ? "" : '' + xml; + }, + + isUnknownToken: function (codepage, token) { + if (this.codepages[codepage] && token in this.codepages[codepage]) return false; + else return true; + }, + + getNamespace: function (codepage) { + return (this.namespaces[codepage]) ? this.namespaces[codepage] : "UnknownCodePage" + codepage; + }, + + getCodepageToken: function (codepage, token) { + return this.isUnknownToken(codepage, token) ? "Unknown." + codepage + "." + token : this.codepages[codepage][token]; + }, + + // This returns a wbxml object, which allows to add tags (using names), switch codepages, or open and close tags, it is also possible to append pure (binary) wbxml + // If no wbxmlstring is present, default to the "init" string ( WBXML Version 1.3, unknown public identifier, UTF-8, Length of string table) + createWBXML: function (wbxmlstring = String.fromCharCode(0x03, 0x01, 0x6A, 0x00), initialCodepage = "") { + let wbxml = { + _codepage: 0, + _wbxml: wbxmlstring, + + append: function (wbxmlstring) { + this._wbxml = this._wbxml + wbxmlstring; + }, + + // adding a string content tag as contentstring + atag: function (tokenname, content = "") { + //check if tokenname is in current codepage + if ((this._codepage in wbxmltools.codepages2) == false) throw "[wbxmltools] Unknown codepage <" + this._codepage + ">"; + if ((tokenname in wbxmltools.codepages2[this._codepage]) == false) throw "[wbxmltools] Unknown tokenname <" + tokenname + "> for codepage <" + wbxmltools.namespaces[this._codepage] + ">"; + + if (content == "") { + //empty, just add token + this._wbxml += String.fromCharCode(wbxmltools.codepages2[this._codepage][tokenname]); + } else { + //not empty,add token with enabled content bit and also add inlinestringidentifier + this._wbxml += String.fromCharCode(wbxmltools.codepages2[this._codepage][tokenname] | 0x40, 0x03); + //add content + for (let i = 0; i < content.length; i++) this._wbxml += String.fromCharCode(content.charCodeAt(i)); + //add string termination and tag close + this._wbxml += String.fromCharCode(0x00, 0x01); + } + }, + + switchpage: function (name) { + let codepage = wbxmltools.namespaces.indexOf(name); + if (codepage == -1) throw "[wbxmltools] Unknown codepage <" + name + ">"; + this._codepage = codepage; + this._wbxml += String.fromCharCode(0x00, codepage); + }, + + ctag: function () { + this._wbxml += String.fromCharCode(0x01); + }, + + //opentag is assumed to add a token with content, otherwise use addtag + otag: function (tokenname) { + this._wbxml += String.fromCharCode(wbxmltools.codepages2[this._codepage][tokenname] | 0x40); + }, + + getCharCodes: function () { + let value = ""; + for (let i = 0; i < this._wbxml.length; i++) value += ("00" + this._wbxml.charCodeAt(i).toString(16)).substr(-2) + " "; + return value; + }, + + getBytes: function () { + return this._wbxml; + } + }; + if (initialCodepage) wbxml._codepage = wbxmltools.namespaces.indexOf(initialCodepage); + return wbxml; + }, + + + + + + codepages2: [], + + buildCodepages2: function () { + for (let i = 0; i < this.codepages.length; i++) { + let inverted = {}; + for (let token in this.codepages[i]) { + inverted[this.codepages[i][token]] = token; + } + this.codepages2.push(inverted); + } + }, + + + + + + codepages: [ + // Code Page 0: AirSync + { + 0x05: 'Sync', + 0x06: 'Responses', + 0x07: 'Add', + 0x08: 'Change', + 0x09: 'Delete', + 0x0A: 'Fetch', + 0x0B: 'SyncKey', + 0x0C: 'ClientId', + 0x0D: 'ServerId', + 0x0E: 'Status', + 0x0F: 'Collection', + 0x10: 'Class', + 0x12: 'CollectionId', + 0x13: 'GetChanges', + 0x14: 'MoreAvailable', + 0x15: 'WindowSize', + 0x16: 'Commands', + 0x17: 'Options', + 0x18: 'FilterType', + 0x1B: 'Conflict', + 0x1C: 'Collections', + 0x1D: 'ApplicationData', + 0x1E: 'DeletesAsMoves', + 0x20: 'Supported', + 0x21: 'SoftDelete', + 0x22: 'MIMESupport', + 0x23: 'MIMETruncation', + 0x24: 'Wait', + 0x25: 'Limit', + 0x26: 'Partial', + 0x27: 'ConversationMode', + 0x28: 'MaxItems', + 0x29: 'HeartbeatInterval' + }, + // Code Page 1: Contacts + { + 0x05: 'Anniversary', + 0x06: 'AssistantName', + 0x07: 'AssistantPhoneNumber', + 0x08: 'Birthday', + 0x09: 'Body', + 0x0A: 'BodySize', + 0x0B: 'BodyTruncated', + 0x0C: 'Business2PhoneNumber', + 0x0D: 'BusinessAddressCity', + 0x0E: 'BusinessAddressCountry', + 0x0F: 'BusinessAddressPostalCode', + 0x10: 'BusinessAddressState', + 0x11: 'BusinessAddressStreet', + 0x12: 'BusinessFaxNumber', + 0x13: 'BusinessPhoneNumber', + 0x14: 'CarPhoneNumber', + 0x15: 'Categories', + 0x16: 'Category', + 0x17: 'Children', + 0x18: 'Child', + 0x19: 'CompanyName', + 0x1A: 'Department', + 0x1B: 'Email1Address', + 0x1C: 'Email2Address', + 0x1D: 'Email3Address', + 0x1E: 'FileAs', + 0x1F: 'FirstName', + 0x20: 'Home2PhoneNumber', + 0x21: 'HomeAddressCity', + 0x22: 'HomeAddressCountry', + 0x23: 'HomeAddressPostalCode', + 0x24: 'HomeAddressState', + 0x25: 'HomeAddressStreet', + 0x26: 'HomeFaxNumber', + 0x27: 'HomePhoneNumber', + 0x28: 'JobTitle', + 0x29: 'LastName', + 0x2A: 'MiddleName', + 0x2B: 'MobilePhoneNumber', + 0x2C: 'OfficeLocation', + 0x2D: 'OtherAddressCity', + 0x2E: 'OtherAddressCountry', + 0x2F: 'OtherAddressPostalCode', + 0x30: 'OtherAddressState', + 0x31: 'OtherAddressStreet', + 0x32: 'PagerNumber', + 0x33: 'RadioPhoneNumber', + 0x34: 'Spouse', + 0x35: 'Suffix', + 0x36: 'Title', + 0x37: 'WebPage', + 0x38: 'YomiCompanyName', + 0x39: 'YomiFirstName', + 0x3A: 'YomiLastName', + 0x3B: 'CompressedRTF', + 0x3C: 'Picture', + 0x3D: 'Alias', + 0x3E: 'WeightedRank' + }, + // Code Page 2: Email + { + 0x05: 'Attachment', + 0x06: 'Attachments', + 0x07: 'AttName', + 0x08: 'AttSize', + 0x09: 'Att0Id', + 0x0a: 'AttMethod', + 0x0b: 'AttRemoved', + 0x0c: 'Body', + 0x0d: 'BodySize', + 0x0e: 'BodyTruncated', + 0x0f: 'DateReceived', + 0x10: 'DisplayName', + 0x11: 'DisplayTo', + 0x12: 'Importance', + 0x13: 'MessageClass', + 0x14: 'Subject', + 0x15: 'Read', + 0x16: 'To', + 0x17: 'Cc', + 0x18: 'From', + 0x19: 'ReplyTo', + 0x1a: 'AllDayEvent', + 0x1b: 'Categories', + 0x1c: 'Category', + 0x1d: 'DTStamp', + 0x1e: 'EndTime', + 0x1f: 'InstanceType', + 0x20: 'BusyStatus', + 0x21: 'Location', + 0x22: 'MeetingRequest', + 0x23: 'Organizer', + 0x24: 'RecurrenceId', + 0x25: 'Reminder', + 0x26: 'ResponseRequested', + 0x27: 'Recurrences', + 0x28: 'Recurrence', + 0x29: 'Recurrence_Type', + 0x2a: 'Recurrence_Until', + 0x2b: 'Recurrence_Occurrences', + 0x2c: 'Recurrence_Interval', + 0x2d: 'Recurrence_DayOfWeek', + 0x2e: 'Recurrence_DayOfMonth', + 0x2f: 'Recurrence_WeekOfMonth', + 0x30: 'Recurrence_MonthOfYear', + 0x31: 'StartTime', + 0x32: 'Sensitivity', + 0x33: 'TimeZone', + 0x34: 'GlobalObjId', + 0x35: 'ThreadTopic', + 0x36: 'MIMEData', + 0x37: 'MIMETruncated', + 0x38: 'MIMESize', + 0x39: 'InternetCPID', + 0x3a: 'Flag', + 0x3b: 'Status', + 0x3c: 'ContentClass', + 0x3d: 'FlagType', + 0x3e: 'CompleteTime', + 0x3f: 'DisallowNewTimeProposal' + }, + // Code Page 3: AirNotify (WBXML code page 3 is no longer in use) + {}, + // Code Page 4: Calendar + { + 0x05: 'TimeZone', + 0x06: 'AllDayEvent', + 0x07: 'Attendees', + 0x08: 'Attendee', + 0x09: 'Email', + 0x0a: 'Name', + 0x0b: 'Body', + 0x0c: 'BodyTruncated', + 0x0d: 'BusyStatus', + 0x0e: 'Categories', + 0x0f: 'Category', + 0x10: 'CompressedRTF', + 0x11: 'DtStamp', + 0x12: 'EndTime', + 0x13: 'Exception', + 0x14: 'Exceptions', + 0x15: 'Deleted', + 0x16: 'ExceptionStartTime', + 0x17: 'Location', + 0x18: 'MeetingStatus', + 0x19: 'OrganizerEmail', + 0x1a: 'OrganizerName', + 0x1b: 'Recurrence', + 0x1c: 'Type', + 0x1d: 'Until', + 0x1e: 'Occurrences', + 0x1f: 'Interval', + 0x20: 'DayOfWeek', + 0x21: 'DayOfMonth', + 0x22: 'WeekOfMonth', + 0x23: 'MonthOfYear', + 0x24: 'Reminder', + 0x25: 'Sensitivity', + 0x26: 'Subject', + 0x27: 'StartTime', + 0x28: 'UID', + 0x29: 'AttendeeStatus', + 0x2a: 'AttendeeType', + 0x2b: 'Attachment', + 0x2c: 'Attachments', + 0x2d: 'AttName', + 0x2e: 'AttSize', + 0x2f: 'AttOid', + 0x30: 'AttMethod', + 0x31: 'AttRemoved', + 0x32: 'DisplayName', + 0x33: 'DisallowNewTimeProposal', + 0x34: 'ResponseRequested', + 0x35: 'AppointmentReplyTime', + 0x36: 'ResponseType', + 0x37: 'CalendarType', + 0x38: 'IsLeapMonth', + 0x39: 'FirstDayOfWeek', + 0x3a: 'OnlineMeetingConfLink', + 0x3b: 'OnlineMeetingExternalLink' + }, + // Code Page 5: Move + { + 0x05: 'MoveItems', + 0x06: 'Move', + 0x07: 'SrcMsgId', + 0x08: 'SrcFldId', + 0x09: 'DstFldId', + 0x0A: 'Response', + 0x0B: 'Status', + 0x0C: 'DstMsgId' + }, + // Code Page 6: GetItemEstimate + { + 0x05: 'GetItemEstimate', + 0x06: 'Version', + 0x07: 'Collections', + 0x08: 'Collection', + 0x09: 'Class', + 0x0A: 'CollectionId', + 0x0B: 'DateTime', + 0x0C: 'Estimate', + 0x0D: 'Response', + 0x0E: 'Status' + }, + // Code Page 7: FolderHierarchy + { + 0x07: 'DisplayName', + 0x08: 'ServerId', + 0x09: 'ParentId', + 0x0A: 'Type', + 0x0C: 'Status', + 0x0E: 'Changes', + 0x0F: 'Add', + 0x10: 'Delete', + 0x11: 'Update', + 0x12: 'SyncKey', + 0x13: 'FolderCreate', + 0x14: 'FolderDelete', + 0x15: 'FolderUpdate', + 0x16: 'FolderSync', + 0x17: 'Count' + }, + // Code Page 8: MeetingResponse + { + 0x05: 'CalendarId', + 0x06: 'CollectionId', + 0x07: 'MeetingResponse', + 0x08: 'RequestId', + 0x09: 'Request', + 0x0a: 'Result', + 0x0b: 'Status', + 0x0c: 'UserResponse', + 0x0e: 'InstanceId' + }, + // Code Page 9: Tasks + { + 0x05: 'Body', + 0x06: 'BodySize', + 0x07: 'BodyTruncated', + 0x08: 'Categories', + 0x09: 'Category', + 0x0A: 'Complete', + 0x0B: 'DateCompleted', + 0x0C: 'DueDate', + 0x0D: 'UtcDueDate', + 0x0E: 'Importance', + 0x0F: 'Recurrence', + 0x10: 'Type', + 0x11: 'Start', + 0x12: 'Until', + 0x13: 'Occurrences', + 0x14: 'Interval', + 0x15: 'DayOfMonth', + 0x16: 'DayOfWeek', + 0x17: 'WeekOfMonth', + 0x18: 'MonthOfYear', + 0x19: 'Regenerate', + 0x1A: 'DeadOccur', + 0x1B: 'ReminderSet', + 0x1C: 'ReminderTime', + 0x1D: 'Sensitivity', + 0x1E: 'StartDate', + 0x1F: 'UtcStartDate', + 0x20: 'Subject', + 0x22: 'OrdinalDate', + 0x23: 'SubOrdinalDate', + 0x24: 'CalendarType', + 0x25: 'IsLeapMonth', + 0x26: 'FirstDayOfWeek' + }, + // Code Page 10: ResolveRecipients + { + 0x05: 'ResolveRecipients', + 0x06: 'Response', + 0x07: 'Status', + 0x08: 'Type', + 0x09: 'Recipient', + 0x0a: 'DisplayName', + 0x0b: 'EmailAddress', + 0x0c: 'Certificates', + 0x0d: 'Certificate', + 0x0e: 'MiniCertificate', + 0x0f: 'Options', + 0x10: 'To', + 0x11: 'CertificateRetrieval', + 0x12: 'RecipientCount', + 0x13: 'MaxCertificates', + 0x14: 'MaxAmbiguousRecipients', + 0x15: 'CertificateCount', + 0x16: 'Availability', + 0x17: 'StartTime', + 0x18: 'EndTime', + 0x19: 'MergedFreeBusy', + 0x1a: 'Picture', + 0x1b: 'MaxSize', + 0x1c: 'Data', + 0x1d: 'MaxPictures' + }, + // Code Page 11: ValidateCert + { + 0x05: 'ValidateCert', + 0x06: 'Certificates', + 0x07: 'Certificate', + 0x08: 'CertificateChain', + 0x09: 'CheckCRL', + 0x0a: 'Status' + }, + // Code Page 12: Contacts2 + { + 0x05: 'CustomerId', + 0x06: 'GovernmentId', + 0x07: 'IMAddress', + 0x08: 'IMAddress2', + 0x09: 'IMAddress3', + 0x0a: 'ManagerName', + 0x0b: 'CompanyMainPhone', + 0x0c: 'AccountName', + 0x0d: 'NickName', + 0x0e: 'MMS' + }, + // Code Page 13: Ping + { + 0x05: 'Ping', + 0x06: 'AutdState', + //(Not used) + 0x07: 'Status', + 0x08: 'HeartbeatInterval', + 0x09: 'Folders', + 0x0A: 'Folder', + 0x0B: 'Id', + 0x0C: 'Class', + 0x0D: 'MaxFolders' + }, + // Code Page 14: Provision + { + 0x05: 'Provision', + 0x06: 'Policies', + 0x07: 'Policy', + 0x08: 'PolicyType', + 0x09: 'PolicyKey', + 0x0A: 'Data', + 0x0B: 'Status', + 0x0C: 'RemoteWipe', + 0x0D: 'EASProvisionDoc', + 0x0E: 'DevicePasswordEnabled', + 0x0F: 'AlphanumericDevicePasswordRequired', + 0x10: 'DeviceEncryptionEnabled', + 0x10: 'RequireStorageCardEncryption', + 0x11: 'PasswordRecoveryEnabled', + 0x13: 'AttachmentsEnabled', + 0x14: 'MinDevicePasswordLength', + 0x15: 'MaxInactivityTimeDeviceLock', + 0x16: 'MaxDevicePasswordFailedAttempts', + 0x17: 'MaxAttachmentSize', + 0x18: 'AllowSimpleDevicePassword', + 0x19: 'DevicePasswordExpiration', + 0x1A: 'DevicePasswordHistory', + 0x1B: 'AllowStorageCard', + 0x1C: 'AllowCamera', + 0x1D: 'RequireDeviceEncryption', + 0x1E: 'AllowUnsignedApplications', + 0x1F: 'AllowUnsignedInstallationPackages', + 0x20: 'MinDevicePasswordComplexCharacters', + 0x21: 'AllowWiFi', + 0x22: 'AllowTextMessaging', + 0x23: 'AllowPOPIMAPEmail', + 0x24: 'AllowBluetooth', + 0x25: 'AllowIrDA', + 0x26: 'RequireManualSyncWhenRoaming', + 0x27: 'AllowDesktopSync', + 0x28: 'MaxCalendarAgeFilter', + 0x29: 'AllowHTMLEmail', + 0x2A: 'MaxEmailAgeFilter', + 0x2B: 'MaxEmailBodyTruncationSize', + 0x2C: 'MaxEmailHTMLBodyTruncationSize', + 0x2D: 'RequireSignedSMIMEMessages', + 0x2E: 'RequireEncryptedSMIMEMessages', + 0x2F: 'RequireSignedSMIMEAlgorithm', + 0x30: 'RequireEncryptionSMIMEAlgorithm', + 0x31: 'AllowSMIMEEncryptionAlgorithmNegotiation', + 0x32: 'AllowSMIMESoftCerts', + 0x33: 'AllowBrowser', + 0x34: 'AllowConsumerEmail', + 0x35: 'AllowRemoteDesktop', + 0x36: 'AllowInternetSharing', + 0x37: 'UnapprovedInROMApplicationList', + 0x38: 'ApplicationName', + 0x39: 'ApprovedApplicationList', + 0x3A: 'Hash' + }, + // Code Page 15: Search + { + 0x05: 'Search', + 0x06: 'Stores', + 0x07: 'Store', + 0x08: 'Name', + 0x09: 'Query', + 0x0a: 'Options', + 0x0b: 'Range', + 0x0c: 'Status', + 0x0d: 'Response', + 0x0e: 'Result', + 0x0f: 'Properties', + 0x10: 'Total', + 0x11: 'EqualTo', + 0x12: 'Value', + 0x13: 'And', + 0x14: 'Or', + 0x15: 'FreeText', + 0x17: 'DeepTraversal', + 0x18: 'LongId', + 0x19: 'RebuildResults', + 0x1a: 'LessThan', + 0x1b: 'GreaterThan', + 0x1c: 'Schema', + 0x1d: 'Supported', + 0x1e: 'UserName', + 0x1f: 'Password', + 0x20: 'ConversationId', + 0x21: 'Picture', + 0x22: 'MaxSize', + 0x23: 'MaxPictures' + }, + // Code Page 16: GAL + { + 0x05: 'DisplayName', + 0x06: 'Phone', + 0x07: 'Office', + 0x08: 'Title', + 0x09: 'Company', + 0x0a: 'Alias', + 0x0b: 'FirstName', + 0x0c: 'LastName', + 0x0d: 'HomePhone', + 0x0e: 'MobilePhone', + 0x0f: 'EmailAddress', + 0x10: 'Picture', + 0x11: 'Status', + 0x12: 'Data' + }, + // Code Page 17: AirSyncBase + { + 0x05: 'BodyPreference', + 0x06: 'Type', + 0x07: 'TruncationSize', + 0x08: 'AllOrNone', + 0x0A: 'Body', + 0x0B: 'Data', + 0x0C: 'EstimatedDataSize', + 0x0D: 'Truncated', + 0x0E: 'Attachments', + 0x0F: 'Attachment', + 0x10: 'DisplayName', + 0x11: 'FileReference', + 0x12: 'Method', + 0x13: 'ContentId', + 0x14: 'ContentLocation', + 0x15: 'IsInline', + 0x16: 'NativeBodyType', + 0x17: 'ContentType', + 0x18: 'Preview', + 0x19: 'BodyPartPreference', + 0x1A: 'BodyPart', + 0x1B: 'Status' + }, + // Code Page 18: Settings + { + 0x05: 'Settings', + 0x06: 'Status', + 0x07: 'Get', + 0x08: 'Set', + 0x09: 'Oof', + 0x0A: 'OofState', + 0x0B: 'StartTime', + 0x0C: 'EndTime', + 0x0D: 'OofMessage', + 0x0E: 'AppliesToInternal', + 0x0F: 'AppliesToExternalKnown', + 0x10: 'AppliesToExternalUnknown', + 0x11: 'Enabled', + 0x12: 'ReplyMessage', + 0x13: 'BodyType', + 0x14: 'DevicePassword', + 0x15: 'Password', + 0x16: 'DeviceInformation', + 0x17: 'Model', + 0x18: 'IMEI', + 0x19: 'FriendlyName', + 0x1A: 'OS', + 0x1B: 'OSLanguage', + 0x1C: 'PhoneNumber', + 0x1D: 'UserInformation', + 0x1E: 'EmailAddresses', + 0x1F: 'SMTPAddress', + 0x20: 'UserAgent', + 0x21: 'EnableOutboundSMS', + 0x22: 'MobileOperator', + 0x23: 'PrimarySmtpAddress', + 0x24: 'Accounts', + 0x25: 'Account', + 0x26: 'AccountId', + 0x27: 'AccountName', + 0x28: 'UserDisplayName', + 0x29: 'SendDisabled', + 0x2B: 'RightsManagementInformation' + }, + // Code Page 19: DocumentLibrary + { + 0x05: 'LinkId', + 0x06: 'DisplayName', + 0x07: 'IsFolder', + 0x08: 'CreationDate', + 0x09: 'LastModifiedDate', + 0x0a: 'IsHidden', + 0x0b: 'ContentLength', + 0x0c: 'ContentType' + }, + // Code Page 20: ItemOperations + { + 0x05: 'ItemOperations', + 0x06: 'Fetch', + 0x07: 'Store', + 0x08: 'Options', + 0x09: 'Range', + 0x0A: 'Total', + 0x0B: 'Properties', + 0x0C: 'Data', + 0x0D: 'Status', + 0x0E: 'Response', + 0x0F: 'Version', + 0x10: 'Schema', + 0x11: 'Part', + 0x12: 'EmptyFolderContents', + 0x13: 'DeleteSubFolders', + 0x14: 'UserName', + 0x15: 'Password', + 0x16: 'Move', + 0x17: 'DstFldId', + 0x18: 'ConversationId', + 0x19: 'MoveAlways' + }, + // Code Page 21: ComposeMail + { + 0x05: 'SendMail', + 0x06: 'SmartForward', + 0x07: 'SmartReply', + 0x08: 'SaveInSentItems', + 0x09: 'ReplaceMime', + 0x0b: 'Source', + 0x0c: 'FolderId', + 0x0d: 'ItemId', + 0x0e: 'LongId', + 0x0f: 'InstanceId', + 0x10: 'Mime', + 0x11: 'ClientId', + 0x12: 'Status', + 0x13: 'AccountId', + 0x15: 'Forwardees', + 0x16: 'Forwardee', + 0x17: 'ForwardeeName', + 0x18: 'ForwardeeEmail' + }, + // Code Page 22: Email2 + { + 0x05: 'UmCallerID', + 0x06: 'UmUserNotes', + 0x07: 'UmAttDuration', + 0x08: 'UmAttOrder', + 0x09: 'ConversationId', + 0x0a: 'ConversationIndex', + 0x0b: 'LastVerbExecuted', + 0x0c: 'LastVerbExecutionTime', + 0x0d: 'ReceivedAsBcc', + 0x0e: 'Sender', + 0x0f: 'CalendarType', + 0x10: 'IsLeapMonth', + 0x11: 'AccountId', + 0x12: 'FirstDayOfWeek', + 0x13: 'MeetingMessageType', + 0x15: 'IsDraft', + 0x16: 'Bcc', + 0x17: 'Send' + }, + // Code Page 23: Notes + { + 0x05: 'Subject', + 0x06: 'MessageClass', + 0x07: 'LastModifiedDate', + 0x08: 'Categories', + 0x09: 'Category' + }, + // Code Page 24: RightsManagement + { + 0x05: 'RightsManagementSupport', + 0x06: 'RightsManagementTemplates', + 0x07: 'RightsManagementTemplate', + 0x08: 'RightsManagementLicense', + 0x09: 'EditAllowed', + 0x0a: 'ReplyAllowed', + 0x0b: 'ReplyAllAllowed', + 0x0c: 'ForwardAllowed', + 0x0d: 'ModifyRecipientsAllowed', + 0x0e: 'ExtractAllowed', + 0x0f: 'PrintAllowed', + 0x10: 'ExportAllowed', + 0x11: 'ProgrammaticAccessAllowed', + 0x12: 'Owner', + 0x13: 'ContentExpiryDate', + 0x14: 'TemplateID', + 0x15: 'TemplateName', + 0x16: 'TemplateDescription', + 0x17: 'ContentOwner', + 0x18: 'RemoveRightsManagementDistribution' + } + ], + + namespaces: [ + 'AirSync', + 'Contacts', + 'Email', + 'AirNotify', + 'Calendar', + 'Move', + 'GetItemEstimate', + 'FolderHierarchy', + 'MeetingResponse', + 'Tasks', + 'ResolveRecipients', + 'ValidateCert', + 'Contacts2', + 'Ping', + 'Provision', + 'Search', + 'Gal', + 'AirSyncBase', + 'Settings', + 'DocumentLibrary', + 'ItemOperations', + 'ComposeMail', + 'Email2', + 'Notes', + 'RightsManagement' + ] + +}; + +wbxmltools.buildCodepages2(); diff -Nru eas4tbsync-4.11/content/includes/xmltools.js eas4tbsync-4.17/content/includes/xmltools.js --- eas4tbsync-4.11/content/includes/xmltools.js 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/content/includes/xmltools.js 2025-05-15 11:21:20.000000000 +0000 @@ -1,156 +1,166 @@ -/* - * This file is part of EAS-4-TbSync. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -"use strict"; - -var { TbSync } = ChromeUtils.import("chrome://tbsync/content/tbsync.jsm"); -var xmltools = { - - isString : function (obj) { - return (Object.prototype.toString.call(obj) === '[object String]'); - }, - - checkString : function(d, fallback = "") { - if (this.isString(d)) return d; - else return fallback; - }, - - nodeAsArray : function (node) { - let a = []; - if (node) { - //return, if already an array - if (node instanceof Array) return node; - - //else push node into an array - a.push(node); - } - return a; - }, - - hasWbxmlDataField: function(wbxmlData, path) { - if (wbxmlData) { - let pathElements = path.split("."); - let data = wbxmlData; - for (let x = 0; x < pathElements.length; x++) { - if (data[pathElements[x]]) data = data[pathElements[x]]; - else return false; - } - return true; - } - return false; - }, - - getWbxmlDataField: function(wbxmlData,path) { - if (wbxmlData) { - let pathElements = path.split("."); - let data = wbxmlData; - let valid = true; - for (let x = 0; valid && x < pathElements.length; x++) { - if (data[pathElements[x]]) data = data[pathElements[x]]; - else valid = false; - } - if (valid) return data; - } - return false - }, - - //print content of xml data object (if debug output enabled) - printXmlData : function (data, printApplicationData) { - if (TbSync.prefs.getIntPref("log.userdatalevel") > 1 || (TbSync.prefs.getIntPref("log.userdatalevel") == 1 && printApplicationData)) { - let dump = JSON.stringify(data); - TbSync.dump("Extracted XML data", "\n" + dump); - } - }, - - getDataFromXMLString: function (str) { - let data = null; - let xml = ""; - if (str == "") return data; - - let oParser = (Services.vc.compare(Services.appinfo.platformVersion, "61.*") >= 0) ? new DOMParser() : Components.classes["@mozilla.org/xmlextras/domparser;1"].createInstance(Components.interfaces.nsIDOMParser); - try { - xml = oParser.parseFromString(str, "application/xml"); - } catch (e) { - //however, domparser does not throw an error, it returns an error document - //https://developer.mozilla.org/de/docs/Web/API/DOMParser - //just in case - throw eas.sync.finish("error", "malformed-xml"); - } - - //check if xml is error document - if (xml.documentElement.nodeName == "parsererror") { - TbSync.dump("BAD XML", "The above XML and WBXML could not be parsed correctly, something is wrong."); - throw eas.sync.finish("error", "malformed-xml"); - } - - try { - data = this.getDataFromXML(xml); - } catch (e) { - throw eas.sync.finish("error", "mailformed-data"); - } - - return data; - }, - - //create data object from XML node - getDataFromXML : function (nodes) { - - /* - * The passed nodes value could be an entire document in a single node (type 9) or a - * single element node (type 1) as returned by getElementById. It could however also - * be an array of nodes as returned by getElementsByTagName or a nodeList as returned - * by childNodes. In that case node.length is defined. - */ - - // create the return object - let obj = {}; - let nodeList = []; - let multiplicity = {}; - - if (nodes.length === undefined) nodeList.push(nodes); - else nodeList = nodes; - - // nodelist contains all childs, if two childs have the same name, we cannot add the chils as an object, but as an array of objects - for (let node of nodeList) { - if (node.nodeType == 1 || node.nodeType == 3) { - if (!multiplicity.hasOwnProperty(node.nodeName)) multiplicity[node.nodeName] = 0; - multiplicity[node.nodeName]++; - //if this nodeName has multiplicity > 1, prepare obj (but only once) - if (multiplicity[node.nodeName]==2) obj[node.nodeName] = []; - } - } - - // process nodes - for (let node of nodeList) { - switch (node.nodeType) { - case 9: - //document node, dive directly and process all children - if (node.hasChildNodes) obj = this.getDataFromXML(node.childNodes); - break; - case 1: - //element node - if (node.hasChildNodes) { - //if this is an element with only one text child, do not dive, but get text childs value - let o; - if (node.childNodes.length == 1 && node.childNodes.item(0).nodeType==3) { - //the passed xml is a save xml with all special chars in the user data encoded by encodeURIComponent - o = decodeURIComponent(node.childNodes.item(0).nodeValue); - } else { - o = this.getDataFromXML(node.childNodes); - } - //check, if we can add the object directly, or if we have to push it into an array - if (multiplicity[node.nodeName]>1) obj[node.nodeName].push(o) - else obj[node.nodeName] = o; - } - break; - } - } - return obj; - } - -}; +/* + * This file is part of EAS-4-TbSync. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +var { ExtensionParent } = ChromeUtils.importESModule( + "resource://gre/modules/ExtensionParent.sys.mjs" +); + +var tbsyncExtension = ExtensionParent.GlobalManager.getExtension( + "tbsync@jobisoft.de" +); +var { TbSync } = ChromeUtils.importESModule( + `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}` +); + +var xmltools = { + + isString: function (obj) { + return (Object.prototype.toString.call(obj) === '[object String]'); + }, + + checkString: function (d, fallback = "") { + if (this.isString(d)) return d; + else return fallback; + }, + + nodeAsArray: function (node) { + let a = []; + if (node) { + //return, if already an array + if (node instanceof Array) return node; + + //else push node into an array + a.push(node); + } + return a; + }, + + hasWbxmlDataField: function (wbxmlData, path) { + if (wbxmlData) { + let pathElements = path.split("."); + let data = wbxmlData; + for (let x = 0; x < pathElements.length; x++) { + if (data[pathElements[x]]) data = data[pathElements[x]]; + else return false; + } + return true; + } + return false; + }, + + getWbxmlDataField: function (wbxmlData, path) { + if (wbxmlData) { + let pathElements = path.split("."); + let data = wbxmlData; + let valid = true; + for (let x = 0; valid && x < pathElements.length; x++) { + if (data[pathElements[x]]) data = data[pathElements[x]]; + else valid = false; + } + if (valid) return data; + } + return false + }, + + //print content of xml data object (if debug output enabled) + printXmlData: function (data, printApplicationData) { + if (TbSync.prefs.getIntPref("log.userdatalevel") > 1 || (TbSync.prefs.getIntPref("log.userdatalevel") == 1 && printApplicationData)) { + let dump = JSON.stringify(data); + TbSync.dump("Extracted XML data", "\n" + dump); + } + }, + + getDataFromXMLString: function (str) { + let data = null; + let xml = ""; + if (str == "") return data; + + let oParser = (Services.vc.compare(Services.appinfo.platformVersion, "61.*") >= 0) ? new DOMParser() : Components.classes["@mozilla.org/xmlextras/domparser;1"].createInstance(Components.interfaces.nsIDOMParser); + try { + xml = oParser.parseFromString(str, "application/xml"); + } catch (e) { + //however, domparser does not throw an error, it returns an error document + //https://developer.mozilla.org/de/docs/Web/API/DOMParser + //just in case + throw eas.sync.finish("error", "malformed-xml"); + } + + //check if xml is error document + if (xml.documentElement.nodeName == "parsererror") { + TbSync.dump("BAD XML", "The above XML and WBXML could not be parsed correctly, something is wrong."); + throw eas.sync.finish("error", "malformed-xml"); + } + + try { + data = this.getDataFromXML(xml); + } catch (e) { + throw eas.sync.finish("error", "mailformed-data"); + } + + return data; + }, + + //create data object from XML node + getDataFromXML: function (nodes) { + + /* + * The passed nodes value could be an entire document in a single node (type 9) or a + * single element node (type 1) as returned by getElementById. It could however also + * be an array of nodes as returned by getElementsByTagName or a nodeList as returned + * by childNodes. In that case node.length is defined. + */ + + // create the return object + let obj = {}; + let nodeList = []; + let multiplicity = {}; + + if (nodes.length === undefined) nodeList.push(nodes); + else nodeList = nodes; + + // nodelist contains all childs, if two childs have the same name, we cannot add the chils as an object, but as an array of objects + for (let node of nodeList) { + if (node.nodeType == 1 || node.nodeType == 3) { + if (!multiplicity.hasOwnProperty(node.nodeName)) multiplicity[node.nodeName] = 0; + multiplicity[node.nodeName]++; + //if this nodeName has multiplicity > 1, prepare obj (but only once) + if (multiplicity[node.nodeName] == 2) obj[node.nodeName] = []; + } + } + + // process nodes + for (let node of nodeList) { + switch (node.nodeType) { + case 9: + //document node, dive directly and process all children + if (node.hasChildNodes) obj = this.getDataFromXML(node.childNodes); + break; + case 1: + //element node + if (node.hasChildNodes) { + //if this is an element with only one text child, do not dive, but get text childs value + let o; + if (node.childNodes.length == 1 && node.childNodes.item(0).nodeType == 3) { + //the passed xml is a save xml with all special chars in the user data encoded by encodeURIComponent + o = decodeURIComponent(node.childNodes.item(0).nodeValue); + } else { + o = this.getDataFromXML(node.childNodes); + } + //check, if we can add the object directly, or if we have to push it into an array + if (multiplicity[node.nodeName] > 1) obj[node.nodeName].push(o) + else obj[node.nodeName] = o; + } + break; + } + } + return obj; + } + +}; diff -Nru eas4tbsync-4.11/content/locales.js eas4tbsync-4.17/content/locales.js --- eas4tbsync-4.11/content/locales.js 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/content/locales.js 2025-05-15 11:21:20.000000000 +0000 @@ -1,3 +1,12 @@ -var { TbSync } = ChromeUtils.import("chrome://tbsync/content/tbsync.jsm"); - -TbSync.localizeOnLoad(window, "eas"); +var { ExtensionParent } = ChromeUtils.importESModule( + "resource://gre/modules/ExtensionParent.sys.mjs" +); + +var tbsyncExtension = ExtensionParent.GlobalManager.getExtension( + "tbsync@jobisoft.de" +); +var { TbSync } = ChromeUtils.importESModule( + `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}` +); + +TbSync.localizeOnLoad(window, "eas"); diff -Nru eas4tbsync-4.11/content/manager/createAccount.js eas4tbsync-4.17/content/manager/createAccount.js --- eas4tbsync-4.11/content/manager/createAccount.js 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/content/manager/createAccount.js 2025-05-15 11:21:20.000000000 +0000 @@ -1,254 +1,263 @@ -/* - * This file is part of EAS-4-TbSync. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - - "use strict"; - -var { TbSync } = ChromeUtils.import("chrome://tbsync/content/tbsync.jsm"); - -const eas = TbSync.providers.eas; - -var tbSyncEasNewAccount = { - - startTime: 0, - maxTimeout: 30, - validating: false, - - onClose: function () { - //disallow closing of wizard while validating - return !this.validating; - }, - - onCancel: function (event) { - //disallow closing of wizard while validating - if (this.validating) { - event.preventDefault(); - } - }, - - onLoad: function () { - this.providerData = new TbSync.ProviderData("eas"); - - this.elementName = document.getElementById('tbsync.newaccount.name'); - this.elementUser = document.getElementById('tbsync.newaccount.user'); - this.elementUrl = document.getElementById('tbsync.newaccount.url'); - this.elementPass = document.getElementById('tbsync.newaccount.password'); - this.elementServertype = document.getElementById('tbsync.newaccount.servertype'); - - document.getElementById("tbsync.newaccount.wizard").getButton("back").hidden = true; - this.onUserDropdown(); - - document.getElementById("tbsync.error").hidden = true; - document.getElementById("tbsync.spinner").hidden = true; - - document.addEventListener("wizardfinish", tbSyncEasNewAccount.onFinish.bind(this)); - document.addEventListener("wizardcancel", tbSyncEasNewAccount.onCancel.bind(this)); - // bug https://bugzilla.mozilla.org/show_bug.cgi?id=1618252 - document.getElementById('tbsync.newaccount.wizard')._adjustWizardHeader(); - }, - - onUnload: function () { - }, - - onUserTextInput: function () { - document.getElementById("tbsync.error").hidden = true; - switch (this.elementServertype.value) { - case "select": - document.getElementById("tbsync.newaccount.wizard").getButton("finish").disabled = true; - break; - - case "auto": - document.getElementById("tbsync.newaccount.wizard").getButton("finish").disabled = (this.elementName.value.trim() == "" || this.elementUser.value == "" || this.elementPass.value == ""); - break; - - case "office365": - document.getElementById("tbsync.newaccount.wizard").getButton("finish").disabled = (this.elementName.value.trim() == "" || this.elementUser.value == ""); - break; - - case "custom": - default: - document.getElementById("tbsync.newaccount.wizard").getButton("finish").disabled = (this.elementName.value.trim() == "" || this.elementUser.value == "" || this.elementPass.value == "" || this.elementUrl.value.trim() == ""); - break; - } - }, - - onUserDropdown: function () { - if (this.elementServertype) { - switch (this.elementServertype.value) { - case "select": - document.getElementById('tbsync.newaccount.user.box').hidden = true; - document.getElementById('tbsync.newaccount.url.box').hidden = true; - document.getElementById('tbsync.newaccount.password.box').hidden = true; - document.getElementById("tbsync.newaccount.wizard").getButton("finish").label = TbSync.getString("newaccount.add_custom","eas"); - break; - - case "auto": - document.getElementById('tbsync.newaccount.user.box').hidden = false; - document.getElementById('tbsync.newaccount.url.box').hidden = true; - document.getElementById('tbsync.newaccount.password.box').hidden = false; - document.getElementById("tbsync.newaccount.wizard").getButton("finish").label = TbSync.getString("newaccount.add_auto","eas"); - break; - - case "office365": - document.getElementById('tbsync.newaccount.user.box').hidden = false; - document.getElementById('tbsync.newaccount.url.box').hidden = true; - document.getElementById('tbsync.newaccount.password.box').hidden = true; - document.getElementById("tbsync.newaccount.wizard").getButton("finish").label = TbSync.getString("newaccount.add_custom","eas"); - break; - - case "custom": - default: - document.getElementById('tbsync.newaccount.user.box').hidden = false; - document.getElementById('tbsync.newaccount.url.box').hidden = false; - document.getElementById('tbsync.newaccount.password.box').hidden = false; - document.getElementById("tbsync.newaccount.wizard").getButton("finish").label = TbSync.getString("newaccount.add_custom","eas"); - break; - } - this.onUserTextInput(); - //document.getElementById("tbsync.newaccount.name").focus(); - } - }, - - onFinish: function (event) { - if (document.getElementById("tbsync.newaccount.wizard").getButton("finish").disabled == false) { - //initiate validation of server connection - this.validate(); - } - event.preventDefault(); - }, - - validate: async function () { - let user = this.elementUser.value; - let servertype = this.elementServertype.value; - let accountname = this.elementName.value.trim(); - - let url = (servertype == "custom") ?this.elementUrl.value.trim() : ""; - let password = (servertype == "auto" || servertype == "custom") ? this.elementPass.value : ""; - - if ((servertype == "auto" || servertype == "office365") && user.split("@").length != 2) { - alert(TbSync.getString("autodiscover.NeedEmail","eas")) - return; - } - - this.validating = true; - let error = ""; - - //document.getElementById("tbsync.newaccount.wizard").canRewind = false; - document.getElementById("tbsync.error").hidden = true; - document.getElementById("tbsync.newaccount.wizard").getButton("cancel").disabled = true; - document.getElementById("tbsync.newaccount.wizard").getButton("finish").disabled = true; - document.getElementById("tbsync.newaccount.name").disabled = true; - document.getElementById("tbsync.newaccount.user").disabled = true; - document.getElementById("tbsync.newaccount.password").disabled = true; - document.getElementById("tbsync.newaccount.servertype").disabled = true; - - tbSyncEasNewAccount.startTime = Date.now(); - tbSyncEasNewAccount.updateAutodiscoverStatus(); - document.getElementById("tbsync.spinner").hidden = false; - - //do autodiscover - if (servertype == "office365" || servertype == "auto") { - let updateTimer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer); - updateTimer.initWithCallback({notify : function () {tbSyncEasNewAccount.updateAutodiscoverStatus()}}, 1000, 3); - - if (servertype == "office365") { - let v2 = await eas.network.getServerConnectionViaAutodiscoverV2JsonRequest( - accountname, - user, - "https://autodiscover-s.outlook.com/autodiscover/autodiscover.json?Email="+encodeURIComponent(user)+"&Protocol=ActiveSync", - ); - let oauthData = eas.network.getOAuthObj({ host: v2.server, user, accountname, servertype }); - if (oauthData) { - // ask for token - document.getElementById("tbsync.spinner").hidden = true; - let _rv = {}; - if (await oauthData.asyncConnect(_rv)) { - password = _rv.tokens; - } else { - error = TbSync.getString("status." + _rv.error, "eas"); - } - document.getElementById("tbsync.spinner").hidden = false; - url=v2.server; - } else { - error = TbSync.getString("status.404", "eas"); - } - } else { - let result = await eas.network.getServerConnectionViaAutodiscover( - accountname, - user, - password, - tbSyncEasNewAccount.maxTimeout*1000 - ); - if (result.server) { - user = result.user; - url = result.server; - } else { - error = result.error; // is a localized string - } - } - - updateTimer.cancel(); - } - - //now validate the information - if (!error) { - if (!password) error = TbSync.getString("status.401", "eas"); - } - - //add if valid - if (!error) { - await tbSyncEasNewAccount.addAccount(user, password, servertype, accountname, url); - } - - //end validation - document.getElementById("tbsync.newaccount.name").disabled = false; - document.getElementById("tbsync.newaccount.user").disabled = false; - document.getElementById("tbsync.newaccount.password").disabled = false; - document.getElementById("tbsync.newaccount.servertype").disabled = false; - document.getElementById("tbsync.newaccount.wizard").getButton("cancel").disabled = false; - document.getElementById("tbsync.newaccount.wizard").getButton("finish").disabled = false; - document.getElementById("tbsync.spinner").hidden = true; - //document.getElementById("tbsync.newaccount.wizard").canRewind = true; - - this.validating = false; - - //close wizard, if done - if (!error) { - document.getElementById("tbsync.newaccount.wizard").cancel(); - } else { - document.getElementById("tbsync.error.message").textContent = error; - document.getElementById("tbsync.error").hidden = false; - } - window.sizeToContent(); - }, - - updateAutodiscoverStatus: function () { - let offset = Math.round(((Date.now() - tbSyncEasNewAccount.startTime)/1000)); - let timeout = (offset>2) ? " (" + (tbSyncEasNewAccount.maxTimeout - offset) + ")" : ""; - - document.getElementById('tbsync.newaccount.autodiscoverstatus').value = TbSync.getString("autodiscover.Querying","eas") + timeout; - }, - - async addAccount (user, password, servertype, accountname, url) { - let newAccountEntry = this.providerData.getDefaultAccountEntries(); - newAccountEntry.user = user; - newAccountEntry.servertype = servertype; - - if (url) { - //if no protocoll is given, prepend "https://" - if (url.substring(0,4) != "http" || url.indexOf("://") == -1) url = "https://" + url.split("://").join("/"); - newAccountEntry.host = eas.network.stripAutodiscoverUrl(url); - newAccountEntry.https = (url.substring(0,5) == "https"); - } - - // Add the new account. - let newAccountData = this.providerData.addAccount(accountname, newAccountEntry); - await eas.network.getAuthData(newAccountData).updateLoginData(user, password); - - window.close(); - } -}; +/* + * This file is part of EAS-4-TbSync. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +var { ExtensionParent } = ChromeUtils.importESModule( + "resource://gre/modules/ExtensionParent.sys.mjs" +); + +var tbsyncExtension = ExtensionParent.GlobalManager.getExtension( + "tbsync@jobisoft.de" +); +var { TbSync } = ChromeUtils.importESModule( + `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}` +); + +const eas = TbSync.providers.eas; + +var tbSyncEasNewAccount = { + + startTime: 0, + maxTimeout: 30, + validating: false, + + onClose: function () { + //disallow closing of wizard while validating + return !this.validating; + }, + + onCancel: function (event) { + //disallow closing of wizard while validating + if (this.validating) { + event.preventDefault(); + } + }, + + onLoad: function () { + this.providerData = new TbSync.ProviderData("eas"); + + this.elementName = document.getElementById('tbsync.newaccount.name'); + this.elementUser = document.getElementById('tbsync.newaccount.user'); + this.elementUrl = document.getElementById('tbsync.newaccount.url'); + this.elementPass = document.getElementById('tbsync.newaccount.password'); + this.elementServertype = document.getElementById('tbsync.newaccount.servertype'); + + document.getElementById("tbsync.newaccount.wizard").getButton("back").hidden = true; + this.onUserDropdown(); + + document.getElementById("tbsync.error").hidden = true; + document.getElementById("tbsync.spinner").hidden = true; + + document.addEventListener("wizardfinish", tbSyncEasNewAccount.onFinish.bind(this)); + document.addEventListener("wizardcancel", tbSyncEasNewAccount.onCancel.bind(this)); + // bug https://bugzilla.mozilla.org/show_bug.cgi?id=1618252 + document.getElementById('tbsync.newaccount.wizard')._adjustWizardHeader(); + }, + + onUnload: function () { + }, + + onUserTextInput: function () { + document.getElementById("tbsync.error").hidden = true; + switch (this.elementServertype.value) { + case "select": + document.getElementById("tbsync.newaccount.wizard").getButton("finish").disabled = true; + break; + + case "auto": + document.getElementById("tbsync.newaccount.wizard").getButton("finish").disabled = (this.elementName.value.trim() == "" || this.elementUser.value == "" || this.elementPass.value == ""); + break; + + case "office365": + document.getElementById("tbsync.newaccount.wizard").getButton("finish").disabled = (this.elementName.value.trim() == "" || this.elementUser.value == ""); + break; + + case "custom": + default: + document.getElementById("tbsync.newaccount.wizard").getButton("finish").disabled = (this.elementName.value.trim() == "" || this.elementUser.value == "" || this.elementPass.value == "" || this.elementUrl.value.trim() == ""); + break; + } + }, + + onUserDropdown: function () { + if (this.elementServertype) { + switch (this.elementServertype.value) { + case "select": + document.getElementById('tbsync.newaccount.user.box').hidden = true; + document.getElementById('tbsync.newaccount.url.box').hidden = true; + document.getElementById('tbsync.newaccount.password.box').hidden = true; + document.getElementById("tbsync.newaccount.wizard").getButton("finish").label = TbSync.getString("newaccount.add_custom", "eas"); + break; + + case "auto": + document.getElementById('tbsync.newaccount.user.box').hidden = false; + document.getElementById('tbsync.newaccount.url.box').hidden = true; + document.getElementById('tbsync.newaccount.password.box').hidden = false; + document.getElementById("tbsync.newaccount.wizard").getButton("finish").label = TbSync.getString("newaccount.add_auto", "eas"); + break; + + case "office365": + document.getElementById('tbsync.newaccount.user.box').hidden = false; + document.getElementById('tbsync.newaccount.url.box').hidden = true; + document.getElementById('tbsync.newaccount.password.box').hidden = true; + document.getElementById("tbsync.newaccount.wizard").getButton("finish").label = TbSync.getString("newaccount.add_custom", "eas"); + break; + + case "custom": + default: + document.getElementById('tbsync.newaccount.user.box').hidden = false; + document.getElementById('tbsync.newaccount.url.box').hidden = false; + document.getElementById('tbsync.newaccount.password.box').hidden = false; + document.getElementById("tbsync.newaccount.wizard").getButton("finish").label = TbSync.getString("newaccount.add_custom", "eas"); + break; + } + this.onUserTextInput(); + //document.getElementById("tbsync.newaccount.name").focus(); + } + }, + + onFinish: function (event) { + if (document.getElementById("tbsync.newaccount.wizard").getButton("finish").disabled == false) { + //initiate validation of server connection + this.validate(); + } + event.preventDefault(); + }, + + validate: async function () { + let user = this.elementUser.value; + let servertype = this.elementServertype.value; + let accountname = this.elementName.value.trim(); + + let url = (servertype == "custom") ? this.elementUrl.value.trim() : ""; + let password = (servertype == "auto" || servertype == "custom") ? this.elementPass.value : ""; + + if ((servertype == "auto" || servertype == "office365") && user.split("@").length != 2) { + alert(TbSync.getString("autodiscover.NeedEmail", "eas")) + return; + } + + this.validating = true; + let error = ""; + + //document.getElementById("tbsync.newaccount.wizard").canRewind = false; + document.getElementById("tbsync.error").hidden = true; + document.getElementById("tbsync.newaccount.wizard").getButton("cancel").disabled = true; + document.getElementById("tbsync.newaccount.wizard").getButton("finish").disabled = true; + document.getElementById("tbsync.newaccount.name").disabled = true; + document.getElementById("tbsync.newaccount.user").disabled = true; + document.getElementById("tbsync.newaccount.password").disabled = true; + document.getElementById("tbsync.newaccount.servertype").disabled = true; + + tbSyncEasNewAccount.startTime = Date.now(); + tbSyncEasNewAccount.updateAutodiscoverStatus(); + document.getElementById("tbsync.spinner").hidden = false; + + //do autodiscover + if (servertype == "office365" || servertype == "auto") { + let updateTimer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer); + updateTimer.initWithCallback({ notify: function () { tbSyncEasNewAccount.updateAutodiscoverStatus() } }, 1000, 3); + + if (servertype == "office365") { + let v2 = await eas.network.getServerConnectionViaAutodiscoverV2JsonRequest( + accountname, + user, + "https://autodiscover-s.outlook.com/autodiscover/autodiscover.json?Email=" + encodeURIComponent(user) + "&Protocol=ActiveSync", + ); + let oauthData = eas.network.getOAuthObj({ host: v2.server, user, accountname, servertype }); + if (oauthData) { + // ask for token + document.getElementById("tbsync.spinner").hidden = true; + let _rv = {}; + if (await oauthData.asyncConnect(_rv)) { + password = _rv.tokens; + } else { + error = TbSync.getString("status." + _rv.error, "eas"); + } + document.getElementById("tbsync.spinner").hidden = false; + url = v2.server; + } else { + error = TbSync.getString("status.404", "eas"); + } + } else { + let result = await eas.network.getServerConnectionViaAutodiscover( + accountname, + user, + password, + tbSyncEasNewAccount.maxTimeout * 1000 + ); + if (result.server) { + user = result.user; + url = result.server; + } else { + error = result.error; // is a localized string + } + } + + updateTimer.cancel(); + } + + //now validate the information + if (!error) { + if (!password) error = TbSync.getString("status.401", "eas"); + } + + //add if valid + if (!error) { + await tbSyncEasNewAccount.addAccount(user, password, servertype, accountname, url); + } + + //end validation + document.getElementById("tbsync.newaccount.name").disabled = false; + document.getElementById("tbsync.newaccount.user").disabled = false; + document.getElementById("tbsync.newaccount.password").disabled = false; + document.getElementById("tbsync.newaccount.servertype").disabled = false; + document.getElementById("tbsync.newaccount.wizard").getButton("cancel").disabled = false; + document.getElementById("tbsync.newaccount.wizard").getButton("finish").disabled = false; + document.getElementById("tbsync.spinner").hidden = true; + //document.getElementById("tbsync.newaccount.wizard").canRewind = true; + + this.validating = false; + + //close wizard, if done + if (!error) { + document.getElementById("tbsync.newaccount.wizard").cancel(); + } else { + document.getElementById("tbsync.error.message").textContent = error; + document.getElementById("tbsync.error").hidden = false; + } + window.sizeToContent(); + }, + + updateAutodiscoverStatus: function () { + let offset = Math.round(((Date.now() - tbSyncEasNewAccount.startTime) / 1000)); + let timeout = (offset > 2) ? " (" + (tbSyncEasNewAccount.maxTimeout - offset) + ")" : ""; + + document.getElementById('tbsync.newaccount.autodiscoverstatus').value = TbSync.getString("autodiscover.Querying", "eas") + timeout; + }, + + async addAccount(user, password, servertype, accountname, url) { + let newAccountEntry = this.providerData.getDefaultAccountEntries(); + newAccountEntry.user = user; + newAccountEntry.servertype = servertype; + + if (url) { + //if no protocoll is given, prepend "https://" + if (url.substring(0, 4) != "http" || url.indexOf("://") == -1) url = "https://" + url.split("://").join("/"); + newAccountEntry.host = eas.network.stripAutodiscoverUrl(url); + newAccountEntry.https = (url.substring(0, 5) == "https"); + } + + // Add the new account. + let newAccountData = this.providerData.addAccount(accountname, newAccountEntry); + await eas.network.getAuthData(newAccountData).updateLoginData(user, password); + + window.close(); + } +}; diff -Nru eas4tbsync-4.11/content/manager/createAccount.xhtml eas4tbsync-4.17/content/manager/createAccount.xhtml --- eas4tbsync-4.11/content/manager/createAccount.xhtml 2024-08-19 18:22:14.000000000 +0000 +++ eas4tbsync-4.17/content/manager/createAccount.xhtml 2025-05-15 11:21:20.000000000 +0000 @@ -1,97 +1,97 @@ - - - - - - - - - -