From: Aurélien COUDERC Date: Sun, 14 Aug 2022 16:55:39 +0000 (+0100) Subject: Import kdav_5.97.0.orig.tar.xz X-Git-Tag: archive/raspbian/1%5.102.0-1+rpi1~3 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=ad7cfe2e763fdd79964cb3096a5509811b4127aa;p=kdav.git Import kdav_5.97.0.orig.tar.xz [dgit import orig kdav_5.97.0.orig.tar.xz] --- ad7cfe2e763fdd79964cb3096a5509811b4127aa diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4231aac --- /dev/null +++ b/.gitignore @@ -0,0 +1,26 @@ +# Ignore the following files +*~ +*.[oa] +*.diff +*.kate-swp +*.kdev4 +.kdev_include_paths +*.kdevelop.pcs +*.moc +*.moc.cpp +*.orig +*.user +.*.swp +.swp.* +Doxyfile +Makefile +/build*/ +.cmake/ +CMakeLists.txt.user* +*.unc-backup* +/.clang-format +/compile_commands.json +.clangd +.idea +/cmake-build* +.cache diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..04bb392 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,10 @@ +# SPDX-FileCopyrightText: 2020 Volker Krause +# SPDX-License-Identifier: CC0-1.0 + +include: + - https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux.yml + - https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/android.yml + - https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/freebsd.yml + - https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux-qt6.yml + - https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/android-qt6.yml + - https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/windows.yml diff --git a/.kde-ci.yml b/.kde-ci.yml new file mode 100644 index 0000000..5334735 --- /dev/null +++ b/.kde-ci.yml @@ -0,0 +1,9 @@ +Dependencies: +- 'on': ['@all'] + 'require': + 'frameworks/extra-cmake-modules': '@same' + 'frameworks/kio' : '@same' + +Options: + test-before-installing: True + require-passing-tests-on: [ 'Linux', 'FreeBSD' ] diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..73d59ac --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,96 @@ +cmake_minimum_required(VERSION 3.16) + +set(KF_VERSION "5.97.0") # handled by release scripts +set(KF_DEP_VERSION "5.97.0") # handled by release scripts + +project(libkdav VERSION ${KF_VERSION}) + +find_package(ECM 5.97.0 CONFIG REQUIRED) +set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) + +include(KDEInstallDirs) +include(KDECMakeSettings) +include(KDEGitCommitHooks) +include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) + +include(CMakeFindDependencyMacro) +include(ECMSetupVersion) +include(GenerateExportHeader) +include(ECMGenerateHeaders) +include(ECMGeneratePriFile) +include(FeatureSummary) +include(ECMAddQch) +include(ECMAddTests) +include(ECMInstallIcons) +include(ECMQtDeclareLoggingCategory) +include(ECMDeprecationSettings) + + +set(REQUIRED_QT_VERSION 5.15.2) +find_package(Qt${QT_MAJOR_VERSION} ${REQUIRED_QT_VERSION} CONFIG REQUIRED Core Gui Test) + +find_package(KF5 ${KF_DEP_VERSION} REQUIRED CoreAddons KIO I18n) + +# setup lib + +option(BUILD_QCH "Build API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)" OFF) +add_feature_info(QCH ${BUILD_QCH} "API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)") + +ecm_set_disabled_deprecation_versions( + QT 5.15.2 + KF 5.95 +) + +ecm_setup_version(PROJECT VARIABLE_PREFIX KDAV + VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kdav_version.h" + PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5DAVConfigVersion.cmake" + SOVERSION 5 + ) + +ki18n_install(po) + +add_subdirectory(src) +if(BUILD_TESTING) + add_subdirectory(autotests) + add_subdirectory(test) +endif() + +set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KF5DAV") + +if (BUILD_QCH) + ecm_install_qch_export( + TARGETS KF5DAV_QCH + FILE KF5DAVQchTargets.cmake + DESTINATION "${CMAKECONFIG_INSTALL_DIR}" + COMPONENT Devel + ) + set(PACKAGE_INCLUDE_QCHTARGETS "include(\"\${CMAKE_CURRENT_LIST_DIR}/KF5DAVQchTargets.cmake\")") +endif() + +configure_package_config_file( + "${CMAKE_CURRENT_SOURCE_DIR}/KF5DAVConfig.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/KF5DAVConfig.cmake" + INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} + ) + +install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/KF5DAVConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/KF5DAVConfigVersion.cmake" + DESTINATION "${CMAKECONFIG_INSTALL_DIR}" + COMPONENT Devel + ) + +install(EXPORT KF5DAVTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" FILE KF5DAVTargets.cmake NAMESPACE KF5::) + +install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/kdav_version.h + DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF} COMPONENT Devel + ) + + +feature_summary(WHAT ALL + INCLUDE_QUIET_PACKAGES + FATAL_ON_MISSING_REQUIRED_PACKAGES +) + +kde_configure_git_pre_commit_hook(CHECKS CLANG_FORMAT) diff --git a/KF5DAVConfig.cmake.in b/KF5DAVConfig.cmake.in new file mode 100644 index 0000000..677262f --- /dev/null +++ b/KF5DAVConfig.cmake.in @@ -0,0 +1,7 @@ +@PACKAGE_INIT@ + +include(CMakeFindDependencyMacro) +find_dependency(KF5CoreAddons "@KF_DEP_VERSION@") + +include("${CMAKE_CURRENT_LIST_DIR}/KF5DAVTargets.cmake") +@PACKAGE_INCLUDE_QCHTARGETS@ diff --git a/LICENSES/CC0-1.0.txt b/LICENSES/CC0-1.0.txt new file mode 100644 index 0000000..0e259d4 --- /dev/null +++ b/LICENSES/CC0-1.0.txt @@ -0,0 +1,121 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. diff --git a/LICENSES/GPL-2.0-or-later.txt b/LICENSES/GPL-2.0-or-later.txt new file mode 100644 index 0000000..1d80ac3 --- /dev/null +++ b/LICENSES/GPL-2.0-or-later.txt @@ -0,0 +1,319 @@ +GNU GENERAL PUBLIC LICENSE + +Version 2, June 1991 + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. + +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + +Preamble + +The licenses for most software are designed to take away your freedom to share +and change it. By contrast, the GNU General Public License is intended to +guarantee your freedom to share and change free software--to make sure the +software is free for all its users. This General Public License applies to +most of the Free Software Foundation's software and to any other program whose +authors commit to using it. (Some other Free Software Foundation software +is covered by the GNU Lesser General Public License instead.) You can apply +it to your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our +General Public Licenses are designed to make sure that you have the freedom +to distribute copies of free software (and charge for this service if you +wish), that you receive source code or can get it if you want it, that you +can change the software or use pieces of it in new free programs; and that +you know you can do these things. + +To protect your rights, we need to make restrictions that forbid anyone to +deny you these rights or to ask you to surrender the rights. These restrictions +translate to certain responsibilities for you if you distribute copies of +the software, or if you modify it. + +For example, if you distribute copies of such a program, whether gratis or +for a fee, you must give the recipients all the rights that you have. You +must make sure that they, too, receive or can get the source code. And you +must show them these terms so they know their rights. + +We protect your rights with two steps: (1) copyright the software, and (2) +offer you this license which gives you legal permission to copy, distribute +and/or modify the software. + +Also, for each author's protection and ours, we want to make certain that +everyone understands that there is no warranty for this free software. If +the software is modified by someone else and passed on, we want its recipients +to know that what they have is not the original, so that any problems introduced +by others will not reflect on the original authors' reputations. + +Finally, any free program is threatened constantly by software patents. We +wish to avoid the danger that redistributors of a free program will individually +obtain patent licenses, in effect making the program proprietary. To prevent +this, we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + +The precise terms and conditions for copying, distribution and modification +follow. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License applies to any program or other work which contains a notice +placed by the copyright holder saying it may be distributed under the terms +of this General Public License. The "Program", below, refers to any such program +or work, and a "work based on the Program" means either the Program or any +derivative work under copyright law: that is to say, a work containing the +Program or a portion of it, either verbatim or with modifications and/or translated +into another language. (Hereinafter, translation is included without limitation +in the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not covered +by this License; they are outside its scope. The act of running the Program +is not restricted, and the output from the Program is covered only if its +contents constitute a work based on the Program (independent of having been +made by running the Program). Whether that is true depends on what the Program +does. + +1. You may copy and distribute verbatim copies of the Program's source code +as you receive it, in any medium, provided that you conspicuously and appropriately +publish on each copy an appropriate copyright notice and disclaimer of warranty; +keep intact all the notices that refer to this License and to the absence +of any warranty; and give any other recipients of the Program a copy of this +License along with the Program. + +You may charge a fee for the physical act of transferring a copy, and you +may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Program or any portion of it, +thus forming a work based on the Program, and copy and distribute such modifications +or work under the terms of Section 1 above, provided that you also meet all +of these conditions: + +a) You must cause the modified files to carry prominent notices stating that +you changed the files and the date of any change. + +b) You must cause any work that you distribute or publish, that in whole or +in part contains or is derived from the Program or any part thereof, to be +licensed as a whole at no charge to all third parties under the terms of this +License. + +c) If the modified program normally reads commands interactively when run, +you must cause it, when started running for such interactive use in the most +ordinary way, to print or display an announcement including an appropriate +copyright notice and a notice that there is no warranty (or else, saying that +you provide a warranty) and that users may redistribute the program under +these conditions, and telling the user how to view a copy of this License. +(Exception: if the Program itself is interactive but does not normally print +such an announcement, your work based on the Program is not required to print +an announcement.) + +These requirements apply to the modified work as a whole. If identifiable +sections of that work are not derived from the Program, and can be reasonably +considered independent and separate works in themselves, then this License, +and its terms, do not apply to those sections when you distribute them as +separate works. But when you distribute the same sections as part of a whole +which is a work based on the Program, the distribution of the whole must be +on the terms of this License, whose permissions for other licensees extend +to the entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest your +rights to work written entirely by you; rather, the intent is to exercise +the right to control the distribution of derivative or collective works based +on the Program. + +In addition, mere aggregation of another work not based on the Program with +the Program (or with a work based on the Program) on a volume of a storage +or distribution medium does not bring the other work under the scope of this +License. + +3. You may copy and distribute the Program (or a work based on it, under Section +2) in object code or executable form under the terms of Sections 1 and 2 above +provided that you also do one of the following: + +a) Accompany it with the complete corresponding machine-readable source code, +which must be distributed under the terms of Sections 1 and 2 above on a medium +customarily used for software interchange; or, + +b) Accompany it with a written offer, valid for at least three years, to give +any third party, for a charge no more than your cost of physically performing +source distribution, a complete machine-readable copy of the corresponding +source code, to be distributed under the terms of Sections 1 and 2 above on +a medium customarily used for software interchange; or, + +c) Accompany it with the information you received as to the offer to distribute +corresponding source code. (This alternative is allowed only for noncommercial +distribution and only if you received the program in object code or executable +form with such an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for making +modifications to it. For an executable work, complete source code means all +the source code for all modules it contains, plus any associated interface +definition files, plus the scripts used to control compilation and installation +of the executable. However, as a special exception, the source code distributed +need not include anything that is normally distributed (in either source or +binary form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component itself +accompanies the executable. + +If distribution of executable or object code is made by offering access to +copy from a designated place, then offering equivalent access to copy the +source code from the same place counts as distribution of the source code, +even though third parties are not compelled to copy the source along with +the object code. + +4. You may not copy, modify, sublicense, or distribute the Program except +as expressly provided under this License. Any attempt otherwise to copy, modify, +sublicense or distribute the Program is void, and will automatically terminate +your rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses terminated +so long as such parties remain in full compliance. + +5. You are not required to accept this License, since you have not signed +it. However, nothing else grants you permission to modify or distribute the +Program or its derivative works. These actions are prohibited by law if you +do not accept this License. Therefore, by modifying or distributing the Program +(or any work based on the Program), you indicate your acceptance of this License +to do so, and all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + +6. Each time you redistribute the Program (or any work based on the Program), +the recipient automatically receives a license from the original licensor +to copy, distribute or modify the Program subject to these terms and conditions. +You may not impose any further restrictions on the recipients' exercise of +the rights granted herein. You are not responsible for enforcing compliance +by third parties to this License. + +7. If, as a consequence of a court judgment or allegation of patent infringement +or for any other reason (not limited to patent issues), conditions are imposed +on you (whether by court order, agreement or otherwise) that contradict the +conditions of this License, they do not excuse you from the conditions of +this License. If you cannot distribute so as to satisfy simultaneously your +obligations under this License and any other pertinent obligations, then as +a consequence you may not distribute the Program at all. For example, if a +patent license would not permit royalty-free redistribution of the Program +by all those who receive copies directly or indirectly through you, then the +only way you could satisfy both it and this License would be to refrain entirely +from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply and +the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents +or other property right claims or to contest validity of any such claims; +this section has the sole purpose of protecting the integrity of the free +software distribution system, which is implemented by public license practices. +Many people have made generous contributions to the wide range of software +distributed through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing to +distribute software through any other system and a licensee cannot impose +that choice. + +This section is intended to make thoroughly clear what is believed to be a +consequence of the rest of this License. + +8. If the distribution and/or use of the Program is restricted in certain +countries either by patents or by copyrighted interfaces, the original copyright +holder who places the Program under this License may add an explicit geographical +distribution limitation excluding those countries, so that distribution is +permitted only in or among countries not thus excluded. In such case, this +License incorporates the limitation as if written in the body of this License. + +9. The Free Software Foundation may publish revised and/or new versions of +the General Public License from time to time. Such new versions will be similar +in spirit to the present version, but may differ in detail to address new +problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies +a version number of this License which applies to it and "any later version", +you have the option of following the terms and conditions either of that version +or of any later version published by the Free Software Foundation. If the +Program does not specify a version number of this License, you may choose +any version ever published by the Free Software Foundation. + +10. If you wish to incorporate parts of the Program into other free programs +whose distribution conditions are different, write to the author to ask for +permission. For software which is copyrighted by the Free Software Foundation, +write to the Free Software Foundation; we sometimes make exceptions for this. +Our decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing and reuse +of software generally. + + NO WARRANTY + +11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR +THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE +STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM +"AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE +OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE +OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA +OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES +OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH +HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest possible +use to the public, the best way to achieve this is to make it free software +which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to attach +them to the start of each source file to most effectively convey the exclusion +of warranty; and each file should have at least the "copyright" line and a +pointer to where the full notice is found. + + + +Copyright (C) + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 51 Franklin +Street, Fifth Floor, Boston, MA 02110-1301, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this when +it starts in an interactive mode: + +Gnomovision version 69, Copyright (C) year name of author Gnomovision comes +with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, +and you are welcome to redistribute it under certain conditions; type `show +c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may be +called something other than `show w' and `show c'; they could even be mouse-clicks +or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your school, +if any, to sign a "copyright disclaimer" for the program, if necessary. Here +is a sample; alter the names: + +Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' +(which makes passes at compilers) written by James Hacker. + +, 1 April 1989 Ty Coon, President of Vice This General +Public License does not permit incorporating your program into proprietary +programs. If your program is a subroutine library, you may consider it more +useful to permit linking proprietary applications with the library. If this +is what you want to do, use the GNU Lesser General Public License instead +of this License. diff --git a/LICENSES/LGPL-2.0-or-later.txt b/LICENSES/LGPL-2.0-or-later.txt new file mode 100644 index 0000000..5c96471 --- /dev/null +++ b/LICENSES/LGPL-2.0-or-later.txt @@ -0,0 +1,446 @@ +GNU LIBRARY GENERAL PUBLIC LICENSE + +Version 2, June 1991 Copyright (C) 1991 Free Software Foundation, Inc. + +51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is numbered 2 because +it goes with version 2 of the ordinary GPL.] + +Preamble + +The licenses for most software are designed to take away your freedom to share +and change it. By contrast, the GNU General Public Licenses are intended to +guarantee your freedom to share and change free software--to make sure the +software is free for all its users. + +This license, the Library General Public License, applies to some specially +designated Free Software Foundation software, and to any other libraries whose +authors decide to use it. You can use it for your libraries, too. + +When we speak of free software, we are referring to freedom, not price. Our +General Public Licenses are designed to make sure that you have the freedom +to distribute copies of free software (and charge for this service if you +wish), that you receive source code or can get it if you want it, that you +can change the software or use pieces of it in new free programs; and that +you know you can do these things. + +To protect your rights, we need to make restrictions that forbid anyone to +deny you these rights or to ask you to surrender the rights. These restrictions +translate to certain responsibilities for you if you distribute copies of +the library, or if you modify it. + +For example, if you distribute copies of the library, whether gratis or for +a fee, you must give the recipients all the rights that we gave you. You must +make sure that they, too, receive or can get the source code. If you link +a program with the library, you must provide complete object files to the +recipients so that they can relink them with the library, after making changes +to the library and recompiling it. And you must show them these terms so they +know their rights. + +Our method of protecting your rights has two steps: (1) copyright the library, +and (2) offer you this license which gives you legal permission to copy, distribute +and/or modify the library. + +Also, for each distributor's protection, we want to make certain that everyone +understands that there is no warranty for this free library. If the library +is modified by someone else and passed on, we want its recipients to know +that what they have is not the original version, so that any problems introduced +by others will not reflect on the original authors' reputations. + +Finally, any free program is threatened constantly by software patents. We +wish to avoid the danger that companies distributing free software will individually +obtain patent licenses, thus in effect transforming the program into proprietary +software. To prevent this, we have made it clear that any patent must be licensed +for everyone's free use or not licensed at all. + +Most GNU software, including some libraries, is covered by the ordinary GNU +General Public License, which was designed for utility programs. This license, +the GNU Library General Public License, applies to certain designated libraries. +This license is quite different from the ordinary one; be sure to read it +in full, and don't assume that anything in it is the same as in the ordinary +license. + +The reason we have a separate public license for some libraries is that they +blur the distinction we usually make between modifying or adding to a program +and simply using it. Linking a program with a library, without changing the +library, is in some sense simply using the library, and is analogous to running +a utility program or application program. However, in a textual and legal +sense, the linked executable is a combined work, a derivative of the original +library, and the ordinary General Public License treats it as such. + +Because of this blurred distinction, using the ordinary General Public License +for libraries did not effectively promote software sharing, because most developers +did not use the libraries. We concluded that weaker conditions might promote +sharing better. + +However, unrestricted linking of non-free programs would deprive the users +of those programs of all benefit from the free status of the libraries themselves. +This Library General Public License is intended to permit developers of non-free +programs to use free libraries, while preserving your freedom as a user of +such programs to change the free libraries that are incorporated in them. +(We have not seen how to achieve this as regards changes in header files, +but we have achieved it as regards changes in the actual functions of the +Library.) The hope is that this will lead to faster development of free libraries. + +The precise terms and conditions for copying, distribution and modification +follow. Pay close attention to the difference between a "work based on the +library" and a "work that uses the library". The former contains code derived +from the library, while the latter only works together with the library. + +Note that it is possible for a library to be covered by the ordinary General +Public License rather than by this special one. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License Agreement applies to any software library which contains a +notice placed by the copyright holder or other authorized party saying it +may be distributed under the terms of this Library General Public License +(also called "this License"). Each licensee is addressed as "you". + +A "library" means a collection of software functions and/or data prepared +so as to be conveniently linked with application programs (which use some +of those functions and data) to form executables. + +The "Library", below, refers to any such software library or work which has +been distributed under these terms. A "work based on the Library" means either +the Library or any derivative work under copyright law: that is to say, a +work containing the Library or a portion of it, either verbatim or with modifications +and/or translated straightforwardly into another language. (Hereinafter, translation +is included without limitation in the term "modification".) + +"Source code" for a work means the preferred form of the work for making modifications +to it. For a library, complete source code means all the source code for all +modules it contains, plus any associated interface definition files, plus +the scripts used to control compilation and installation of the library. + +Activities other than copying, distribution and modification are not covered +by this License; they are outside its scope. The act of running a program +using the Library is not restricted, and output from such a program is covered +only if its contents constitute a work based on the Library (independent of +the use of the Library in a tool for writing it). Whether that is true depends +on what the Library does and what the program that uses the Library does. + +1. You may copy and distribute verbatim copies of the Library's complete source +code as you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice and disclaimer +of warranty; keep intact all the notices that refer to this License and to +the absence of any warranty; and distribute a copy of this License along with +the Library. + +You may charge a fee for the physical act of transferring a copy, and you +may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Library or any portion of it, +thus forming a work based on the Library, and copy and distribute such modifications +or work under the terms of Section 1 above, provided that you also meet all +of these conditions: + + a) The modified work must itself be a software library. + +b) You must cause the files modified to carry prominent notices stating that +you changed the files and the date of any change. + +c) You must cause the whole of the work to be licensed at no charge to all +third parties under the terms of this License. + +d) If a facility in the modified Library refers to a function or a table of +data to be supplied by an application program that uses the facility, other +than as an argument passed when the facility is invoked, then you must make +a good faith effort to ensure that, in the event an application does not supply +such function or table, the facility still operates, and performs whatever +part of its purpose remains meaningful. + +(For example, a function in a library to compute square roots has a purpose +that is entirely well-defined independent of the application. Therefore, Subsection +2d requires that any application-supplied function or table used by this function +must be optional: if the application does not supply it, the square root function +must still compute square roots.) + +These requirements apply to the modified work as a whole. If identifiable +sections of that work are not derived from the Library, and can be reasonably +considered independent and separate works in themselves, then this License, +and its terms, do not apply to those sections when you distribute them as +separate works. But when you distribute the same sections as part of a whole +which is a work based on the Library, the distribution of the whole must be +on the terms of this License, whose permissions for other licensees extend +to the entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest your +rights to work written entirely by you; rather, the intent is to exercise +the right to control the distribution of derivative or collective works based +on the Library. + +In addition, mere aggregation of another work not based on the Library with +the Library (or with a work based on the Library) on a volume of a storage +or distribution medium does not bring the other work under the scope of this +License. + +3. You may opt to apply the terms of the ordinary GNU General Public License +instead of this License to a given copy of the Library. To do this, you must +alter all the notices that refer to this License, so that they refer to the +ordinary GNU General Public License, version 2, instead of to this License. +(If a newer version than version 2 of the ordinary GNU General Public License +has appeared, then you can specify that version instead if you wish.) Do not +make any other change in these notices. + +Once this change is made in a given copy, it is irreversible for that copy, +so the ordinary GNU General Public License applies to all subsequent copies +and derivative works made from that copy. + +This option is useful when you wish to copy part of the code of the Library +into a program that is not a library. + +4. You may copy and distribute the Library (or a portion or derivative of +it, under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you accompany it with the complete corresponding +machine-readable source code, which must be distributed under the terms of +Sections 1 and 2 above on a medium customarily used for software interchange. + +If distribution of object code is made by offering access to copy from a designated +place, then offering equivalent access to copy the source code from the same +place satisfies the requirement to distribute the source code, even though +third parties are not compelled to copy the source along with the object code. + +5. A program that contains no derivative of any portion of the Library, but +is designed to work with the Library by being compiled or linked with it, +is called a "work that uses the Library". Such a work, in isolation, is not +a derivative work of the Library, and therefore falls outside the scope of +this License. + +However, linking a "work that uses the Library" with the Library creates an +executable that is a derivative of the Library (because it contains portions +of the Library), rather than a "work that uses the library". The executable +is therefore covered by this License. Section 6 states terms for distribution +of such executables. + +When a "work that uses the Library" uses material from a header file that +is part of the Library, the object code for the work may be a derivative work +of the Library even though the source code is not. Whether this is true is +especially significant if the work can be linked without the Library, or if +the work is itself a library. The threshold for this to be true is not precisely +defined by law. + +If such an object file uses only numerical parameters, data structure layouts +and accessors, and small macros and small inline functions (ten lines or less +in length), then the use of the object file is unrestricted, regardless of +whether it is legally a derivative work. (Executables containing this object +code plus portions of the Library will still fall under Section 6.) + +Otherwise, if the work is a derivative of the Library, you may distribute +the object code for the work under the terms of Section 6. Any executables +containing that work also fall under Section 6, whether or not they are linked +directly with the Library itself. + +6. As an exception to the Sections above, you may also compile or link a "work +that uses the Library" with the Library to produce a work containing portions +of the Library, and distribute that work under terms of your choice, provided +that the terms permit modification of the work for the customer's own use +and reverse engineering for debugging such modifications. + +You must give prominent notice with each copy of the work that the Library +is used in it and that the Library and its use are covered by this License. +You must supply a copy of this License. If the work during execution displays +copyright notices, you must include the copyright notice for the Library among +them, as well as a reference directing the user to the copy of this License. +Also, you must do one of these things: + +a) Accompany the work with the complete corresponding machine-readable source +code for the Library including whatever changes were used in the work (which +must be distributed under Sections 1 and 2 above); and, if the work is an +executable linked with the Library, with the complete machine-readable "work +that uses the Library", as object code and/or source code, so that the user +can modify the Library and then relink to produce a modified executable containing +the modified Library. (It is understood that the user who changes the contents +of definitions files in the Library will not necessarily be able to recompile +the application to use the modified definitions.) + +b) Accompany the work with a written offer, valid for at least three years, +to give the same user the materials specified in Subsection 6a, above, for +a charge no more than the cost of performing this distribution. + +c) If distribution of the work is made by offering access to copy from a designated +place, offer equivalent access to copy the above specified materials from +the same place. + +d) Verify that the user has already received a copy of these materials or +that you have already sent this user a copy. + +For an executable, the required form of the "work that uses the Library" must +include any data and utility programs needed for reproducing the executable +from it. However, as a special exception, the source code distributed need +not include anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the operating +system on which the executable runs, unless that component itself accompanies +the executable. + +It may happen that this requirement contradicts the license restrictions of +other proprietary libraries that do not normally accompany the operating system. +Such a contradiction means you cannot use both them and the Library together +in an executable that you distribute. + +7. You may place library facilities that are a work based on the Library side-by-side +in a single library together with other library facilities not covered by +this License, and distribute such a combined library, provided that the separate +distribution of the work based on the Library and of the other library facilities +is otherwise permitted, and provided that you do these two things: + +a) Accompany the combined library with a copy of the same work based on the +Library, uncombined with any other library facilities. This must be distributed +under the terms of the Sections above. + +b) Give prominent notice with the combined library of the fact that part of +it is a work based on the Library, and explaining where to find the accompanying +uncombined form of the same work. + +8. You may not copy, modify, sublicense, link with, or distribute the Library +except as expressly provided under this License. Any attempt otherwise to +copy, modify, sublicense, link with, or distribute the Library is void, and +will automatically terminate your rights under this License. However, parties +who have received copies, or rights, from you under this License will not +have their licenses terminated so long as such parties remain in full compliance. + +9. You are not required to accept this License, since you have not signed +it. However, nothing else grants you permission to modify or distribute the +Library or its derivative works. These actions are prohibited by law if you +do not accept this License. Therefore, by modifying or distributing the Library +(or any work based on the Library), you indicate your acceptance of this License +to do so, and all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + +10. Each time you redistribute the Library (or any work based on the Library), +the recipient automatically receives a license from the original licensor +to copy, distribute, link with or modify the Library subject to these terms +and conditions. You may not impose any further restrictions on the recipients' +exercise of the rights granted herein. You are not responsible for enforcing +compliance by third parties to this License. + +11. If, as a consequence of a court judgment or allegation of patent infringement +or for any other reason (not limited to patent issues), conditions are imposed +on you (whether by court order, agreement or otherwise) that contradict the +conditions of this License, they do not excuse you from the conditions of +this License. If you cannot distribute so as to satisfy simultaneously your +obligations under this License and any other pertinent obligations, then as +a consequence you may not distribute the Library at all. For example, if a +patent license would not permit royalty-free redistribution of the Library +by all those who receive copies directly or indirectly through you, then the +only way you could satisfy both it and this License would be to refrain entirely +from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents +or other property right claims or to contest validity of any such claims; +this section has the sole purpose of protecting the integrity of the free +software distribution system which is implemented by public license practices. +Many people have made generous contributions to the wide range of software +distributed through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing to +distribute software through any other system and a licensee cannot impose +that choice. + +This section is intended to make thoroughly clear what is believed to be a +consequence of the rest of this License. + +12. If the distribution and/or use of the Library is restricted in certain +countries either by patents or by copyrighted interfaces, the original copyright +holder who places the Library under this License may add an explicit geographical +distribution limitation excluding those countries, so that distribution is +permitted only in or among countries not thus excluded. In such case, this +License incorporates the limitation as if written in the body of this License. + +13. The Free Software Foundation may publish revised and/or new versions of +the Library General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to address +new problems or concerns. + +Each version is given a distinguishing version number. If the Library specifies +a version number of this License which applies to it and "any later version", +you have the option of following the terms and conditions either of that version +or of any later version published by the Free Software Foundation. If the +Library does not specify a license version number, you may choose any version +ever published by the Free Software Foundation. + +14. If you wish to incorporate parts of the Library into other free programs +whose distribution conditions are incompatible with these, write to the author +to ask for permission. For software which is copyrighted by the Free Software +Foundation, write to the Free Software Foundation; we sometimes make exceptions +for this. Our decision will be guided by the two goals of preserving the free +status of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + +15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR +THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE +STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY +"AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE +OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE +THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE +OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA +OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES +OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH +HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Libraries + +If you develop a new library, and you want it to be of the greatest possible +use to the public, we recommend making it free software that everyone can +redistribute and change. You can do so by permitting redistribution under +these terms (or, alternatively, under the terms of the ordinary General Public +License). + +To apply these terms, attach the following notices to the library. It is safest +to attach them to the start of each source file to most effectively convey +the exclusion of warranty; and each file should have at least the "copyright" +line and a pointer to where the full notice is found. + +one line to give the library's name and an idea of what it does. + +Copyright (C) year name of author + +This library is free software; you can redistribute it and/or modify it under +the terms of the GNU Library General Public License as published by the Free +Software Foundation; either version 2 of the License, or (at your option) +any later version. + +This library is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more +details. + +You should have received a copy of the GNU Library General Public License +along with this library; if not, write to the Free Software Foundation, Inc., +51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your school, +if any, to sign a "copyright disclaimer" for the library, if necessary. Here +is a sample; alter the names: + +Yoyodyne, Inc., hereby disclaims all copyright interest in + +the library `Frob' (a library for tweaking knobs) written + +by James Random Hacker. + +signature of Ty Coon, 1 April 1990 + +Ty Coon, President of Vice + +That's all there is to it! diff --git a/README.md b/README.md new file mode 100644 index 0000000..e720ad1 --- /dev/null +++ b/README.md @@ -0,0 +1,56 @@ +# KDAV + +## Introduction + +This is an DAV protocol implementation with KJobs. + +Calendars and todos are supported, using either GroupDAV +or CalDAV, and contacts are supported using GroupDAV or +CardDAV. + + +## Usage + +It should be pretty straightforward. The URL to use should be, if possible, +the principals URL for your server (CalDAV / CardDAV) or the parent +collection of your calendars to allow discovery. + + +## Tested with / known bugs + +Here is a list of servers tested with this resource with the URLs used. +Feel free to contact the author(s) if you successfully tested a configuration +not listed here. + +* Egroupware (1.6.002) + https://host/groupdav.php + - GroupDAV working. + - CalDAV working. + - CardDAV working. + +* SOGo (version 1.0.4, 1.1.0 and version at http://sogo-demo.inverse.ca/) + https://host/SOGo/dav//Calendar and https://host/SOGo/dav//Contacts + - GroupDAV calendar working, but the timezone data in the ICalendar + generated by KCal seems misinterpreted by SOGo : every event is + shifted by the timezone offset (at least test with TZ Europe/Paris, + feel free to send your results to the author(s). This seems resolved + with the demo version made available by Inverse.ca. + - CalDAV working, with the same bug. + - CardDAV working. + +* Davical (version 0.9.7.6) + https://host/caldav.php/principals/users/ + - CalDAV working. + +* Zimbra Open-Source edition (version 5.0.18), + https://host/principals/users/ + - Caldav mostly working : retrieval of shared calendars that contain a lot + of events fails with a 500 server error. + +* Google calendar + https://www.google.com/calendar/dav//events + - CalDAV working. + +* iCloud + https://caldav.icloud.com/ + - CalDAV working ([App-specific password required](https://support.apple.com/en-us/HT204397)). \ No newline at end of file diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt new file mode 100644 index 0000000..9bfcb92 --- /dev/null +++ b/autotests/CMakeLists.txt @@ -0,0 +1,38 @@ +set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) +add_definitions(-DAUTOTEST_DATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}/data") + +ecm_add_test(davcollectiontest.cpp + TEST_NAME davcollection + NAME_PREFIX "kdav-" + LINK_LIBRARIES KF5::DAV Qt${QT_MAJOR_VERSION}::Test Qt${QT_MAJOR_VERSION}::Core Qt${QT_MAJOR_VERSION}::Gui +) + +ecm_add_test(davitemtest.cpp + TEST_NAME davitem + NAME_PREFIX "kdav-" + LINK_LIBRARIES KF5::DAV Qt${QT_MAJOR_VERSION}::Test Qt${QT_MAJOR_VERSION}::Core +) + +ecm_add_test(davurltest.cpp + TEST_NAME davurl + NAME_PREFIX "kdav-" + LINK_LIBRARIES KF5::DAV Qt${QT_MAJOR_VERSION}::Test Qt${QT_MAJOR_VERSION}::Core +) + +ecm_add_test(davcollectionsmultifetchjobtest.cpp fakeserver.cpp + TEST_NAME davcollectionsmultifetchjobtest + NAME_PREFIX "kdav-" + LINK_LIBRARIES KF5::DAV Qt${QT_MAJOR_VERSION}::Test Qt${QT_MAJOR_VERSION}::Core Qt${QT_MAJOR_VERSION}::Network +) + +ecm_add_test(davitemfetchjobtest.cpp fakeserver.cpp + TEST_NAME davitemfetchjob + NAME_PREFIX "kdav-" + LINK_LIBRARIES KF5::DAV Qt${QT_MAJOR_VERSION}::Test Qt${QT_MAJOR_VERSION}::Core Qt${QT_MAJOR_VERSION}::Network +) + +ecm_add_test(davitemslistjobtest.cpp fakeserver.cpp + TEST_NAME davitemslistjob + NAME_PREFIX "kdav-" + LINK_LIBRARIES KF5::DAV Qt${QT_MAJOR_VERSION}::Test Qt${QT_MAJOR_VERSION}::Core Qt${QT_MAJOR_VERSION}::Network +) diff --git a/autotests/data/dataitemfetchjob.txt b/autotests/data/dataitemfetchjob.txt new file mode 100644 index 0000000..26588f9 --- /dev/null +++ b/autotests/data/dataitemfetchjob.txt @@ -0,0 +1,17 @@ +C: GET /item HTTP/1.1 +C: User-Agent: KDE DAV groupware client +S: HTTP/1.0 200 OK +S: Date: Wed, 04 Jan 2017 18:26:48 GMT +S: Last-Modified: Wed, 04 Jan 2017 18:26:47 GMT +S: ETag: 7a33141f192d904d-47 +S: Content-Type: text/x-vcard; charset=utf-8 +D: BEGIN:VCARD +D: VERSION:3.0 +D: PRODID:-//Kolab//iRony DAV Server 0.3.1//Sabre//Sabre VObject 2.1.7//EN +D: UID:12345678-1234-1234-1234-123456789abc +D: FN:John2 Doe +D: N:Doe;John2;;; +D: EMAIL;TYPE=INTERNET;TYPE=HOME:john2.doe@example.com +D: REV;VALUE=DATE-TIME:20170104T182647Z +D: END:VCARD +X diff --git a/autotests/data/dataitemmultifetchjob-caldav-collections.txt b/autotests/data/dataitemmultifetchjob-caldav-collections.txt new file mode 100644 index 0000000..5d29dbc --- /dev/null +++ b/autotests/data/dataitemmultifetchjob-caldav-collections.txt @@ -0,0 +1,37 @@ +C: PROPFIND /caldav/dfaure%40example.com/ HTTP/1.1 +S: HTTP/1.1 207 Multi-Status +S: Date: Wed, 04 Jan 2017 18:26:48 GMT +S: Last-Modified: Wed, 04 Jan 2017 18:26:47 GMT +S: DAV: 1, 3, extended-mkcol, access-control, calendarserver-principal-property-search, calendar-access, calendar-proxy, calendar-schedule, calendar-auto-schedule, addressbook, 2 +S: Content-Type: application/xml; charset=utf-8 +D: +D: +D: +D: /caldav.php/test1.user/home/ +D: +D: +D: +D: +D: +D: +D: +D: +D: +D: +D: +D: +D: +D: +D: Test1 User +D: +D: +D: +D: +D: +D: 12345 +D: +D: HTTP/1.1 200 OK +D: +D: +D: +X diff --git a/autotests/data/dataitemmultifetchjob-caldav.txt b/autotests/data/dataitemmultifetchjob-caldav.txt new file mode 100644 index 0000000..e876f57 --- /dev/null +++ b/autotests/data/dataitemmultifetchjob-caldav.txt @@ -0,0 +1,21 @@ +C: PROPFIND /caldav HTTP/1.1 +S: HTTP/1.1 207 Multi-Status +S: Date: Wed, 04 Jan 2017 18:26:48 GMT +S: Last-Modified: Wed, 04 Jan 2017 18:26:47 GMT +S: DAV: 1, 3, extended-mkcol, access-control, calendarserver-principal-property-search, calendar-access, calendar-proxy, calendar-schedule, calendar-auto-schedule, addressbook, 2 +S: Content-Type: application/xml; charset=utf-8 +D: +D: +D: +D: /principals/users/dfaure%40example.com/ +D: +D: +D: +D: /caldav/dfaure%40example.com/ +D: +D: +D: HTTP/1.1 200 OK +D: +D: +D: +X diff --git a/autotests/data/dataitemmultifetchjob-carddav-collections.txt b/autotests/data/dataitemmultifetchjob-carddav-collections.txt new file mode 100644 index 0000000..e63496d --- /dev/null +++ b/autotests/data/dataitemmultifetchjob-carddav-collections.txt @@ -0,0 +1,24 @@ +C: PROPFIND /carddav/dfaure%40example.com/ HTTP/1.1 +S: HTTP/1.1 207 Multi-Status +S: Date: Wed, 04 Jan 2017 18:26:48 GMT +S: Last-Modified: Wed, 04 Jan 2017 18:26:47 GMT +S: DAV: 1, 3, extended-mkcol, access-control, calendarserver-principal-property-search, calendar-access, calendar-proxy, calendar-schedule, calendar-auto-schedule, addressbook, 2 +S: Content-Type: application/xml; charset=utf-8 +D: +D: +D: +D: /carddav.php/test1.user/home/ +D: +D: +D: +D: +D: +D: +D: My Address Book +D: 3145 +D: +D: HTTP/1.1 200 OK +D: +D: +D: +X diff --git a/autotests/data/dataitemmultifetchjob-carddav.txt b/autotests/data/dataitemmultifetchjob-carddav.txt new file mode 100644 index 0000000..6a389b7 --- /dev/null +++ b/autotests/data/dataitemmultifetchjob-carddav.txt @@ -0,0 +1,21 @@ +C: PROPFIND /carddav HTTP/1.1 +S: HTTP/1.1 207 Multi-Status +S: Date: Wed, 04 Jan 2017 18:26:48 GMT +S: Last-Modified: Wed, 04 Jan 2017 18:26:47 GMT +S: DAV: 1, 3, extended-mkcol, access-control, calendarserver-principal-property-search, calendar-access, calendar-proxy, calendar-schedule, calendar-auto-schedule, addressbook, 2 +S: Content-Type: application/xml; charset=utf-8 +D: +D: +D: +D: /principals/users/dfaure%40example.com/ +D: +D: +D: +D: /carddav/dfaure%40example.com/ +D: +D: +D: HTTP/1.1 200 OK +D: +D: +D: +X diff --git a/autotests/data/dataitemmultifetchjob-error.txt b/autotests/data/dataitemmultifetchjob-error.txt new file mode 100644 index 0000000..ada1fb0 --- /dev/null +++ b/autotests/data/dataitemmultifetchjob-error.txt @@ -0,0 +1,3 @@ +C: PROPFIND /does_not_exist HTTP/1.1 +S: HTTP/1.1 404 Not found +X diff --git a/autotests/davcollectionsmultifetchjobtest.cpp b/autotests/davcollectionsmultifetchjobtest.cpp new file mode 100644 index 0000000..497d340 --- /dev/null +++ b/autotests/davcollectionsmultifetchjobtest.cpp @@ -0,0 +1,106 @@ +/* + SPDX-FileCopyrightText: 2020 David Faure + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "davcollectionsmultifetchjobtest.h" +#include "fakeserver.h" + +#include + +#include +#include + +using KDAV::DavCollection; +Q_DECLARE_METATYPE(KDAV::Protocol) + +void DavCollectionsMultiFetchJobTest::initTestCase() +{ + // To avoid a runtime dependency on klauncher + qputenv("KDE_FORK_SLAVES", "yes"); + // To let ctest exit, we shouldn't start kio_http_cache_cleaner + qputenv("KIO_DISABLE_CACHE_CLEANER", "yes"); + + qRegisterMetaType(); +} + +void DavCollectionsMultiFetchJobTest::runSuccessfullTest() +{ + FakeServer fakeServer(5990); + QUrl url(QStringLiteral("http://localhost/caldav")); + url.setPort(fakeServer.port()); + KDAV::DavUrl davUrl1(url, KDAV::CalDav); + QUrl url2(url); + url2.setPath(QStringLiteral("/carddav")); + KDAV::DavUrl davUrl2(url2, KDAV::CardDav); + + auto job = new KDAV::DavCollectionsMultiFetchJob({davUrl1, davUrl2}); + + QSignalSpy spy(job, &KDAV::DavCollectionsMultiFetchJob::collectionDiscovered); + + fakeServer.addScenarioFromFile(QLatin1String(AUTOTEST_DATA_DIR) + QStringLiteral("/dataitemmultifetchjob-caldav.txt")); + fakeServer.addScenarioFromFile(QLatin1String(AUTOTEST_DATA_DIR) + QStringLiteral("/dataitemmultifetchjob-caldav-collections.txt")); + fakeServer.addScenarioFromFile(QLatin1String(AUTOTEST_DATA_DIR) + QStringLiteral("/dataitemmultifetchjob-carddav.txt")); + fakeServer.addScenarioFromFile(QLatin1String(AUTOTEST_DATA_DIR) + QStringLiteral("/dataitemmultifetchjob-carddav-collections.txt")); + fakeServer.startAndWait(); + job->exec(); + + QVERIFY(fakeServer.isAllScenarioDone()); + QCOMPARE(job->error(), 0); + + const KDAV::DavCollection::List collections = job->collections(); + QCOMPARE(collections.count(), 2); + int calDavIdx = 0; + int cardDavIdx = 1; + if (collections.at(0).contentTypes() == DavCollection::Contacts) { // put things in a defined order + std::swap(calDavIdx, cardDavIdx); + } + + const KDAV::DavCollection calendar = collections.at(calDavIdx); + QCOMPARE(calendar.displayName(), QStringLiteral("Test1 User")); + QCOMPARE(calendar.contentTypes(), DavCollection::Events | DavCollection::Todos | DavCollection::FreeBusy | DavCollection::Journal); + QCOMPARE(calendar.url().url().path(), QStringLiteral("/caldav.php/test1.user/home/")); + QCOMPARE(calendar.CTag(), QStringLiteral("12345")); + QCOMPARE(calendar.privileges(), KDAV::Read); + + const KDAV::DavCollection addressbook = collections.at(cardDavIdx); + QCOMPARE(addressbook.displayName(), QStringLiteral("My Address Book")); + QCOMPARE(addressbook.contentTypes(), DavCollection::Contacts); + QCOMPARE(addressbook.url().url().path(), QStringLiteral("/carddav.php/test1.user/home/")); + QCOMPARE(addressbook.CTag(), QStringLiteral("3145")); + QCOMPARE(addressbook.privileges(), KDAV::All); + + QCOMPARE(spy.count(), 2); + QCOMPARE(int(spy.at(calDavIdx).at(0).value()), int(KDAV::CalDav)); + QCOMPARE(spy.at(calDavIdx).at(1).toString(), calendar.url().url().toString()); + QCOMPARE(spy.at(calDavIdx).at(2).toString(), url.toString()); + + QCOMPARE(int(spy.at(cardDavIdx).at(0).value()), int(KDAV::CardDav)); + QCOMPARE(spy.at(cardDavIdx).at(1).toString(), addressbook.url().url().toString()); + QCOMPARE(spy.at(cardDavIdx).at(2).toString(), url2.toString()); +} + +void DavCollectionsMultiFetchJobTest::shouldFailOnError() +{ + FakeServer fakeServer(5990); + QUrl url(QStringLiteral("http://localhost/caldav")); + url.setPort(fakeServer.port()); + KDAV::DavUrl davUrl1(url, KDAV::CalDav); + QUrl urlError(url); + urlError.setPath(QStringLiteral("/does_not_exist")); + KDAV::DavUrl davUrlError(urlError, KDAV::CalDav); + + auto job = new KDAV::DavCollectionsMultiFetchJob({davUrl1, davUrlError}); + + fakeServer.addScenarioFromFile(QLatin1String(AUTOTEST_DATA_DIR) + QStringLiteral("/dataitemmultifetchjob-caldav.txt")); + fakeServer.addScenarioFromFile(QLatin1String(AUTOTEST_DATA_DIR) + QStringLiteral("/dataitemmultifetchjob-caldav-collections.txt")); + fakeServer.addScenarioFromFile(QLatin1String(AUTOTEST_DATA_DIR) + QStringLiteral("/dataitemmultifetchjob-error.txt")); + fakeServer.startAndWait(); + job->exec(); + + QVERIFY(fakeServer.isAllScenarioDone()); + QCOMPARE(job->error(), 300); +} + +QTEST_MAIN(DavCollectionsMultiFetchJobTest) diff --git a/autotests/davcollectionsmultifetchjobtest.h b/autotests/davcollectionsmultifetchjobtest.h new file mode 100644 index 0000000..9a652af --- /dev/null +++ b/autotests/davcollectionsmultifetchjobtest.h @@ -0,0 +1,22 @@ +/* + SPDX-FileCopyrightText: 2020 David Faure + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef DAVITEMFETCHJOB_TEST_H +#define DAVITEMFETCHJOB_TEST_H + +#include + +class DavCollectionsMultiFetchJobTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void runSuccessfullTest(); + void shouldFailOnError(); +}; + +#endif diff --git a/autotests/davcollectiontest.cpp b/autotests/davcollectiontest.cpp new file mode 100644 index 0000000..eb69128 --- /dev/null +++ b/autotests/davcollectiontest.cpp @@ -0,0 +1,99 @@ +/* + SPDX-FileCopyrightText: 2017 Sandro Knauß + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "davcollectiontest.h" + +#include +#include + +#include +#include + +void DavCollectionTest::createEmpty() +{ + KDAV::DavCollection davCollection; + + QCOMPARE(davCollection.url().protocol(), KDAV::CalDav); + QCOMPARE(davCollection.CTag(), QString()); + QCOMPARE(davCollection.displayName(), QString()); + QCOMPARE(davCollection.color(), QColor()); + QCOMPARE(davCollection.contentTypes(), KDAV::DavCollection::ContentTypes()); + QCOMPARE(davCollection.privileges(), KDAV::Privileges()); +} + +void DavCollectionTest::storeTest() +{ + QUrl url(QStringLiteral("test://me:pw@test")); + KDAV::DavUrl davUrl(url, KDAV::CardDav); + KDAV::DavCollection davCollection(davUrl, QStringLiteral("myname"), KDAV::DavCollection::Events | KDAV::DavCollection::Todos); + + QCOMPARE(davCollection.url().protocol(), KDAV::CardDav); + QCOMPARE(davCollection.url().url(), url); + QCOMPARE(davCollection.CTag(), QString()); + QCOMPARE(davCollection.displayName(), QStringLiteral("myname")); + QCOMPARE(davCollection.color(), QColor()); + QCOMPARE(davCollection.contentTypes(), KDAV::DavCollection::Events | KDAV::DavCollection::Todos); + QCOMPARE(davCollection.privileges(), KDAV::All); +} + +void DavCollectionTest::setTest() +{ + QUrl url(QStringLiteral("test://me:pw@test")); + KDAV::DavUrl davUrl(url, KDAV::CardDav); + KDAV::DavCollection davCollection; + + davCollection.setUrl(davUrl); + davCollection.setCTag(QStringLiteral("ctag")); + davCollection.setDisplayName(QStringLiteral("myname")); + davCollection.setColor(QColor(1, 2, 3)); + davCollection.setContentTypes(KDAV::DavCollection::Events | KDAV::DavCollection::Todos); + davCollection.setPrivileges(KDAV::Read | KDAV::Write); + + QCOMPARE(davCollection.url().protocol(), KDAV::CardDav); + QCOMPARE(davCollection.url().url(), url); + QCOMPARE(davCollection.CTag(), QStringLiteral("ctag")); + QCOMPARE(davCollection.displayName(), QStringLiteral("myname")); + QCOMPARE(davCollection.color(), QColor(1, 2, 3)); + QCOMPARE(davCollection.contentTypes(), KDAV::DavCollection::Events | KDAV::DavCollection::Todos); + QCOMPARE(davCollection.privileges(), KDAV::Read | KDAV::Write); +} + +void DavCollectionTest::copyTest() +{ + KDAV::DavCollection davCollection; + + QUrl url(QStringLiteral("test://me:pw@test")); + KDAV::DavUrl davUrl(url, KDAV::CardDav); + + davCollection.setUrl(davUrl); + davCollection.setCTag(QStringLiteral("ctag")); + davCollection.setDisplayName(QStringLiteral("myname")); + davCollection.setColor(QColor(1, 2, 3)); + davCollection.setContentTypes(KDAV::DavCollection::Events | KDAV::DavCollection::Todos); + davCollection.setPrivileges(KDAV::Read | KDAV::Write); + + KDAV::DavCollection copy1(davCollection); + QCOMPARE(copy1.url().protocol(), davCollection.url().protocol()); + QCOMPARE(copy1.url().url(), davCollection.url().url()); + QCOMPARE(copy1.CTag(), davCollection.CTag()); + QCOMPARE(copy1.displayName(), davCollection.displayName()); + QCOMPARE(copy1.color(), davCollection.color()); + QCOMPARE(copy1.contentTypes(), davCollection.contentTypes()); + QCOMPARE(copy1.privileges(), davCollection.privileges()); + + KDAV::DavCollection copy2; + copy2 = davCollection; + + QCOMPARE(copy2.url().protocol(), davCollection.url().protocol()); + QCOMPARE(copy2.url().url(), davCollection.url().url()); + QCOMPARE(copy2.CTag(), davCollection.CTag()); + QCOMPARE(copy2.displayName(), davCollection.displayName()); + QCOMPARE(copy2.color(), davCollection.color()); + QCOMPARE(copy2.contentTypes(), davCollection.contentTypes()); + QCOMPARE(copy2.privileges(), davCollection.privileges()); +} + +QTEST_MAIN(DavCollectionTest) diff --git a/autotests/davcollectiontest.h b/autotests/davcollectiontest.h new file mode 100644 index 0000000..de4a87c --- /dev/null +++ b/autotests/davcollectiontest.h @@ -0,0 +1,23 @@ +/* + SPDX-FileCopyrightText: 2017 Sandro Knauß + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef DAVCOLLECTION_TEST_H +#define DAVCOLLECTION_TEST_H + +#include + +class DavCollectionTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void createEmpty(); + void storeTest(); + void setTest(); + void copyTest(); +}; + +#endif diff --git a/autotests/davitemfetchjobtest.cpp b/autotests/davitemfetchjobtest.cpp new file mode 100644 index 0000000..46d0742 --- /dev/null +++ b/autotests/davitemfetchjobtest.cpp @@ -0,0 +1,54 @@ +/* + SPDX-FileCopyrightText: 2017 Sandro Knauß + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "davitemfetchjobtest.h" +#include "fakeserver.h" + +#include + +#include + +void DavItemFetchJobTest::initTestCase() +{ + // To avoid a runtime dependency on klauncher + qputenv("KDE_FORK_SLAVES", "yes"); + // To let ctest exit, we shouldn't start kio_http_cache_cleaner + qputenv("KIO_DISABLE_CACHE_CLEANER", "yes"); +} + +void DavItemFetchJobTest::runSuccessfullTest() +{ + FakeServer fakeServer(5989); + QUrl url(QStringLiteral("http://localhost/item")); + url.setPort(fakeServer.port()); + KDAV::DavUrl davUrl(url, KDAV::CardDav); + + KDAV::DavItem item(davUrl, QString(), QByteArray(), QString()); + + auto job = new KDAV::DavItemFetchJob(item); + + fakeServer.addScenarioFromFile(QLatin1String(AUTOTEST_DATA_DIR) + QStringLiteral("/dataitemfetchjob.txt")); + fakeServer.startAndWait(); + job->exec(); + + QVERIFY(fakeServer.isAllScenarioDone()); + QCOMPARE(job->error(), 0); + + QCOMPARE(item.data(), QByteArray()); + QCOMPARE(item.etag(), QString()); + QCOMPARE(item.contentType(), QString()); + + item = job->item(); + QByteArray data( + "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Kolab//iRony DAV Server 0.3.1//Sabre//Sabre VObject " + "2.1.7//EN\r\nUID:12345678-1234-1234-1234-123456789abc\r\nFN:John2 " + "Doe\r\nN:Doe;John2;;;\r\nEMAIL;TYPE=INTERNET;TYPE=HOME:john2.doe@example.com\r\nREV;VALUE=DATE-TIME:20170104T182647Z\r\nEND:VCARD\r\n"); + QCOMPARE(item.data(), data); + QCOMPARE(item.etag(), QStringLiteral("7a33141f192d904d-47")); + QCOMPARE(item.contentType(), QStringLiteral("text/x-vcard")); +} + +QTEST_MAIN(DavItemFetchJobTest) diff --git a/autotests/davitemfetchjobtest.h b/autotests/davitemfetchjobtest.h new file mode 100644 index 0000000..e86f016 --- /dev/null +++ b/autotests/davitemfetchjobtest.h @@ -0,0 +1,21 @@ +/* + SPDX-FileCopyrightText: 2017 Sandro Knauß + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef DAVITEMFETCHJOB_TEST_H +#define DAVITEMFETCHJOB_TEST_H + +#include + +class DavItemFetchJobTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void runSuccessfullTest(); +}; + +#endif diff --git a/autotests/davitemslistjobtest.cpp b/autotests/davitemslistjobtest.cpp new file mode 100644 index 0000000..41daeb5 --- /dev/null +++ b/autotests/davitemslistjobtest.cpp @@ -0,0 +1,33 @@ +/* + SPDX-FileCopyrightText: 2017 Sandro Knauß + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "davitemslistjobtest.h" +#include "fakeserver.h" + +#include +#include +#include +#include + +#include + +void DavItemsListJobTest::noMatchingMimetype() +{ + std::shared_ptr cache(new KDAV::EtagCache()); + + QUrl url(QStringLiteral("http://localhost/collection")); + KDAV::DavUrl davUrl(url, KDAV::CardDav); + KDAV::Error error(KDAV::ErrorNumber::ERR_ITEMLIST_NOMIMETYPE, 0, QString(), 0); + + auto job = new KDAV::DavItemsListJob(davUrl, cache); + job->setContentMimeTypes(QStringList() << QStringLiteral("mime/invalid1") << QStringLiteral("mime/invalid2")); + job->exec(); + + QCOMPARE(job->error(), static_cast(KDAV::ErrorNumber::ERR_ITEMLIST_NOMIMETYPE)); + QCOMPARE(job->errorText(), error.errorText()); +} + +QTEST_MAIN(DavItemsListJobTest) diff --git a/autotests/davitemslistjobtest.h b/autotests/davitemslistjobtest.h new file mode 100644 index 0000000..87fa092 --- /dev/null +++ b/autotests/davitemslistjobtest.h @@ -0,0 +1,20 @@ +/* + SPDX-FileCopyrightText: 2017 Sandro Knauß + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef DAVITEMSLISTJOB_TEST_H +#define DAVITEMSLISTJOB_TEST_H + +#include + +class DavItemsListJobTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void noMatchingMimetype(); +}; + +#endif diff --git a/autotests/davitemtest.cpp b/autotests/davitemtest.cpp new file mode 100644 index 0000000..7a17fb3 --- /dev/null +++ b/autotests/davitemtest.cpp @@ -0,0 +1,103 @@ +/* + SPDX-FileCopyrightText: 2017 Sandro Knauß + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "davitemtest.h" + +#include +#include + +#include +#include + +void DavItemTest::createEmpty() +{ + KDAV::DavItem davItem; + + QCOMPARE(davItem.url().toDisplayString(), QString()); + QCOMPARE(davItem.contentType(), QString()); + QCOMPARE(davItem.data(), QByteArray()); + QCOMPARE(davItem.etag(), QString()); +} + +void DavItemTest::storeTest() +{ + QUrl url(QStringLiteral("test://me:pw@test")); + KDAV::DavUrl davUrl(url, KDAV::CardDav); + KDAV::DavItem davItem(davUrl, QStringLiteral("text/test"), QByteArray("data"), QStringLiteral("991233434-234345")); + + QCOMPARE(davItem.url().protocol(), KDAV::CardDav); + QCOMPARE(davItem.contentType(), QStringLiteral("text/test")); + QCOMPARE(davItem.data(), QByteArray("data")); + QCOMPARE(davItem.etag(), QStringLiteral("991233434-234345")); +} + +void DavItemTest::setTest() +{ + QUrl url(QStringLiteral("test://me:pw@test")); + KDAV::DavUrl davUrl(url, KDAV::CardDav); + KDAV::DavItem davItem; + + davItem.setUrl(davUrl); + davItem.setContentType(QStringLiteral("text/test")); + davItem.setData(QByteArray("data")); + davItem.setEtag(QStringLiteral("991233434-234345")); + + QCOMPARE(davItem.url().protocol(), KDAV::CardDav); + QCOMPARE(davItem.contentType(), QStringLiteral("text/test")); + QCOMPARE(davItem.data(), QByteArray("data")); + QCOMPARE(davItem.etag(), QStringLiteral("991233434-234345")); +} + +void DavItemTest::copyTest() +{ + QUrl url(QStringLiteral("test://me:pw@test")); + KDAV::DavUrl davUrl(url, KDAV::CardDav); + KDAV::DavItem davItem(davUrl, QStringLiteral("text/test"), QByteArray("data"), QStringLiteral("991233434-234345")); + + KDAV::DavItem davItemCopy1(davItem); + QCOMPARE(davItemCopy1.url().protocol(), davItem.url().protocol()); + QCOMPARE(davItemCopy1.url().url(), davItem.url().url()); + QCOMPARE(davItemCopy1.contentType(), davItem.contentType()); + QCOMPARE(davItemCopy1.data(), davItem.data()); + QCOMPARE(davItemCopy1.etag(), davItem.etag()); + + KDAV::DavItem davItemCopy2; + davItemCopy2 = davItem; + QCOMPARE(davItemCopy2.url().protocol(), davItem.url().protocol()); + QCOMPARE(davItemCopy2.url().url(), davItem.url().url()); + QCOMPARE(davItemCopy2.contentType(), davItem.contentType()); + QCOMPARE(davItemCopy2.data(), davItem.data()); + QCOMPARE(davItemCopy2.etag(), davItem.etag()); +} + +void DavItemTest::serializeTest() +{ + KDAV::DavItem davItem1; + KDAV::DavItem davItem2; + + QUrl url(QStringLiteral("test://me:pw@test")); + KDAV::DavUrl davUrl(url, KDAV::CardDav); + + davItem1.setUrl(davUrl); + davItem1.setContentType(QStringLiteral("text/test")); + davItem1.setData(QByteArray("data")); + davItem1.setEtag(QStringLiteral("991233434-234345")); + + QByteArray data; + QDataStream s(&data, QIODevice::WriteOnly); + s << davItem1; + + QDataStream t(&data, QIODevice::ReadOnly); + t >> davItem2; + + QCOMPARE(davItem2.url().protocol(), davItem1.url().protocol()); + QCOMPARE(davItem2.url().url(), davItem1.url().url()); + QCOMPARE(davItem2.contentType(), davItem1.contentType()); + QCOMPARE(davItem2.data(), davItem1.data()); + QCOMPARE(davItem2.etag(), davItem1.etag()); +} + +QTEST_MAIN(DavItemTest) diff --git a/autotests/davitemtest.h b/autotests/davitemtest.h new file mode 100644 index 0000000..0ea589b --- /dev/null +++ b/autotests/davitemtest.h @@ -0,0 +1,25 @@ +/* + SPDX-FileCopyrightText: 2017 Sandro Knauß + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef DAVITEM_TEST_H +#define DAVITEM_TEST_H + +#include + +class DavItemTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void createEmpty(); + void storeTest(); + void setTest(); + void copyTest(); + + void serializeTest(); +}; + +#endif diff --git a/autotests/davurltest.cpp b/autotests/davurltest.cpp new file mode 100644 index 0000000..008003e --- /dev/null +++ b/autotests/davurltest.cpp @@ -0,0 +1,65 @@ +/* + SPDX-FileCopyrightText: 2017 Sandro Knauß + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "davurltest.h" + +#include + +#include +#include + +void DavUrlTest::createEmpty() +{ + KDAV::DavUrl davUrl; + + QCOMPARE(davUrl.protocol(), KDAV::CalDav); + QCOMPARE(davUrl.url(), QUrl()); +} + +void DavUrlTest::storeTest() +{ + QUrl url(QStringLiteral("test://me:pw@test")); + KDAV::DavUrl davUrl(url, KDAV::CardDav); + + QCOMPARE(davUrl.protocol(), KDAV::CardDav); + QCOMPARE(davUrl.url(), url); + QCOMPARE(davUrl.toDisplayString(), QStringLiteral("test://test")); +} + +void DavUrlTest::setTest() +{ + QUrl url(QStringLiteral("test://me:pw@test")); + KDAV::DavUrl davUrl; + + davUrl.setProtocol(KDAV::CardDav); + davUrl.setUrl(url); + + QCOMPARE(davUrl.protocol(), KDAV::CardDav); + QCOMPARE(davUrl.url(), url); + QCOMPARE(davUrl.toDisplayString(), QStringLiteral("test://test")); +} + +void DavUrlTest::serializeTest() +{ + KDAV::DavUrl davUrl1; + KDAV::DavUrl davUrl2; + + QUrl url(QStringLiteral("test://me:pw@test")); + davUrl1.setProtocol(KDAV::CardDav); + davUrl1.setUrl(url); + + QByteArray data; + QDataStream s(&data, QIODevice::WriteOnly); + s << davUrl1; + + QDataStream t(&data, QIODevice::ReadOnly); + t >> davUrl2; + + QCOMPARE(davUrl2.protocol(), davUrl1.protocol()); + QCOMPARE(davUrl2.url(), davUrl1.url()); +} + +QTEST_MAIN(DavUrlTest) diff --git a/autotests/davurltest.h b/autotests/davurltest.h new file mode 100644 index 0000000..ecc7624 --- /dev/null +++ b/autotests/davurltest.h @@ -0,0 +1,24 @@ +/* + SPDX-FileCopyrightText: 2017 Sandro Knauß + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef DAVURL_TEST_H +#define DAVURL_TEST_H + +#include + +class DavUrlTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void createEmpty(); + void storeTest(); + void setTest(); + + void serializeTest(); +}; + +#endif diff --git a/autotests/fakeserver.cpp b/autotests/fakeserver.cpp new file mode 100644 index 0000000..84ce022 --- /dev/null +++ b/autotests/fakeserver.cpp @@ -0,0 +1,219 @@ +/* + SPDX-FileCopyrightText: 2008 Omat Holding B .V. + SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB , a KDAB Group company + SPDX-FileContributor: Kevin Ottens + SPDX-FileCopyrightText: 2017 Sandro Kanuß + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +// Own +#include "fakeserver.h" + +// Qt +#include +#include +#include + +FakeServer::FakeServer(int port, QObject *parent) + : QObject(parent) + , m_thread(new QThread) + , m_port(port) +{ + moveToThread(m_thread); +} + +FakeServer::~FakeServer() +{ + QMetaObject::invokeMethod(this, &FakeServer::cleanup); + m_thread->quit(); + m_thread->wait(); + delete m_thread; +} + +void FakeServer::startAndWait() +{ + m_thread->start(); + // this will block until the init code happens and the event queue starts + QMetaObject::invokeMethod(this, &FakeServer::init, Qt::BlockingQueuedConnection); +} + +void FakeServer::dataAvailable() +{ + QMutexLocker locker(&m_mutex); + + QTcpSocket *socket = qobject_cast(sender()); + Q_ASSERT(socket != nullptr); + + int scenarioNumber = -1; + readClientPart(socket, &scenarioNumber); + if (scenarioNumber >= 0) { + Q_ASSERT(scenarioNumber < m_scenarios.count()); + writeServerPart(socket, scenarioNumber); + } +} + +void FakeServer::newConnection() +{ + QMutexLocker locker(&m_mutex); + + m_clientSockets << m_tcpServer->nextPendingConnection(); + connect(m_clientSockets.last(), &QTcpSocket::readyRead, this, &FakeServer::dataAvailable); +} + +void FakeServer::init() +{ + m_tcpServer = new QTcpServer(); + + if (!m_tcpServer->listen(QHostAddress(QHostAddress::LocalHost), m_port)) { + qFatal("Unable to start the server"); + } + + connect(m_tcpServer, &QTcpServer::newConnection, this, &FakeServer::newConnection); +} + +void FakeServer::cleanup() +{ + qDeleteAll(m_clientSockets); + delete m_tcpServer; +} + +void FakeServer::setScenario(const QList &scenario) +{ + QMutexLocker locker(&m_mutex); + + m_scenarios.clear(); + m_scenarios << scenario; +} + +void FakeServer::addScenario(const QList &scenario) +{ + QMutexLocker locker(&m_mutex); + + m_scenarios << scenario; +} + +void FakeServer::addScenarioFromFile(const QString &fileName) +{ + QFile file(fileName); + file.open(QIODevice::ReadOnly | QIODevice::Text); + + QList scenario; + + while (!file.atEnd()) { + scenario << file.readLine().trimmed(); + } + + file.close(); + + addScenario(scenario); +} + +bool FakeServer::isScenarioDone(int scenarioNumber) const +{ + QMutexLocker locker(&m_mutex); + + if (scenarioNumber < m_scenarios.size()) { + return m_scenarios[scenarioNumber].isEmpty(); + } else { + return true; // Non existent hence empty, right? + } +} + +bool FakeServer::isAllScenarioDone() const +{ + QMutexLocker locker(&m_mutex); + + for (const QList &scenario : std::as_const(m_scenarios)) { + if (!scenario.isEmpty()) { + return false; + } + } + + return true; +} + +void FakeServer::writeServerPart(QTcpSocket *clientSocket, int scenarioNumber) +{ + QList scenario = m_scenarios[scenarioNumber]; + + while (!scenario.isEmpty() && scenario.first().startsWith("S: ")) { + QByteArray rule = scenario.takeFirst(); + + QByteArray payload = rule.mid(3); + clientSocket->write(payload + "\r\n"); + } + + QByteArray data; + + while (!scenario.isEmpty() && scenario.first().startsWith("D: ")) { + QByteArray rule = scenario.takeFirst(); + + QByteArray payload = rule.mid(3); + data.append(payload + "\r\n"); + } + + clientSocket->write(QStringLiteral("Content-Length: %1\r\n\r\n").arg(data.length()).toLatin1()); + clientSocket->write(data); + + if (!scenario.isEmpty() && scenario.first().startsWith("X")) { + scenario.takeFirst(); + clientSocket->close(); + } + + if (!scenario.isEmpty()) { + QVERIFY(scenario.first().startsWith("C: ")); + } + + m_scenarios[scenarioNumber] = scenario; +} + +void FakeServer::readClientPart(QTcpSocket *socket, int *scenarioNumber) +{ + QByteArray line = socket->readLine(); + qDebug() << "Read client request" << line; + const auto it = std::find_if(m_scenarios.begin(), m_scenarios.end(), [&](const QList &scenario) { + return !scenario.isEmpty() && scenario.at(0).mid(3) + "\r\n" == line; + }); + if (it == m_scenarios.end()) { + qWarning() << "No server response available for" << line; + QFAIL("Unexpected request"); + return; + } + QList scenario = *it; + QVector header; + + while (line != "\r\n") { + header << line; + if (socket->bytesAvailable() == 0 && !socket->waitForReadyRead()) { + qDebug() << header; + QFAIL("could not read all headers"); + return; + } + line = socket->readLine(); + } + + while (!scenario.isEmpty() && scenario.first().startsWith("C: ")) { + QByteArray expected = scenario.takeFirst().mid(3) + "\r\n"; + + if (!header.contains(expected)) { + qWarning() << expected << "not found in header. Here's what we got:"; + qWarning() << header; + QVERIFY(false); + break; + } + } + + if (!scenario.isEmpty()) { + QVERIFY(scenario.first().startsWith("S: ")); + } + + *it = scenario; + *scenarioNumber = std::distance(m_scenarios.begin(), it); + QVERIFY(*scenarioNumber < m_scenarios.count()); +} + +int FakeServer::port() const +{ + return m_port; +} diff --git a/autotests/fakeserver.h b/autotests/fakeserver.h new file mode 100644 index 0000000..38cab61 --- /dev/null +++ b/autotests/fakeserver.h @@ -0,0 +1,177 @@ +/* + SPDX-FileCopyrightText: 2008 Omat Holding B .V. + SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB , a KDAB Group company + SPDX-FileContributor: Kevin Ottens + SPDX-FileCopyrightText: 2017 Sandro Kanuß + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#ifndef FAKESERVER_H +#define FAKESERVER_H + +#include +#include +#include +#include + +Q_DECLARE_METATYPE(QList) + +/** + * Pretends to be an DAV server for the purposes of unit tests. + * + * FakeServer does not really understand the DAV protocol. Instead, + * you give it a script, or scenario, that lists how an DAV session + * exchange should go. When it receives the client parts of the + * scenario, it will respond with the following server parts. + * + * The server can be furnished with several scenarios. The first + * scenario will be played out to the first client that connects, the + * second scenario to the second client connection and so on. + * + * The fake server runs as a separate thread in the same process it + * is started from, and listens for connections (see port() method) on the + * local machine. + * + * Scenarios are in the form of protocol messages, with a tag at the + * start to indicate whether it is message that will be sent by the + * client ("C: ") or a response that should be sent by the server + * ("S: "). Or ("D: ") for the exchanged data. Content-length header is added + * automatically with the current length and also the empty line between Header + * and Content. For example: + * @code + * C: GET /item HTTP/1.1 + * S: HTTP/1.0 200 OK + * D: much data + * D: more data + * X + * @endcode + * + * A line starting with X indicates that the connection should be + * closed by the server. This should be the last line in the + * scenario. + + * A typical usage is something like + * @code + * QList scenario; + * scenario << "C: GET /item HTTP/1.1" + * << "S: HTTP/1.0 200 OK" + * << "D: much data" + * << "D: more data" + * << "X"; + * + * FakeServer fakeServer; + * fakeServer.setScenario(scenario); + * fakeServer.startAndWait(); + * + * QUrl url(QStringLiteral("http://localhost/item")); + * url.setPort(fakeServer.port()); + * KDAV::DavUrl davUrl(url, KDAV::CardDav); + * KDAV::DavItem item(davUrl, QString(), QByteArray(), QString()); + * + * auto job = new KDAV::DavItemFetchJob(item); + * job->exec(); + * fakeServer.quit(); + * QVERIFY(fakeServer.isAllScenarioDone()); + * @endcode + */ + +class FakeServer : public QObject +{ + Q_OBJECT + +public: + /** + * Each unittest should use a different port so that they can be run in parallel + */ + FakeServer(int port = 5989, QObject *parent = nullptr); + ~FakeServer() override; + + /** + * Starts the server and waits for it to be ready + * + * You should use this instead of start() to avoid race conditions. + */ + void startAndWait(); + + /** + * Removes any previously-added scenarios, and adds a new one + * + * After this, there will only be one scenario, and so the fake + * server will only be able to service a single request. More + * scenarios can be added with addScenario, though. + * + * @see addScenario()\n + * addScenarioFromFile() + */ + void setScenario(const QList &scenario); + + /** + * Adds a new scenario + * + * Note that scenarios will be used in the order that clients + * connect. If this is the 5th scenario that has been added + * (bearing in mind that setScenario() resets the scenario + * count), it will be used to service the 5th client that + * connects. + * + * @see addScenarioFromFile() + * + * @param scenario the scenario as a list of messages + */ + void addScenario(const QList &scenario); + /** + * Adds a new scenario from a local file + * + * Note that scenarios will be used in the order that clients + * connect. If this is the 5th scenario that has been added + * (bearing in mind that setScenario() resets the scenario + * count), it will be used to service the 5th client that + * connects. + * + * @see addScenario() + * + * @param fileName the name of the file that contains the + * scenario; it will be split at line + * boundaries, and excess whitespace will + * be trimmed from the start and end of lines + */ + void addScenarioFromFile(const QString &fileName); + + /** + * Checks whether a particular scenario has completed + * + * @param scenarioNumber the number of the scenario to check, + * in order of addition/client connection + */ + bool isScenarioDone(int scenarioNumber) const; + /** + * Whether all the scenarios that were added to the fake + * server have been completed. + */ + bool isAllScenarioDone() const; + + /** + * Returns the port where the fake server is listening. + */ + int port() const; + +private Q_SLOTS: + void newConnection(); + void dataAvailable(); + void init(); + void cleanup(); + +private: + void writeServerPart(QTcpSocket *clientSocket, int scenarioNumber); + void readClientPart(QTcpSocket *socket, int *scenarioNumber); + + QList> m_scenarios; + QTcpServer *m_tcpServer = nullptr; + mutable QMutex m_mutex; + QList m_clientSockets; + QThread *m_thread; + int m_port; +}; + +#endif diff --git a/metainfo.yaml b/metainfo.yaml new file mode 100644 index 0000000..3596e12 --- /dev/null +++ b/metainfo.yaml @@ -0,0 +1,18 @@ +maintainer: +fancyname: KDAV +description: An DAV protocol implementation with KJobs +tier: 3 +type: functional +platforms: + - name: All +portingAid: false +deprecated: false +release: true +libraries: + - qmake: KDAV + cmake: "KF5::DAV" +cmakename: KF5DAV + +public_lib: true +group: Frameworks +subgroup: Tier 3 diff --git a/po/ar/libkdav.po b/po/ar/libkdav.po new file mode 100644 index 0000000..56a031a --- /dev/null +++ b/po/ar/libkdav.po @@ -0,0 +1,158 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Safa Alfulaij , 2018. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2018-01-31 22:49+0300\n" +"Last-Translator: Safa Alfulaij \n" +"Language-Team: Arabic \n" +"Language: ar\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " +"&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n" +"X-Generator: Lokalize 2.0\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "اسم المستخدم/كلمة السّرّ غير صالحة" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "النّفاذ ممنوع" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "لم يُعثر على المورد" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "خطأ HTTP" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"حدثت مشكلة بالطّلب.\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "لا يدعم ميفاق التّجميعات MULTIGET" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "واجه الخادوم خطأً منعه من إكمال الطّلب: %1 ‏(%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"حدثت مشكلة بالطّلب. لم تُحذف التّجميعة من الخادوم.\n" +"%1 (%2)." + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "ردود غير صالحة من السّند" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "خطأ في ضبط التّركيز على XQuery" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "أرسل تنفيذ DAV استعلام XQuery غير صالح" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"حدثت مشكلة بالطّلب. لم تُعدّل التّجميعة في الخادوم.\n" +"%1 (%2)." + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "لا خصائص لتغييرها أو إزالتها" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "حدث خطأ أثناء تعديل الخصائص" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"أعاد الخادوم معلومات أكثر:\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"حدثت مشكلة بالطّلب. لم يُنشأ العنصر في الخادوم.\n" +"%1 (%2)." + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"حدثت مشكلة بالطّلب. لم يُحذف العنصر من الخادوم.\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"حدثت مشكلة بالطّلب. لم يُعدّل العنصر في الخادوم.\n" +"%1 (%2)." + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "حدثت مشكلة بالطّلب." + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "حدثت مشكلة بالطّلب. أنواع MIME المطلوبة غير مدعومة." diff --git a/po/az/libkdav.po b/po/az/libkdav.po new file mode 100644 index 0000000..4469190 --- /dev/null +++ b/po/az/libkdav.po @@ -0,0 +1,159 @@ +# Copyright (C) YEAR This file is copyright: +# This file is distributed under the same license as the kdav package. +# +# Kheyyam Gojayev , 2021. +msgid "" +msgstr "" +"Project-Id-Version: kdav\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2021-02-08 17:35+0400\n" +"Last-Translator: Kheyyam Gojayev \n" +"Language-Team: Azerbaijani \n" +"Language: az\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Lokalize 20.12.2\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "İstifadəçi adı və ya şifrə səhvdir" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "Giriş qadağandır" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "Resurs tapılmadı" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "HTTP xətası" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"Tələb ilə bağlı problem var.\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "Kolleksiya üçün protokol MULTIGET dəstəkləmir" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" +"Server, sorğunuzun yerinə yetirməsinə mane olan bir səhvlə qarşılaşdı: %1 " +"(%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"Tələb ilə bağlı problem var. Bu kolleksiya serverdən silinə bilmədi\n" +"%1 (%2)." + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "Server tərəfdən səhv cavablar" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "XQuery üçün fokus qurulmasında xəta" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "DAV tətbiqi tərəfindən göndərilən etibarsız XQuery" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"Tələb ilə bağlı problem var. Bu kolleksiya serverdə dəyişdirilə bilmədi\n" +"%1 (%2)." + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "Dəyişdirmək və silmək xüsusiyyətlərinə malik deyil" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "Xüsusiyyətləri dəyişdirərkən xəta baş verdi" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"Server daha çox məlumat qaytardı:\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Tələb ilə bağlı problem var. Bu kolleksiya serverdə yaradıla bilmədi\n" +"%1 (%2)." + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"Tələb ilə bağlı problem var. Bu element serverdən silinə bilmədi\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Tələb ilə bağlı problem var. Bu element serverdə dəyişdirilə bilmədi\n" +"%1 (%2)." + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "Tələb ilə bağlı problem var." + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "Tələb ilə bağlı problem var. Tələb olunnan MİME növləri dəstəklənmədi." diff --git a/po/bg/libkdav.po b/po/bg/libkdav.po new file mode 100644 index 0000000..6a387df --- /dev/null +++ b/po/bg/libkdav.po @@ -0,0 +1,155 @@ +# Mincho Kondarev , 2022. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2022-05-20 18:59+0200\n" +"Last-Translator: Mincho Kondarev \n" +"Language-Team: Bulgarian \n" +"Language: bg\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 22.04.0\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "Невалидно потребителско име/парола" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "Достъпът е забранен" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "Ресурсът не е намерен" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "HTTP грешка" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"Имаше проблем със заявката.\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "Протоколът за колекцията не поддържа MULTIGET" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" +"Сървърът срещна грешка, която му попречи да завърши вашата заявка: %1 (%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"Имаше проблем със заявката. Колекцията не е изтрита от сървъра.\n" +"%1 (%2)." + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "Невалидни отговори от бекенда" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "Грешка при задаване на фокуса за XQuery" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "Невалиден XQuery, изпратен от внедряването на DAV" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"Имаше проблем със заявката. Колекцията не е модифицирана на сървъра.\n" +"%1 (%2)." + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "Няма свойства за промяна или премахване" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "При промяна на свойствата възникна грешка" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"Сървърът върна повече информация:\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Имаше проблем със заявката. Елементът не е създаден в сървър.\n" +"%1 (%2)." + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"Имаше проблем със заявката. Елементът не е изтрит от сървър.\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Имаше проблем със заявката. Артикулът не е модифициран на сървър.\n" +"%1 (%2)." + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "Имаше проблем със заявката." + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "Имаше проблем със заявката. Исканите MIME типове не се поддържат." diff --git a/po/ca/libkdav.po b/po/ca/libkdav.po new file mode 100644 index 0000000..c743c1d --- /dev/null +++ b/po/ca/libkdav.po @@ -0,0 +1,171 @@ +# Translation of libkdav.po to Catalan +# Copyright (C) 2009-2017 This_file_is_part_of_KDE +# This file is distributed under the license LGPL version 2.1 or +# version 3 or later versions approved by the membership of KDE e.V. +# +# Manuel Tortosa Moreno , 2009, 2010. +# Josep M. Ferrer , 2010, 2011, 2012, 2015, 2017. +# Antoni Bella Pérez , 2012, 2013, 2014, 2015, 2016, 2017. +msgid "" +msgstr "" +"Project-Id-Version: kdav\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2017-12-12 12:17+0100\n" +"Last-Translator: Antoni Bella Pérez \n" +"Language-Team: Catalan \n" +"Language: ca\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 2.0\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Accelerator-Marker: &\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "Nom d'usuari o contrasenya no vàlids" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "Accés prohibit" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "No s'ha trobat el recurs" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "Error d'HTTP" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"S'ha produït un problema amb la sol·licitud.\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "El protocol per a la col·lecció no permet MULTIGET" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" +"El servidor ha trobat un error que impedeix completar la vostra sol·licitud: " +"%1 (%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"S'ha produït un problema amb la sol·licitud. La col·lecció no ha estat " +"eliminada del servidor.\n" +"%1 (%2)." + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "Respostes no vàlides del dorsal" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "Error en establir el focus a XQuery" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "XQuery no vàlida enviada per la implementació DAV" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"S'ha produït un problema amb la sol·licitud. La col·lecció no ha estat " +"modificada en el servidor.\n" +"%1 (%2)." + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "No hi ha cap propietat a canviar o eliminar" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "S'ha produït un error en modificar les propietats" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"El servidor ha retornat més informació:\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"S'ha produït un problema amb la sol·licitud. L'element no ha estat creat en " +"el servidor.\n" +"%1 (%2)." + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"S'ha produït un problema amb la sol·licitud. L'element no ha estat eliminat " +"del servidor.\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"S'ha produït un problema amb la sol·licitud. L'element no ha estat modificat " +"en el servidor.\n" +"%1 (%2)." + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "S'ha produït un problema amb la sol·licitud." + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "" +"S'ha produït un problema amb la sol·licitud. Els tipus MIME requerits no " +"estan implementats." diff --git a/po/ca@valencia/libkdav.po b/po/ca@valencia/libkdav.po new file mode 100644 index 0000000..3b058a5 --- /dev/null +++ b/po/ca@valencia/libkdav.po @@ -0,0 +1,171 @@ +# Translation of libkdav.po to Catalan (Valencian) +# Copyright (C) 2009-2017 This_file_is_part_of_KDE +# This file is distributed under the license LGPL version 2.1 or +# version 3 or later versions approved by the membership of KDE e.V. +# +# Manuel Tortosa Moreno , 2009, 2010. +# Josep M. Ferrer , 2010, 2011, 2012, 2015, 2017. +# Antoni Bella Pérez , 2012, 2013, 2014, 2015, 2016, 2017. +msgid "" +msgstr "" +"Project-Id-Version: kdav\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2017-12-12 12:17+0100\n" +"Last-Translator: Antoni Bella Pérez \n" +"Language-Team: Catalan \n" +"Language: ca@valencia\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 2.0\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Accelerator-Marker: &\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "Nom d'usuari o contrasenya no vàlids" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "Accés prohibit" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "No s'ha trobat el recurs" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "S'ha produït un error d'HTTP" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"S'ha produït un problema amb la sol·licitud.\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "El protocol per a la col·lecció no permet MULTIGET" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" +"El servidor ha trobat un error que impedix completar la vostra sol·licitud: " +"%1 (%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"S'ha produït un problema amb la sol·licitud. La col·lecció no ha sigut " +"eliminada del servidor.\n" +"%1 (%2)." + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "Respostes no vàlides del dorsal" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "S'ha produït un error en establir el focus a XQuery" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "XQuery no vàlida enviada per la implementació DAV" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"S'ha produït un problema amb la sol·licitud. La col·lecció no ha sigut " +"modificada en el servidor.\n" +"%1 (%2)." + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "No hi ha cap propietat que s'haja de canviar o eliminar" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "S'ha produït un error en modificar les propietats" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"El servidor ha retornat més informació:\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"S'ha produït un problema amb la sol·licitud. L'element no ha sigut creat en " +"el servidor.\n" +"%1 (%2)." + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"S'ha produït un problema amb la sol·licitud. L'element no ha sigut eliminat " +"del servidor.\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"S'ha produït un problema amb la sol·licitud. L'element no ha sigut modificat " +"en el servidor.\n" +"%1 (%2)." + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "S'ha produït un problema amb la sol·licitud." + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "" +"S'ha produït un problema amb la sol·licitud. Els tipus MIME requerits no " +"estan implementats." diff --git a/po/cs/libkdav.po b/po/cs/libkdav.po new file mode 100644 index 0000000..d8c575e --- /dev/null +++ b/po/cs/libkdav.po @@ -0,0 +1,146 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# Vít Pelčák , 2010, 2011, 2013, 2016, 2017, 2018. +# Tomáš Chvátal , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2017-02-27 13:49+0100\n" +"Last-Translator: Vít Pelčák \n" +"Language-Team: Czech \n" +"Language: cs\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" +"X-Generator: Lokalize 2.0\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "Neplatné uživatelské jméno nebo heslo" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "Přístup zakázán" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "Zdroj nebyl nalezen" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "Chyba HTTP" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"Server navrátil více informací:\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "V požadavku nastal problém." + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "" diff --git a/po/de/libkdav.po b/po/de/libkdav.po new file mode 100644 index 0000000..0b22773 --- /dev/null +++ b/po/de/libkdav.po @@ -0,0 +1,168 @@ +# Burkhard Lück , 2009, 2011, 2013, 2014, 2015, 2017, 2018, 2020, 2021. +# Frederik Schwarzer , 2010, 2011, 2016, 2020. +# Panagiotis Papadopoulos , 2010. +# Peter Rüthemann , 2010. +# Torbjörn Klatt , 2011. +# Rolf Eike Beer , 2011. +msgid "" +msgstr "" +"Project-Id-Version: akonadi_davgroupware_resource\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2021-05-31 15:13+0200\n" +"Last-Translator: Burkhard Lück \n" +"Language-Team: German \n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "Ungültiger Benutzername/Passwort" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "Zugriff unzulässig" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "Die Ressource wurde nicht gefunden" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "HTTP-Fehler" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"Bei der Abfrage ist ein Problem aufgetreten\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "Das Protokoll für die Sammlung unterstützt MULTIGET nicht." + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" +"Der Server hat einen Fehler festgestellt, der die Fertigstellung Ihrer " +"Abfrage verhindert: %1 (%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"Bei der Abfrage ist ein Problem aufgetreten. Die Sammlung wurde nicht vom " +"Server gelöscht.\n" +"%1 (%2)." + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "Ungültige Antwort des Treibers" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "Fehler beim Bestimmen des Fokus für XQuery" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "DAV-Implementation hat ungültige XQuery übermittelt" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"Bei der Abfrage ist ein Problem aufgetreten. Die Sammlung wurde auf dem " +"Server nicht verändert.\n" +"%1 (%2)." + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "" +"Keine Eigenschaften vorhanden, die verändert oder gelöscht werden können." + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "Problem beim Anpassen der Eigenschaften" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"Der Server hat weitere Informationen zurückgegeben:\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Bei der Abfrage ist ein Problem aufgetreten. Der Eintrag wurde auf dem " +"Server nicht erstellt\n" +"%1 (%2)." + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"Bei der Abfrage ist ein Problem aufgetreten. Der Eintrag wurde nicht vom " +"Server gelöscht\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Bei der Abfrage ist ein Problem aufgetreten. Der Eintrag wurde auf dem " +"Server nicht verändert\n" +"%1 (%2)." + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "Bei der Abfrage ist ein Problem aufgetreten" + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "" +"Bei der Abfrage ist ein Problem aufgetreten. Die angeforderte MIME-Typen " +"werden nicht unterstützt." diff --git a/po/el/libkdav.po b/po/el/libkdav.po new file mode 100644 index 0000000..987d820 --- /dev/null +++ b/po/el/libkdav.po @@ -0,0 +1,165 @@ +# Copyright (C) YEAR This file is copyright: +# This file is distributed under the same license as the kdav package. +# +# Stelios , 2020. +msgid "" +msgstr "" +"Project-Id-Version: kdav\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2020-09-13 16:21+0300\n" +"Last-Translator: Stelios \n" +"Language-Team: Greek \n" +"Language: el\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 20.04.2\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "Μη έγκυρα όνομα χρήστη ή κωδικός πρόσβασης" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "Η πρόσβαση απαγορεύεται" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "Ο πόρος δε βρέθηκε" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "HTTP σφάλμα" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"Παρουσιάστηκε κάποιο πρόβλημα με την αίτηση.\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "Το πρωτόκολλο για τη συλλογή δεν υποστηρίζει MULTIGET" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" +"Ο εξυπηρετητής αντιμετώπισε κάποιο σφάλμα που τον εμπόδισε να ολοκληρώσει " +"την αίτησή σας: %1 (%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"Υπήρξε πρόβλημα με την αίτηση. Η συλλογή δεν έχει διαγραφεί από τον " +"εξυπηρετητή.\n" +"%1 (%2)." + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "Μη έγκυρες αποκρίσεις από το σύστημα υποστήριξης" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "Σφάλμα ρύθμισης της εστίασης για το XQuery" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "Μη έγκυρο XQuery υποβλήθηκε από DAV υλοποίηση" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"Υπήρξε πρόβλημα με την αίτηση. Η συλλογή δεν έχει τροποποιηθεί στον " +"εξυπηρετητή.\n" +"%1 (%2)." + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "Δεν υπάρχουν ιδιότητες για αλλαγή ή διαγραφή" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "Παρουσιάστηκε σφάλμα κατά την τροποποίηση των ιδιοτήτων" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"Ο εξυπηρετητής επίστρεψε και άλλη πληροφορία:\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Υπήρξε πρόβλημα με την αίτηση. Το αντικείμενο δεν έχει δημιουργηθεί στον " +"εξυπηρετητή.\n" +"%1 (%2)." + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"Υπήρξε πρόβλημα με την αίτηση. Το αντικείμενο δεν έχει διαγραφεί από τον " +"εξυπηρετητή.\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Υπήρξε πρόβλημα με την αίτηση. Το αντικείμενο δεν έχει τροποποιηθεί στον " +"εξυπηρετητή.\n" +"%1 (%2)." + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "Υπήρξε πρόβλημα με την αίτηση." + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "" +"Υπήρξε πρόβλημα με την αίτηση. Οι αιτούμενοι τύποι MIME δεν υποστηρίζονται." diff --git a/po/en_GB/libkdav.po b/po/en_GB/libkdav.po new file mode 100644 index 0000000..297e5ca --- /dev/null +++ b/po/en_GB/libkdav.po @@ -0,0 +1,166 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Steve Allewell , 2017. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2017-12-22 15:41+0000\n" +"Last-Translator: Steve Allewell \n" +"Language-Team: British English \n" +"Language: en_GB\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 2.0\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "Invalid username/password" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "Access forbidden" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "Resource not found" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "HTTP error" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"There was a problem with the request.\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "Protocol for the collection does not support MULTIGET" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "Invalid responses from backend" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "Error setting focus for XQuery" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "Invalid XQuery submitted by DAV implementation" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "No properties to change or remove" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "There was an error when modifying the properties" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"The server returned more information:\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "There was a problem with the request." + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "" +"There was a problem with the request. The requested MIME types are not " +"supported." diff --git a/po/es/libkdav.po b/po/es/libkdav.po new file mode 100644 index 0000000..8244afd --- /dev/null +++ b/po/es/libkdav.po @@ -0,0 +1,166 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2017-12-14 09:10+0100\n" +"Last-Translator: Javier Viñal \n" +"Language-Team: Spanish \n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 2.0.3\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "Usuario/contraseña inválidos" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "Acceso prohíbido" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "Recurso no encontrado" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "Error HTTP" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"Ha habido un problema con la petición.\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "El protocolo para la colección no implementa MULTIGET" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" +"El servidor encontró un error que le impide completar la petición: %1 (%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"Ha habido un problema con la petición. La colección no se ha borrado del " +"servidor.\n" +"%1 (%2)" + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "Respuesta inválida desde el motor" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "Error al establecer el foco para XQuery" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "XQuery inválido enviado por la implementación de DAV" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"Ha habido un problema con la petición. La colección no se ha modificado del " +"servidor.\n" +"%1 (%2)" + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "Ninguna propiedad que cambiar o eliminar" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "Ha habido un error al modificar las propiedades" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"El servidor ha devuelto más información:\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Ha habido un problema con la petición. El elemento no se ha creado en el " +"servidor.\n" +"%1 (%2)" + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"Ha habido un problema con la petición. El elemento no se ha borrado desde el " +"servidor.\n" +"%1 (%2)" + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Ha habido un problema con la petición. El elemento no se ha modificado en el " +"servidor.\n" +"%1 (%2)" + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "Ha habido un problema con la petición." + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "" +"Ha habido un problema con la petición. El tipo MIME solicitado no está " +"implementado." diff --git a/po/et/libkdav.po b/po/et/libkdav.po new file mode 100644 index 0000000..11ec05e --- /dev/null +++ b/po/et/libkdav.po @@ -0,0 +1,157 @@ +# Copyright (C) YEAR This file is copyright: +# This file is distributed under the same license as the kdav package. +# +# Marek Laane , 2019. +msgid "" +msgstr "" +"Project-Id-Version: kdav\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2019-11-16 21:51+0200\n" +"Last-Translator: Marek Laane \n" +"Language-Team: Estonian \n" +"Language: et\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 19.08.1\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "Vigane kasutajanimi/parool" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "Juurdepääs keelatud" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "Ressurssi ei leitud" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "HTTP tõrge" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"Päringuga tekkis probleem.\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "Kogumise protokollis ei ole MULTIGET toetatud" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "Serveris tekkis tõrge, mis takistas sinu päringu täitmist: %1 (%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"Päringuga tekkis probleem. Kogu ei ole serverist kustutatud.\n" +"%1 (%2)." + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "Vigased vastused taustaprogrammilt" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "Tõrge fookuse määramisel XQueryle" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "DAV-i teostus edastas vigase XQuery" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"Päringuga tekkis probleem. Kogu ei oldud serveris muudetud.\n" +"%1 (%2)." + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "Pole omadusi, mida muuta või eemaldada" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "Omaduste muutmisel tekkis tõrge" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"Server tagastas rohkem teavet:\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Päringuga tekkis probleem. Elementi ei ole serveris loodud.\n" +"%1 (%2)." + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"Päringuga tekkis probleem. Elementi ei ole serverist kustutatud.\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Päringuga tekkis probleem. Elementi ei oldud serveris muudetud.\n" +"%1 (%2)." + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "Päringuga tekkis probleem." + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "Päringuga tekkis probleem. Nõutavad MIME tüübid ei ole toetatud." diff --git a/po/eu/libkdav.po b/po/eu/libkdav.po new file mode 100644 index 0000000..8eda54c --- /dev/null +++ b/po/eu/libkdav.po @@ -0,0 +1,163 @@ +# Translation for libkdav.po to Euskara/Basque (eu). +# Copyright (C) 2021, This file is copyright: +# This file is distributed under the same license as the kdav package. +# KDE euskaratzeko proiektuko arduraduna . +# +# Translators: +# Iñigo Salvador Azurmendi , 2021. +msgid "" +msgstr "" +"Project-Id-Version: kdav\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2021-07-30 21:09+0200\n" +"Last-Translator: Iñigo Salvador Azurmendi \n" +"Language-Team: Basque \n" +"Language: eu\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Lokalize 21.04.3\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "Erabiltzaile-izen/pasahitz baliogabea" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "Sarrera debekatua" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "Baliabidea ez da aurkitu" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "HTTP errorea" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"Eskaerarekin arazo bat egon da.\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "Bildumarako protokoloak ez du MULTIGET onartzen" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" +"Zerbitzariak zure eskaria betetzea eragozten duen errore bat aurkitu du: %1 " +"(%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"Eskaerarekin arazo bat egon da. Bilduma ez da zerbitzaritik ezabatu.\n" +"%1 (%2)." + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "Bizkarraldekoaren erantzun baliogabeak" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "«XQuery»rako arreta ezartzeko errorea" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "DAV inplementazioak «XQuery» baliogabea bidali du " + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"Eskaerarekin arazo bat egon da. Bilduma ez da aldatu zerbitzarian.\n" +"%1 (%2)." + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "Ez dago aldatzeko edo kentzeko propietaterik" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "Errore bat gertatu da propietateak aldatzean" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"Zerbitzariak informazio gehiago itzuli du:\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Eskaerarekin arazo bat egon da. Elementua ez da sortu zerbitzarian.\n" +"%1 (%2)." + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"Eskaerarekin arazo bat egon da. Elementua ez da zerbitzaritik ezabatu.\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Eskaerarekin arazo bat egon da. Elementua ez da aldatu zerbitzarian.\n" +"%1 (%2)." + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "Eskaerarekin arazo bat egon da." + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "" +"Eskaerarekin arazo bat egon da. Eskatutako MIME-motak ez dira onartzen." diff --git a/po/fi/libkdav.po b/po/fi/libkdav.po new file mode 100644 index 0000000..4c15b3c --- /dev/null +++ b/po/fi/libkdav.po @@ -0,0 +1,164 @@ +# Copyright © 2011, 2012 This_file_is_part_of_KDE +# This file is distributed under the same license as the kdepim-runtime package. +# Tommi Nieminen , 2011, 2012, 2013, 2015, 2016, 2017. +# Lasse Liehu , 2012, 2013, 2014, 2015. +# Jiri Grönroos , 2012. +# +# KDE Finnish translation sprint participants: +# Author: Artnay +# Author: Lliehu +msgid "" +msgstr "" +"Project-Id-Version: akonadi_davgroupware_resource\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2017-12-25 20:33+0200\n" +"Last-Translator: Tommi Nieminen \n" +"Language-Team: Finnish \n" +"Language: fi\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-POT-Import-Date: 2012-12-01 22:24:46+0000\n" +"X-Generator: Lokalize 2.0\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "Virheellinen käyttäjätunnus tai salasana" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "Saanti estetty" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "Resurssia ei löydy" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "HTTP-virhe" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"Pyynnössä oli ongelmia.\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "Kokoelman yhteyskäytäntö ei tue MULTIGETiä" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" +"Palvelin kohtasi virheen, joka esti sitä toteuttamasta pyyntöäsi: %1 (%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"Pyynnössä oli ongelmia eikä kokoelmaa poistettu palvelimelta.\n" +"%1 (%2)." + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "Taustaosa vastaa virheellisesti" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "Virhe asetettaessa XQueryn kohdistusta" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "DAV-toteutus lähetti virheellisen XQueryn" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"Pyynnössä oli ongelmia eikä kokoelmaa muutettu palvelimella.\n" +"%1 (%2)." + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "Ei muutettavia tai poistettavia ominaisuuksia" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "Ominaisuuksia muutettaessa sattui virhe" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"Palvelin palautti lisätietoa:\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Pyynnössä oli ongelmia eikä merkintää luotu palvelimeen.\n" +"%1 (%2)." + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"Pyynnössä oli ongelmia eikä merkintää poistettu palvelimelta.\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Pyynnössä oli ongelmia eikä merkintää muutettu palvelimella.\n" +"%1 (%2)." + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "Pyynnössä oli ongelmia." + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "Pyynnössä oli ongelmia: pyydettyjä MIME-tyyppejä ei tueta." diff --git a/po/fr/libkdav.po b/po/fr/libkdav.po new file mode 100644 index 0000000..a92c401 --- /dev/null +++ b/po/fr/libkdav.po @@ -0,0 +1,175 @@ +# translation of akonadi_davgroupware_resource.po to Français +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# Guillaume Pujol , 2009, 2010. +# Geoffray Levasseur , 2012, 2013, 2014. +# xavier , 2013. +# Joëlle Cornavin , 2011. +# Sebastien Renard , 2013. +# Vincent Pinon , 2017, 2018. +# +msgid "" +msgstr "" +"Project-Id-Version: akonadi_davgroupware_resource\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2018-01-11 17:51+0100\n" +"Last-Translator: Vincent Pinon \n" +"Language-Team: French \n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 2.0\n" +"X-Environment: kde\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: kde4\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "Nom d'utilisateur ou mot de passe non valable" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "Accès refusé" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "Impossible de trouver la ressource" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "Erreur « HTTP »" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"Il y a eu un problème avec la requête.\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "Le protocole pour la collection ne prend pas en charge MULTIGET" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" +"Le serveur a rencontré une erreur l'empêchant de mener à bien votre " +"requête : %1 (%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"Il y a eu un problème avec la requête. La collection n'a pas été supprimée " +"du serveur.\n" +"%1 (%2)." + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "Réponses non valables provenant du moteur" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "Problème lors de la définition du focus pour « XQuery »" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "« XQuery » non valable soumise par l'implémentation de DAV" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"Il y a eu un problème avec la requête. La collection n'a pas été modifié sur " +"le serveur.\n" +"%1 (%2)." + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "Aucune propriété à modifier ou supprimer" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "Une erreur est survenue lors de la modification des propriétés" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"Le serveur a retourné plus d'informations :\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Il y a eu un problème avec la requête. L'élément n'a pas été créé sur le " +"serveur.\n" +"%1 (%2)." + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"Il y a eu un problème avec la requête. L'élément n'a pas été supprimé du " +"serveur.\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Il y a eu un problème avec la requête. L'élément n'a pas été modifié sur le " +"serveur.\n" +"%1 (%2)." + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "Il y a eu un problème avec la requête." + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "" +"Il y a eu un problème avec la requête. Les types MIME demandés ne sont pas " +"pris en charge." diff --git a/po/gl/libkdav.po b/po/gl/libkdav.po new file mode 100644 index 0000000..f1ee055 --- /dev/null +++ b/po/gl/libkdav.po @@ -0,0 +1,164 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# Xosé , 2009, 2010, 2013. +# Adrian Chaves Fernandez , 2013, 2015, 2017. +# Marce Villarino , 2014. +# Adrián Chaves (Gallaecio) , 2017, 2018, 2019. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2019-03-16 19:40+0100\n" +"Last-Translator: Adrián Chaves (Gallaecio) \n" +"Language-Team: Galician \n" +"Language: gl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "O nome de usuario ou o contrasinal son incorrectos" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "Denegouse o acceso" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "Non se atopou o recurso." + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "Erro de HTTP" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"Houbo un problema coa solicitude.\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "O protocolo da colección non admite MULTIGET" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" +"O servidor atopouse cun erro que evitou que realizase a súa solicitude: %1 " +"(%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"Produciuse un problema coa solicitude. A colección non se eliminou do " +"servidor.\n" +"%1 (%2)." + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "Responsas incorrectas da infraestrutura" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "Produciuse un erro ao configurar o foco de XQuery" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "A realización de DAV enviou unha XQuery incorrecta" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"Houbo un problema coa solicitude. A colección non se modificou no servidor.\n" +"%1 (%2)." + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "Non hai propiedades que cambiar ou retirar" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "Produciuse un erro ao modificar as propiedades." + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"O servidor devolveu máis información:\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Houbo un problema coa solicitude. O elemento non se creou no servidor.\n" +"%1 (%2)." + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"Houbo un problema coa solicitude. O elemento non se eliminou do servidor.\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Houbo un problema coa solicitude. O elemento non se modificou no servidor.\n" +"%1 (%2)." + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "Houbo un problema coa solicitude." + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "" +"Houbo un problema coa solicitude. O tipos MIME solicitados non son " +"compatíbeis." diff --git a/po/hi/libkdav.po b/po/hi/libkdav.po new file mode 100644 index 0000000..429a9b7 --- /dev/null +++ b/po/hi/libkdav.po @@ -0,0 +1,158 @@ +# Copyright (C) YEAR This file is copyright: +# This file is distributed under the same license as the kdav package. +# +# Sameer Singh , 2021. +# Raghavendra Kamath , 2021. +msgid "" +msgstr "" +"Project-Id-Version: kdav\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2021-06-27 10:10+0530\n" +"Last-Translator: Raghavendra Kamath \n" +"Language-Team: kde-hindi\n" +"Language: hi\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" +"X-Generator: Lokalize 21.04.2\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "अवैध उपयोक्ता नाम/कूटशब्द" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "प्रवेश निषेध" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "कोई संसाधन नहीं मिला" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "एचटीटीपी त्रुटि" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"याचिका में कोई समस्या थी।\n" +"%1 (%2) ।" + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "संग्रह का प्रोटोकॉल मल्टीगेट का समर्थन नहीं करता है।" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "सर्वर किसी समस्या के कारण आपकी याचिका को पूरा नहीं कर सका: %1 (%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"याचिका में कोई समस्या थी। संग्रह को सर्वर से हटा दिया गया है।\n" +"%1 (%2)।" + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "पृष्ठभाग से अवैध उत्तर" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "एक्सक्वैरी में फ़ोकस सेट करने में त्रुटि" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "डीएवी कार्यान्वयन ने अवैध एक्सक्वैरी प्रस्तुत की" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"याचिका में कोई समस्या थी। सर्वर में संग्रह का परिवर्तिन नहीं किया गया है।\n" +"%1 (%2)।" + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "कोई गुण परिवर्तिन या हटाने के लिए नहीं है" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "गुणों को परिवर्तित करते समय त्रुटि हुई" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"सर्वर नें अतिरिक्त जानकारी प्रदान की है:\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"याचिका में कोई समस्या थी। वस्तु सर्वर में सृजित नहीं की गई।\n" +"%1 (%2)।" + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"याचिका में कोई समस्या थी। वस्तु सर्वर से हटाई नहीं गई।\n" +"%1 (%2)।" + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"याचिका में कोई समस्या थी। वस्तु सर्वर में परिवर्तित नहीं हुई।\n" +"%1 (%2)।" + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "याचिका में कोई समस्या थी।" + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "याचिका में कोई समस्या थी। प्राथित माईम प्रकार समर्थित नहीं हैं।" diff --git a/po/ia/libkdav.po b/po/ia/libkdav.po new file mode 100644 index 0000000..e004ad4 --- /dev/null +++ b/po/ia/libkdav.po @@ -0,0 +1,166 @@ +# Copyright (C) YEAR This file is copyright: +# This file is distributed under the same license as the kdav package. +# +# giovanni , 2020. +msgid "" +msgstr "" +"Project-Id-Version: kdav\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2020-02-12 14:05+0100\n" +"Last-Translator: giovanni \n" +"Language-Team: Interlingua \n" +"Language: ia\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 18.12.3\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "Invalide nomine de usator / contrasigno" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "Accesso prohibite" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "Il non trovava ressource" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "Error HTTP" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"Il habeva un problema con le requesta.\n" +" %1(%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "Le protocollo pro le collection non supporta MULTIGET" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" +"Le servitor incontrava un error que impediva ex completar tu requesta: %1 " +"(%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"Il habeva un problema con le requesta. Le collection non ha essite delite ex " +"le servitor.\n" +"%1 (%2)." + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "Responsas invalide ex retro-administration" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "Error durante que il fixava foco per XQuery" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "XQuery invalide submittite per implementation de DAV" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"Il habeva un problema con le requesta. Le collection non ha essite " +"modificate sur le servitor \n" +" %1 (%2)" + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "Nulle proprietates de modificar o remover" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "Il haveba un error durante que on modificava le proprietates" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"Le servitor retornava plure de information:\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Il habeva un problema con le requesta. Le elemento non ha essite create sur " +"le servitor.\n" +"%1 (%2)." + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"Il habeva un problema con le requesta. Le elemento non ha essite delite ex " +"le servitor.\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Il habeva un problema con le requesta. Le elemento non esseva modificate sur " +"le servitor.\n" +"%1 (%2)." + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "Il habeva un problema con le requesta." + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "" +"Il habeva un problema con le requesta. Le requirite typos MIME non es " +"supportate." diff --git a/po/it/libkdav.po b/po/it/libkdav.po new file mode 100644 index 0000000..b5344a4 --- /dev/null +++ b/po/it/libkdav.po @@ -0,0 +1,158 @@ +# translation of akonadi_davgroupware_resource.po to Italian +# +# Vincenzo Reale , 2009, 2010. +# Nicola Ruggero , 2010, 2011. +# Luigi Toscano , 2012, 2013, 2014, 2015, 2016, 2017. +msgid "" +msgstr "" +"Project-Id-Version: akonadi_davgroupware_resource\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2017-12-14 21:04+0100\n" +"Last-Translator: Luigi Toscano \n" +"Language-Team: Italian \n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Lokalize 2.0\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "Username o password non validi" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "Accesso vietato" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "Risorsa non trovata" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "Errore HTTP" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"Problema con la richiesta.\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "Il protocollo della collezione non supporta MULTIGET" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "Errore nel server. Impossibile completare la richiesta: %1 (%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"Problema con la richiesta. La collezione non è stata eliminata dal server.\n" +"%1 (%2)." + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "Risposta non valida dal backend" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "Errore impostando il fuoco su XQuery" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "XQuery non valida inviata dall'implementazione DAV" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"Problema con la richiesta. La collezione non è stata modificata sul server.\n" +"%1 (%2)." + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "Nessuna proprietà da cambiare o rimuovere" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "Errore nella modifica delle proprietà" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"Il server ha fornito ulteriori informazioni:\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Problema con la richiesta. L'elemento non è stato creato sul server.\n" +"%1 (%2)." + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"Problema con la richiesta. L'elemento non è stato eliminato dal server.\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Problema con la richiesta. L'elemento non è stato modificato sul server.\n" +"%1 (%2)." + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "Problema con la richiesta." + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "Problema con la richiesta. I tipi MIME richiesti non sono supportati." diff --git a/po/ja/libkdav.po b/po/ja/libkdav.po new file mode 100644 index 0000000..9417f51 --- /dev/null +++ b/po/ja/libkdav.po @@ -0,0 +1,139 @@ +msgid "" +msgstr "" +"Project-Id-Version: akonadi_davcalendar_resource\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2009-11-04 20:48+0900\n" +"Last-Translator: Japanese KDE translation team \n" +"Language-Team: Japanese \n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: kde4\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "" + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "" diff --git a/po/ka/libkdav.po b/po/ka/libkdav.po new file mode 100644 index 0000000..a1bcbcc --- /dev/null +++ b/po/ka/libkdav.po @@ -0,0 +1,158 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR This file is copyright: +# This file is distributed under the same license as the kdav package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: kdav\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2022-05-22 06:20+0200\n" +"Last-Translator: Temuri Doghonadze \n" +"Language-Team: Georgian \n" +"Language: ka\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Poedit 3.0.1\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "მომხმარებელი ან პაროლი არასწორია" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "წვდომა აკრძალულია" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "რესურსი ნაპოვნი არაა" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "HTTP შეცდომა" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"მოთხოვნის პრობლემა.\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "კოლექციის პროტოკოლს MULTIGET-ს მხარდაჭერა არ გააჩნია" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "სერვერის შეცდომა. შედეგად მოთხოვნა არ შესრულებულა: %1 (%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"მოთხოვნის პრობლემა. კოლექცია სერვერიდან არ წაშლილა.\n" +"%1 (%2)" + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "უკანაბოლოს არასწორი პასუხი" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "XQuery-ის ფოკუსის დაყენების შეცდომა" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "DAV-ის იმპლემენტაციის მიერ გადმოცემული XQuery არასწორია" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"მოთხოვნის პრობლემა. კოლექცია სერვერზე არ შეცვლილა.\n" +"%1 (%2)" + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "შესაცვლელი ან წასაშლელი თვსებები ნაპოვნი არაა" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "შეცდომა თვისებების შეცვლისას" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"მეტი ინფორმაციისთვის იხილეთ:\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"მოთხოვნის პრობლემა. სერვერზე ჩანაწერი არ გაკეთებულა.\n" +"%1 (%2)." + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"მოთხოვნის პრობლემა. ჩანაწერი სერვერიდან არ წაშლილა.\n" +"%1 (%2)" + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"მოთხოვნის პრობლემა. სერვერზე ჩანაწერი არ შეცვლილა.\n" +"%1 (%2)." + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "მოთხოვნის პრობლემა." + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "მოთხოვნის პრობლემა. მითითებული MIME ტიპები მხარდაჭერილი არაა." diff --git a/po/ko/libkdav.po b/po/ko/libkdav.po new file mode 100644 index 0000000..b9c096e --- /dev/null +++ b/po/ko/libkdav.po @@ -0,0 +1,157 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# Shinjo Park , 2013, 2014, 2015, 2016, 2017, 2018. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2018-08-15 12:26+0100\n" +"Last-Translator: Shinjo Park \n" +"Language-Team: Korean \n" +"Language: ko\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Lokalize 2.0\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "잘못된 사용자 이름 및 암호" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "접근 거부됨" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "자원을 찾을 수 없음" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "HTTP 오류" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"요청에 문제가 있습니다.\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "모음집에 대한 프로토콜이 MULTIGET을 지원하지 않음" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "서버에서 요청을 처리할 수 없는 오류가 발생했습니다: %1(%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"요청에 문제가 있습니다. 서버에서 모음집이 삭제되지 않았습니다:\n" +"%1 (%2)." + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "백엔드에서 잘못된 응답이 돌아옴" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "XQuery 초점 설정 오류" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "DAV 구현에서 잘못된 XQuery를 보냄" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"요청에 문제가 있습니다. 서버에서 모음집이 수정되지 않았습니다:\n" +"%1 (%2)." + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "변경하거나 삭제할 속성 없음" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "속성을 수정하는 중 오류가 발생함" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"서버에서 부가 정보를 돌려 줌:\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"요청에 문제가 있습니다. 서버에서 모음집이 생성되지 않았습니다:\n" +"%1 (%2)." + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"요청에 문제가 있습니다. 서버에서 항목이 삭제되지 않았습니다:\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"요청에 문제가 있습니다. 서버에서 항목이 수정되지 않았습니다:\n" +"%1 (%2)." + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "요청에 문제가 있습니다." + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "요청에 문제가 있습니다. 지정한 MIME 형식을 지원하지 않습니다." diff --git a/po/lt/libkdav.po b/po/lt/libkdav.po new file mode 100644 index 0000000..d579a50 --- /dev/null +++ b/po/lt/libkdav.po @@ -0,0 +1,143 @@ +# Lithuanian translations for kdav package. +# Copyright (C) 2019 This file is copyright: +# This file is distributed under the same license as the kdav package. +# Automatically generated, 2019. +# +msgid "" +msgstr "" +"Project-Id-Version: kdav\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2018-08-16 09:12+0200\n" +"Last-Translator: Automatically generated\n" +"Language-Team: lt\n" +"Language: lt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : n%10>=2 && (n%100<10 || n" +"%100>=20) ? 1 : n%10==0 || (n%100>10 && n%100<20) ? 2 : 3);\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "" + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "" diff --git a/po/nb/libkdav.po b/po/nb/libkdav.po new file mode 100644 index 0000000..8a7e095 --- /dev/null +++ b/po/nb/libkdav.po @@ -0,0 +1,158 @@ +# Translation of libkdav to Norwegian BokmÃ¥l +# +# Bjørn Steensrud , 2010, 2011, 2013, 2014. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2014-09-19 22:47+0200\n" +"Last-Translator: Bjørn Steensrud \n" +"Language-Team: Norwegian BokmÃ¥l \n" +"Language: nb\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.5\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Environment: kde\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: kde4\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "Ugyldig brukernavn/passord" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "Adgang forbudt" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "Fant ikke ressurs" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "HTTP-feil" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"Det var et problem med forespørselen.\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "Protokollen for samlingen støtter ikke MULTIGET" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"Det var et problem med forespørselen. Samlingen er ikke slettet fra " +"tjeneren.\n" +"%1 (%2)." + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "Ugyldige svar fra bakgrunnsmotor" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "Feil ved fokussetting for XQuery" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "Ugyldig XQuery sendt inn av DAV-implementasjon" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "Ingen egenskaper som skal endres eller fjernes" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "Det oppsto en feil ved endring av egenskapene" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Det var et problem med forespørselen. Elementet er ikke opprettet pÃ¥ " +"tjeneren.\n" +"%1 (%2)." + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"Det var et problem med forespørselen. Elementet er ikke slettet fra " +"tjeneren.\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Det var et problem med forespørselen. Elementet ble ikke endret pÃ¥ " +"tjeneren.\n" +"%1 (%2)." + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "" + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "" diff --git a/po/nl/libkdav.po b/po/nl/libkdav.po new file mode 100644 index 0000000..93e9745 --- /dev/null +++ b/po/nl/libkdav.po @@ -0,0 +1,166 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Freek de Kruijf , 2017. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2017-12-12 22:49+0100\n" +"Last-Translator: Freek de Kruijf \n" +"Language-Team: Dutch \n" +"Language: nl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 2.0\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "Ongeldige gebruikersnaam/wachtwoord" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "Toegang verboden" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "Hulpbron niet gevonden" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "HTTP-fout" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"Er was een probleem met het verzoek.\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "Protocol voor de verzameling ondersteunt geen MULTIGET" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" +"De server kwam een fout tegen, waardoor deze uw verzoek niet kon afhandelen: " +"%1 (%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"Er was een probleem met het verzoek. De verzameling is niet van de server " +"verwijderd.\n" +"%1 (%2)." + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "Ongeldige antwoorden van backend" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "Fout bij het instellen van de focus voor XQuery" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "Ongeldige Xquery ingediend door DAV-implementatie" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"Er was een probleem met het verzoek. De verzameling is niet gewijzigd op de " +"server.\n" +"%1 (%2)." + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "Er zijn geen eigenschappen te wijzigen of te verwijderen" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "Er trad een fout op bij het wijzigen van de eigenschappen" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"De server gaf meer informatie terug:\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Er was een probleem met het verzoek. Het item is niet aangemaakt op de " +"server\n" +"%1 (%2)." + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"Er was een probleem met het verzoek. Het item is niet van de server " +"verwijderd.\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Er was een probleem met het verzoek. Het item is niet gewijzigd op de " +"server.\n" +"%1 (%2)." + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "Er was een probleem met het verzoek." + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "" +"Er was een probleem met het verzoek. De gevraagde MIME-typen worden niet " +"ondersteund." diff --git a/po/nn/libkdav.po b/po/nn/libkdav.po new file mode 100644 index 0000000..9b4f2f4 --- /dev/null +++ b/po/nn/libkdav.po @@ -0,0 +1,163 @@ +# Translation of libkdav to Norwegian Nynorsk +# +# Karl Ove Hufthammer , 2020. +msgid "" +msgstr "" +"Project-Id-Version: kdepim-runtime\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2020-10-24 14:20+0200\n" +"Last-Translator: Karl Ove Hufthammer \n" +"Language-Team: Norwegian Nynorsk \n" +"Language: nn\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 20.08.2\n" +"X-Environment: kde\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: kde4\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "Ugyldig brukarnamn/passord" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "Nekta tilgang" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "Fann ikkje ressursen" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "HTTP-feil" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"Det var problem med førespurnaden.\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "Protokoll for samlinga støttar ikkje MULTIGET" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" +"Tenaren støytte pÃ¥ ein feil som hindra han i Ã¥ fullføra førespurnaden: %1 " +"(%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"Det var problem med førespurnaden. Samlinga er ikkje sletta frÃ¥ tenaren.\n" +"%1 (%2)." + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "Ugyldig svar frÃ¥ bakgrunnsmotoren" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "Feil ved fokusval for XQuery" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "Ugyldig XQuery send av DAV-implementasjon" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"Det var problem med førespurnaden. Samlinga er ikkje endra pÃ¥ tenaren.\n" +"%1 (%2)." + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "Ingen eigenskapar Ã¥ endra eller fjerna" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "Det oppstod ein feil ved endring av eigenskapar" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"Tenaren returnerte meir informasjon:\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Det var problem med førespurnaden. Elementet er ikkje oppretta pÃ¥ tenaren.\n" +"%1 (%2)." + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"Det var problem med førespurnaden. Elementet er ikkje sletta frÃ¥ tenaren.\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Det var problem med førespurnaden. Elementet er ikkje endra pÃ¥ tenaren.\n" +"%1 (%2)." + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "Det var problem med førespurnaden." + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "" +"Det var problem med førespurnaden. Dei førespurde MIME-typane er ikkje " +"støtta." diff --git a/po/pl/libkdav.po b/po/pl/libkdav.po new file mode 100644 index 0000000..ac1a41d --- /dev/null +++ b/po/pl/libkdav.po @@ -0,0 +1,159 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Łukasz Wojniłowicz , 2018. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2018-01-28 06:08+0100\n" +"Last-Translator: Łukasz Wojniłowicz \n" +"Language-Team: Polish \n" +"Language: pl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " +"|| n%100>=20) ? 1 : 2);\n" +"X-Generator: Lokalize 2.0\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "Nieprawidłowa nazwa użytkownika/hasło" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "Dostęp wzbroniony" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "Nie znaleziono zasobu" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "Błąd HTTP" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"Wystąpił problem z żądaniem\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "Protokół dla zbioru nie obsługuje MULTIGET" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" +"Serwer napotkał błąd który uniemożliwił spełnienie twojego żądania: %1 (%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"Wystąpił problem z żądaniem. Zbiór nie został usunięty z serwera.\n" +"%1 (%2)." + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "Nieprawidłowa odpowiedź z modułu obsługi" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "Błąd ustawiania ostrości dla XQuery" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "Nieprawidłowe XQuery wykonane przez DAV" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"Wystąpił problem z żądaniem. Zbiór nie został zmieniony na serwerze.\n" +"%1 (%2)." + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "Nie ma właściwości, aby zmienić lub usunąć" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "Wystąpił błąd w trakcje zmiany właściwości" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"Serwer zwrócił więcej informacji:\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Wystąpił problem z żądaniem. Element nie został stworzona na serwerze.\n" +" %1 (%2)." + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"Wystąpił problem z żądaniem. Element nie został usunięty na serwerze.\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Wystąpił problem z żądaniem. Element nie został zmieniony na serwerze.\n" +"%1 (%2)." + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "Wystąpił problem z żądaniem." + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "Wystąpił problem z żądaniem. Żądane typy MIME nie są obsługiwane." diff --git a/po/pt/libkdav.po b/po/pt/libkdav.po new file mode 100644 index 0000000..18452c6 --- /dev/null +++ b/po/pt/libkdav.po @@ -0,0 +1,156 @@ +msgid "" +msgstr "" +"Project-Id-Version: libkdav\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2017-12-04 11:32+0000\n" +"Last-Translator: José Nuno Coelho Pires \n" +"Language-Team: Portuguese \n" +"Language: pt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-POFile-SpellExtra: XQuery MULTIGET DAV\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "Utilizador/senha inválidos" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "Acesso proibido" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "Recurso não encontrado" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "Erro de HTTP" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"Ocorreu um problema com o pedido.\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "O protocolo da colecção não suporta o MULTIGET" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" +"O servidor encontrou um erro que o impediu de terminar o seu pedido: %1 (%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"Ocorreu um problema com o pedido. A colecção não foi apagada no servidor.\n" +"%1 (%2)." + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "Foi obtida uma resposta inválida da infra-estrutura" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "Ocorreu um erro na atribuição do XQuery" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "Foi enviado um pedido de XQuery inválido pela implementação do DAV" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"Ocorreu um problema com o pedido. A colecção não foi modificada no " +"servidor.\n" +"%1 (%2)." + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "Não existem propriedades para alterar ou remover" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "Ocorreu um erro ao modificar as propriedades" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"O servidor devolveu mais informações:\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Ocorreu um problema com o pedido - O item não foi criado no servidor.\n" +"%1 (%2)." + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"Ocorreu um problema com o pedido - o item não foi apagado no servidor.\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Ocorreu um problema com o pedido. O item não foi modificado no servidor.\n" +"%1 (%2)." + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "Ocorreu um problema com o pedido." + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "" +"Ocorreu um problema com o pedido. Os tipos MIME pedidos não são suportados." diff --git a/po/pt_BR/libkdav.po b/po/pt_BR/libkdav.po new file mode 100644 index 0000000..8c6689e --- /dev/null +++ b/po/pt_BR/libkdav.po @@ -0,0 +1,166 @@ +# Translation of libkdav.po to Brazilian Portuguese +# Copyright (C) 2018 This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# André Marcelo Alvarenga , 2018. +msgid "" +msgstr "" +"Project-Id-Version: libkdav\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2018-07-24 22:45-0300\n" +"Last-Translator: André Marcelo Alvarenga \n" +"Language-Team: Brazilian Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 2.0\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "Usuário/senha inválidos" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "Acesso proibido" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "Recurso não encontrado" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "Erro de HTTP" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"Ocorreu um problema com a solicitação.\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "O protocolo da coleção não tem suporte ao MULTIGET" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" +"O servidor encontrou um erro que o impediu de concluir a sua solicitação: %1 " +"(%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"Ocorreu um problema com a solicitação. A coleção não foi excluída no " +"servidor.\n" +"%1 (%2)." + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "Foi obtida uma resposta inválida da infraestrutura" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "Ocorreu um erro na configuração do XQuery" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "" +"Foi enviada uma solicitação de XQuery inválida pela implementação do DAV" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"Ocorreu um problema com a solicitação. A coleção não foi modificada no " +"servidor.\n" +"%1 (%2)." + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "Nenhuma propriedade para alterar ou remover" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "Ocorreu um erro ao modificar as propriedades" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"O servidor retornou mais informações:\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Ocorreu um problema com a solicitação. O item não foi criado no servidor.\n" +"%1 (%2)." + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"Ocorreu um problema com a solicitação. O item não foi excluído no servidor.\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Ocorreu um problema com a solicitação. O item não foi modificado no " +"servidor.\n" +"%1 (%2)." + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "Ocorreu um problema com a solicitação." + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "" +"Ocorreu um problema com a solicitação. Não há suporte para os tipos MIME " +"solicitados." diff --git a/po/ro/libkdav.po b/po/ro/libkdav.po new file mode 100644 index 0000000..2c63467 --- /dev/null +++ b/po/ro/libkdav.po @@ -0,0 +1,161 @@ +# Copyright (C) YEAR This file is copyright: +# This file is distributed under the same license as the kdepim-runtime package. +# Sergiu Bivol , 2020. +# +msgid "" +msgstr "" +"Project-Id-Version: kdepim-runtime\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2020-09-27 12:44+0100\n" +"Last-Translator: Sergiu Bivol \n" +"Language-Team: Romanian\n" +"Language: ro\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < " +"20)) ? 1 : 2;\n" +"X-Generator: Lokalize 19.12.3\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "Utilizator/parolă nevalide" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "Acces interzis" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "Resursa nu a fost găsită" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "Eroare HTTP" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"A apărut o problemă cu cererea.\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "Protocolul pentru colecție nu susține MULTIGET" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" +"Serverul a întâmpinat o eroare ce l-a împiedicat să vă completeze cererea: " +"%1 (%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"A apărut o problemă cu cererea. Colecția nu a fost ștearsă de pe server.\n" +"%1 (%2)." + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "Răspunsuri nevalide de la platformă" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "Eroare la stabilirea focalizării pentru XQuery" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "XQuery nevalid transmis de implementarea DAV" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"A apărut o problemă cu cererea. Colecția nu a fost modificată pe server.\n" +"%1 (%2)." + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "Nu sunt proprietăți de schimbat sau eliminat" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "A apărut o eroare la modificarea proprietăților" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"Serverul a întors mai multă informație:\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"A apărut o problemă cu cererea. Elementul nu a fost creat pe server.\n" +"%1 (%2)." + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"A apărut o problemă cu cererea. Elementul nu a fost șters de pe server.\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"A apărut o problemă cu cererea. Elementul nu a fost modificat pe server.\n" +"%1 (%2)." + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "A apărut o problemă cu cererea." + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "" +"A apărut o problemă cu cererea. Tipurile MIME cerute nu sunt susținute." diff --git a/po/ru/libkdav.po b/po/ru/libkdav.po new file mode 100644 index 0000000..fb20c35 --- /dev/null +++ b/po/ru/libkdav.po @@ -0,0 +1,165 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Alexander Potashev , 2017. +# Alexander Yavorsky , 2018. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2018-07-16 21:52+0300\n" +"Last-Translator: Alexander Yavorsky \n" +"Language-Team: Russian \n" +"Language: ru\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n" +"%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Generator: Lokalize 2.0\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "Неправильное имя пользователя или пароль" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "Доступ запрещён" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "Ресурс не найден" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "Ошибка HTTP" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"При выполнении запроса произошла ошибка.\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "Протокол для этой коллекции не поддерживает MULTIGET." + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" +"На сервере произошла ошибка, из-за чего он не смог завершить выполнение " +"запроса: %1 (%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"При выполнении запроса произошла ошибка. Коллекция не была удалена с " +"сервера.\n" +"%1 (%2)." + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "Неверный ответ сервера" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "Ошибка установки фокуса для XQuery" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "Неверный XQuery, представленный реализацией DAV" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"При выполнении запроса произошла ошибка. Коллекция не была изменена на " +"сервере.\n" +"%1 (%2)." + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "Нет свойств для изменения или удаления" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "При изменении свойств произошла ошибка" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"Сервер вернул расширенные сведения:\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"При выполнении запроса произошла ошибка. Объект не был создан на сервере.\n" +"%1 (%2)." + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"При выполнении запроса произошла ошибка. Объект не был удалён с сервера.\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"При выполнении запроса произошла ошибка. Объект не был изменён на сервере.\n" +"%1 (%2)." + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "При выполнении запроса произошла ошибка." + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "" +"При выполнении запроса произошла ошибка. Запрошенные типы MIME не " +"поддерживаются." diff --git a/po/sk/libkdav.po b/po/sk/libkdav.po new file mode 100644 index 0000000..a500125 --- /dev/null +++ b/po/sk/libkdav.po @@ -0,0 +1,158 @@ +# translation of libkdav.po to Slovak +# Roman Paholík , 2017. +# Matej Mrenica , 2022. +msgid "" +msgstr "" +"Project-Id-Version: libkdav\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2022-02-14 19:47+0100\n" +"Last-Translator: Matej Mrenica \n" +"Language-Team: Slovak \n" +"Language: sk\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 21.12.2\n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "Neplatné užívateľské meno/heslo" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "Prístup zamietnutý" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "Zdroj nenájdený" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "HTTP chyba" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"Bol problém s požiadavkou.\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "Protokol pre kolekciu nepodporuje MULTIGET" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" +"Nastala chyba servera, ktorá znemožnila vykonaÅ¥ vaÅ¡u požiadavku: %1 (%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"Nastala chyba s požiadavkou. Kolekcia nebola vymazaná zo servera.\n" +"%1 (%2)." + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "Neplatná odpoveď z backendu" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "Chyba nastavenia zamerania na XQuery" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "Neplatná XQuery poslaná implementáciou DAV" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"Nastala chyba s požiadavkou. Položka nebola zmenená na serveri.\n" +"%1 (%2)." + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "Žiadne vlastnosti na zmenu alebo odstránenie" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "Nastala chyba počas zmeny vlastností" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"Server vrátil viac informácií:\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Nastala chyba s požiadavkou. Položka nebola vytvorená na serveri.\n" +"%1 (%2)." + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"Nastala chyba s požiadavkou. Položka nebola vymazaná zo servera.\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Nastala chyba s požiadavkou. Položka nebola zmenená na serveri.\n" +"%1 (%2)." + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "Bol problém s požiadavkou." + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "" +"Vyskytol sa problém so žiadosÅ¥ou. Požadované typy MIME nie sú podporované." diff --git a/po/sl/libkdav.po b/po/sl/libkdav.po new file mode 100644 index 0000000..eae3bab --- /dev/null +++ b/po/sl/libkdav.po @@ -0,0 +1,161 @@ +# Copyright (C) YEAR This file is copyright: +# This file is distributed under the same license as the kdav package. +# +# Matjaž Jeran , 2020. +msgid "" +msgstr "" +"Project-Id-Version: kdav\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2020-06-09 07:29+0200\n" +"Last-Translator: Matjaž Jeran \n" +"Language-Team: Slovenian \n" +"Language: sl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 19.12.2\n" +"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n" +"%100==4 ? 3 : 0);\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "Neveljavno uporabniÅ¡ko ime/geslo" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "Dostop prepovedan" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "Vira ni mogoče najti" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "Napaka HTTP" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"Problem pri zahtevku.\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "Protokol za zbiranje ne podpira MULTIGET" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" +"Strežnik je naletel na napako, ki mu je preprečila dokončanje vaÅ¡ega " +"zahtevka: %1 (%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"Pri zahtevku je priÅ¡lo do težave. Zbirka ni bila izbrisana s strežnika.\n" +"%1 (%2)." + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "Neveljavni odzivi iz zaledja" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "Napaka pri postavitvi osredotočenja na XQuery" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "Neveljavna poizvedba XQuery, poslana iz implementacije DAV" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"Pri zahtevku je priÅ¡lo do težave. Zbirka ni na strežniku bila spremenjena.\n" +"%1 (%2)." + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "Ni lastnosti za spremembo ali odstranitev" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "Pri spreminjanju lastnosti je priÅ¡lo do napake" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"Strežnik je vrnil več informacij:\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Pri zahtevku je priÅ¡lo do težave. Na strežniku ni bilo ustvarjenega " +"elementa.\n" +"%1 (%2)." + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"Pri zahtevku je priÅ¡lo do težave. Na strežniku element ni bil izbrisan.\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Pri zahtevku je priÅ¡lo do težave. Na strežniku element ni bil spremenjen.\n" +"%1 (%2)." + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "Pri zahtevku je priÅ¡lo do težave." + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "Pri zahtevku je priÅ¡lo do težave. Zahtevane vrste Mime niso podprte." diff --git a/po/sr/libkdav.po b/po/sr/libkdav.po new file mode 100644 index 0000000..f42439d --- /dev/null +++ b/po/sr/libkdav.po @@ -0,0 +1,159 @@ +# Translation of libkdav.po into Serbian. +# Chusslove Illich , 2011, 2013, 2014, 2015, 2016, 2017. +msgid "" +msgstr "" +"Project-Id-Version: libkdav\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2020-04-06 03:29+0200\n" +"PO-Revision-Date: 2017-12-17 18:01+0100\n" +"Last-Translator: Chusslove Illich \n" +"Language-Team: Serbian \n" +"Language: sr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n" +"%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: kde4\n" +"X-Environment: kde\n" + +#: common/daverror.cpp:87 +#, kde-format +msgid "Invalid username/password" +msgstr "Лоше корисничко име или лозинка" + +#: common/daverror.cpp:89 +#, kde-format +msgid "Access forbidden" +msgstr "Приступ забрањен" + +#: common/daverror.cpp:91 +#, kde-format +msgid "Resource not found" +msgstr "Ресурс није нађен" + +#: common/daverror.cpp:93 +#, kde-format +msgid "HTTP error" +msgstr "ХТТП грешка" + +#: common/daverror.cpp:95 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"Дошло је до проблема са захтевом.\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "Протокол за збирке не подржава MULTIGET." + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" +"Сервер је наишао на грешку која га је спречила да доврши ваш захтев: %1 (%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"Дошло је до проблема са захтевом. Збирка није обрисана са сервера.\n" +"%1 (%2)." + +#: common/daverror.cpp:109 +#, kde-format +msgid "Invalid responses from backend" +msgstr "Неисправни одговори из позадине." + +#: common/daverror.cpp:112 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "Грешка у постављању фокуса за икс‑упит." + +#: common/daverror.cpp:115 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "Изведба ДАВ‑а предала је лош икс‑упит." + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"Дошло је до проблема са захтевом. Збирка није измењена на серверу.\n" +"%1 (%2)." + +#: common/daverror.cpp:122 +#, kde-format +msgid "No properties to change or remove" +msgstr "Нема својстава за мењање или уклањање." + +#: common/daverror.cpp:125 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "Грешка при мењању својстава." + +#: common/daverror.cpp:127 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"Сервер је вратио још података:\n" +"%1" + +#: common/daverror.cpp:131 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Дошло је до проблема са захтевом. Ставка није створена на серверу.\n" +"%1 (%2)." + +#: common/daverror.cpp:135 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"Дошло је до проблема са захтевом. Ставка није обрисана са сервера.\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Дошло је до проблема са захтевом, ставка није измењена на серверу.\n" +"%1 (%2)." + +#: common/daverror.cpp:144 +#, kde-format +msgid "There was a problem with the request." +msgstr "Дошло је до проблема са захтевом." + +#: common/daverror.cpp:148 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "Дошло је до проблема са захтевом. Тражени МИМЕ типови нису подржани." diff --git a/po/sr@ijekavian/libkdav.po b/po/sr@ijekavian/libkdav.po new file mode 100644 index 0000000..7ee5d14 --- /dev/null +++ b/po/sr@ijekavian/libkdav.po @@ -0,0 +1,159 @@ +# Translation of libkdav.po into Serbian. +# Chusslove Illich , 2011, 2013, 2014, 2015, 2016, 2017. +msgid "" +msgstr "" +"Project-Id-Version: libkdav\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2020-04-06 03:29+0200\n" +"PO-Revision-Date: 2017-12-17 18:01+0100\n" +"Last-Translator: Chusslove Illich \n" +"Language-Team: Serbian \n" +"Language: sr@ijekavian\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n" +"%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: kde4\n" +"X-Environment: kde\n" + +#: common/daverror.cpp:87 +#, kde-format +msgid "Invalid username/password" +msgstr "Лоше корисничко име или лозинка" + +#: common/daverror.cpp:89 +#, kde-format +msgid "Access forbidden" +msgstr "Приступ забрањен" + +#: common/daverror.cpp:91 +#, kde-format +msgid "Resource not found" +msgstr "Ресурс није нађен" + +#: common/daverror.cpp:93 +#, kde-format +msgid "HTTP error" +msgstr "ХТТП грешка" + +#: common/daverror.cpp:95 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"Дошло је до проблема са захтевом.\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "Протокол за збирке не подржава MULTIGET." + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" +"Сервер је наишао на грешку која га је спречила да доврши ваш захтев: %1 (%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"Дошло је до проблема са захтевом. Збирка није обрисана са сервера.\n" +"%1 (%2)." + +#: common/daverror.cpp:109 +#, kde-format +msgid "Invalid responses from backend" +msgstr "Неисправни одговори из позадине." + +#: common/daverror.cpp:112 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "Грешка у постављању фокуса за икс‑упит." + +#: common/daverror.cpp:115 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "Изведба ДАВ‑а предала је лош икс‑упит." + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"Дошло је до проблема са захтевом. Збирка није измењена на серверу.\n" +"%1 (%2)." + +#: common/daverror.cpp:122 +#, kde-format +msgid "No properties to change or remove" +msgstr "Нема својстава за мењање или уклањање." + +#: common/daverror.cpp:125 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "Грешка при мењању својстава." + +#: common/daverror.cpp:127 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"Сервер је вратио још података:\n" +"%1" + +#: common/daverror.cpp:131 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Дошло је до проблема са захтевом. Ставка није створена на серверу.\n" +"%1 (%2)." + +#: common/daverror.cpp:135 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"Дошло је до проблема са захтевом. Ставка није обрисана са сервера.\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Дошло је до проблема са захтевом, ставка није измењена на серверу.\n" +"%1 (%2)." + +#: common/daverror.cpp:144 +#, kde-format +msgid "There was a problem with the request." +msgstr "Дошло је до проблема са захтевом." + +#: common/daverror.cpp:148 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "Дошло је до проблема са захтевом. Тражени МИМЕ типови нису подржани." diff --git a/po/sr@ijekavianlatin/libkdav.po b/po/sr@ijekavianlatin/libkdav.po new file mode 100644 index 0000000..931dd52 --- /dev/null +++ b/po/sr@ijekavianlatin/libkdav.po @@ -0,0 +1,159 @@ +# Translation of libkdav.po into Serbian. +# Chusslove Illich , 2011, 2013, 2014, 2015, 2016, 2017. +msgid "" +msgstr "" +"Project-Id-Version: libkdav\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2020-04-06 03:29+0200\n" +"PO-Revision-Date: 2017-12-17 18:01+0100\n" +"Last-Translator: Chusslove Illich \n" +"Language-Team: Serbian \n" +"Language: sr@ijekavianlatin\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n" +"%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: kde4\n" +"X-Environment: kde\n" + +#: common/daverror.cpp:87 +#, kde-format +msgid "Invalid username/password" +msgstr "LoÅ¡e korisničko ime ili lozinka" + +#: common/daverror.cpp:89 +#, kde-format +msgid "Access forbidden" +msgstr "Pristup zabranjen" + +#: common/daverror.cpp:91 +#, kde-format +msgid "Resource not found" +msgstr "Resurs nije nađen" + +#: common/daverror.cpp:93 +#, kde-format +msgid "HTTP error" +msgstr "HTTP greÅ¡ka" + +#: common/daverror.cpp:95 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"DoÅ¡lo je do problema sa zahtevom.\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "Protokol za zbirke ne podržava MULTIGET." + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" +"Server je naiÅ¡ao na greÅ¡ku koja ga je sprečila da dovrÅ¡i vaÅ¡ zahtev: %1 (%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"DoÅ¡lo je do problema sa zahtevom. Zbirka nije obrisana sa servera.\n" +"%1 (%2)." + +#: common/daverror.cpp:109 +#, kde-format +msgid "Invalid responses from backend" +msgstr "Neispravni odgovori iz pozadine." + +#: common/daverror.cpp:112 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "GreÅ¡ka u postavljanju fokusa za XQuery." + +#: common/daverror.cpp:115 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "Izvedba DAV‑a predala je loÅ¡ XQuery." + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"DoÅ¡lo je do problema sa zahtevom. Zbirka nije izmenjena na serveru.\n" +"%1 (%2)." + +#: common/daverror.cpp:122 +#, kde-format +msgid "No properties to change or remove" +msgstr "Nema svojstava za menjanje ili uklanjanje." + +#: common/daverror.cpp:125 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "GreÅ¡ka pri menjanju svojstava." + +#: common/daverror.cpp:127 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"Server je vratio joÅ¡ podataka:\n" +"%1" + +#: common/daverror.cpp:131 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"DoÅ¡lo je do problema sa zahtevom. Stavka nije stvorena na serveru.\n" +"%1 (%2)." + +#: common/daverror.cpp:135 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"DoÅ¡lo je do problema sa zahtevom. Stavka nije obrisana sa servera.\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"DoÅ¡lo je do problema sa zahtevom, stavka nije izmenjena na serveru.\n" +"%1 (%2)." + +#: common/daverror.cpp:144 +#, kde-format +msgid "There was a problem with the request." +msgstr "DoÅ¡lo je do problema sa zahtevom." + +#: common/daverror.cpp:148 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "DoÅ¡lo je do problema sa zahtevom. Traženi MIME tipovi nisu podržani." diff --git a/po/sr@latin/libkdav.po b/po/sr@latin/libkdav.po new file mode 100644 index 0000000..df490d4 --- /dev/null +++ b/po/sr@latin/libkdav.po @@ -0,0 +1,159 @@ +# Translation of libkdav.po into Serbian. +# Chusslove Illich , 2011, 2013, 2014, 2015, 2016, 2017. +msgid "" +msgstr "" +"Project-Id-Version: libkdav\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2020-04-06 03:29+0200\n" +"PO-Revision-Date: 2017-12-17 18:01+0100\n" +"Last-Translator: Chusslove Illich \n" +"Language-Team: Serbian \n" +"Language: sr@latin\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n" +"%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: kde4\n" +"X-Environment: kde\n" + +#: common/daverror.cpp:87 +#, kde-format +msgid "Invalid username/password" +msgstr "LoÅ¡e korisničko ime ili lozinka" + +#: common/daverror.cpp:89 +#, kde-format +msgid "Access forbidden" +msgstr "Pristup zabranjen" + +#: common/daverror.cpp:91 +#, kde-format +msgid "Resource not found" +msgstr "Resurs nije nađen" + +#: common/daverror.cpp:93 +#, kde-format +msgid "HTTP error" +msgstr "HTTP greÅ¡ka" + +#: common/daverror.cpp:95 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"DoÅ¡lo je do problema sa zahtevom.\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "Protokol za zbirke ne podržava MULTIGET." + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" +"Server je naiÅ¡ao na greÅ¡ku koja ga je sprečila da dovrÅ¡i vaÅ¡ zahtev: %1 (%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"DoÅ¡lo je do problema sa zahtevom. Zbirka nije obrisana sa servera.\n" +"%1 (%2)." + +#: common/daverror.cpp:109 +#, kde-format +msgid "Invalid responses from backend" +msgstr "Neispravni odgovori iz pozadine." + +#: common/daverror.cpp:112 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "GreÅ¡ka u postavljanju fokusa za XQuery." + +#: common/daverror.cpp:115 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "Izvedba DAV‑a predala je loÅ¡ XQuery." + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"DoÅ¡lo je do problema sa zahtevom. Zbirka nije izmenjena na serveru.\n" +"%1 (%2)." + +#: common/daverror.cpp:122 +#, kde-format +msgid "No properties to change or remove" +msgstr "Nema svojstava za menjanje ili uklanjanje." + +#: common/daverror.cpp:125 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "GreÅ¡ka pri menjanju svojstava." + +#: common/daverror.cpp:127 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"Server je vratio joÅ¡ podataka:\n" +"%1" + +#: common/daverror.cpp:131 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"DoÅ¡lo je do problema sa zahtevom. Stavka nije stvorena na serveru.\n" +"%1 (%2)." + +#: common/daverror.cpp:135 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"DoÅ¡lo je do problema sa zahtevom. Stavka nije obrisana sa servera.\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"DoÅ¡lo je do problema sa zahtevom, stavka nije izmenjena na serveru.\n" +"%1 (%2)." + +#: common/daverror.cpp:144 +#, kde-format +msgid "There was a problem with the request." +msgstr "DoÅ¡lo je do problema sa zahtevom." + +#: common/daverror.cpp:148 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "DoÅ¡lo je do problema sa zahtevom. Traženi MIME tipovi nisu podržani." diff --git a/po/sv/libkdav.po b/po/sv/libkdav.po new file mode 100644 index 0000000..ae49d7c --- /dev/null +++ b/po/sv/libkdav.po @@ -0,0 +1,161 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Stefan Asserhäll , 2017. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2017-12-12 19:37+0100\n" +"Last-Translator: Stefan Asserhäll \n" +"Language-Team: Swedish \n" +"Language: sv\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 2.0\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "Ogiltigt användarnamn eller lösenord" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "Åtkomst nekas" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "Resurs hittades inte" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "HTTP-fel" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"Ett problem uppstod med begäran.\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "Protokoll för samlingen stöder inte MULTIGET" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" +"Servern rÃ¥kade ut för ett fel som förhindrade den att färdigställa din " +"begäran: %1 (%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"Ett problem uppstod med begäran. Samlingen har inte tagits bort frÃ¥n " +"servern.\n" +"%1 (%2)." + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "Felaktigt svar frÃ¥n gränssnitt" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "Fel när fokus skulle ställas in för XQuery" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "Felaktig XQuery skickades av DAV-implementering" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"Ett problem uppstod med begäran. Samlingen har inte ändrats pÃ¥ servern.\n" +"%1 (%2)." + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "Inga egenskaper att ändra eller ta bort" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "Ett fel uppstod när egenskaperna skulle ändras" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"Servern returnerade mer information:\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Ett problem uppstod med begäran. Objektet har inte skapats pÃ¥ servern.\n" +"%1 (%2)." + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"Ett problem uppstod med begäran. Objektet har inte tagits bort frÃ¥n " +"servern.\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Ett problem uppstod med begäran. Objektet ändrades inte pÃ¥ servern.\n" +"%1 (%2)." + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "Ett problem uppstod med begäran." + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "Ett problem uppstod med begäran. De begärda Mime-typerna stöds inte." diff --git a/po/tr/libkdav.po b/po/tr/libkdav.po new file mode 100644 index 0000000..1a067f4 --- /dev/null +++ b/po/tr/libkdav.po @@ -0,0 +1,158 @@ +# Copyright (C) YEAR This file is copyright: +# This file is distributed under the same license as the kdav package. +# +# Emir SARI , 2022. +msgid "" +msgstr "" +"Project-Id-Version: kdav\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2022-03-18 23:21+0300\n" +"Last-Translator: Emir SARI \n" +"Language-Team: Turkish \n" +"Language: tr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.12.3\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "Geçersiz kullanıcı adı/parola" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "Erişim engellendi" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "Özkaynak bulunamadı" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "HTTP hatası" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"İstekte bir sorun oluştu.\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "Koleksiyon protokolü MULTIGET desteklemiyor" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" +"Sunucu, isteğinizin tamamlanmasını engelleyen bir hatayla karşılaştı: %1 (%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"İstekte bir sorun oluştu. Koleksiyon sunucudan silinmedi.\n" +"%1 (%2)." + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "Arka uçtan geçersiz yanıt" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "XQuery için odak ayarlanırken hata" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "DAV uygulaması tarafından sağlanan geçersiz XQuery" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"İstekte bir sorun oluştu. Koleksiyon, sunucuda değiştirilmedi.\n" +"%1 (%2)." + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "Değiştirilecek veya kaldırılacak özellik yok" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "Özellikleri değiştirirken bir hata oluştu" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"Sunucu ek bilgi döndürdü:\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"İstekte bir sorun oluştu. Öge, sunucuda oluşturulmadı.\n" +"%1 (%2)." + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"İstekte bir sorun oluştu. Öge, sunucuda silinmedi.\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"İstekte bir sorun oluştu. Öge, sunucuda değiştirilmedi.\n" +"%1 (%2)." + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "İstekte bir sorun oluştu." + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "İstekte bir sorun oluştu. İstenen MIME türleri desteklenmiyor." diff --git a/po/uk/libkdav.po b/po/uk/libkdav.po new file mode 100644 index 0000000..4b6dd82 --- /dev/null +++ b/po/uk/libkdav.po @@ -0,0 +1,169 @@ +# Translation of libkdav.po to Ukrainian +# Copyright (C) 2017 This_file_is_part_of_KDE +# This file is distributed under the license LGPL version 2.1 or +# version 3 or later versions approved by the membership of KDE e.V. +# +# Yuri Chornoivan , 2017. +msgid "" +msgstr "" +"Project-Id-Version: libkdav\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2017-12-12 08:38+0200\n" +"Last-Translator: Yuri Chornoivan \n" +"Language-Team: Ukrainian \n" +"Language: uk\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n" +"%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Generator: Lokalize 2.0\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "Некоректне ім’я користувача чи пароль" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "Доступ заборонено" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "Ресурс не знайдено" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "Помилка HTTP" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" +"Під час виконання запиту виникла проблема.\n" +"%1 (%2)." + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "У протоколі для роботи з цією збіркою не передбачено команди MULTIGET" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" +"На сервері сталася помилка, через яку він не зміг завершити виконання вашого " +"запиту: %1 (%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"Під час виконання запиту виникла проблема. Збірку на сервері не було " +"вилучено.\n" +"%1 (%2)." + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "Отримано некоректні відповіді сервера" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "Помилка під час спроби встановлення фокусу для XQuery" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "Реалізацією DAV було надіслано некоректні дані XQuery" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"Під час виконання запиту виникла проблема. Збірку на сервері не було " +"змінено.\n" +"%1 (%2)." + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "Немає властивостей для зміни або вилучення" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "Під час спроби зміни властивостей сталася помилка" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"Сервером було повернуто додаткову інформацію:\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Під час виконання запиту виникла проблема. Запис на сервері не було " +"створено.\n" +"%1 (%2)." + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"Під час виконання запиту виникла проблема. Запис на сервері не було " +"вилучено.\n" +"%1 (%2)." + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"Під час виконання запиту виникла проблема. Запис на сервері не було " +"змінено.\n" +"%1 (%2)." + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "Під час виконання запиту виникла проблема." + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "" +"Під час виконання запиту виникла проблема. Підтримки потрібних вам типів " +"MIME не передбачено." diff --git a/po/zh_CN/libkdav.po b/po/zh_CN/libkdav.po new file mode 100644 index 0000000..6b9cb89 --- /dev/null +++ b/po/zh_CN/libkdav.po @@ -0,0 +1,155 @@ +msgid "" +msgstr "" +"Project-Id-Version: kdeorg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: 2022-07-30 15:54\n" +"Last-Translator: \n" +"Language-Team: Chinese Simplified\n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Crowdin-Project: kdeorg\n" +"X-Crowdin-Project-ID: 269464\n" +"X-Crowdin-Language: zh-CN\n" +"X-Crowdin-File: /kf5-trunk/messages/kdav/libkdav.pot\n" +"X-Crowdin-File-ID: 6689\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "无效的用户名或密码" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "禁止访问" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "找不到资源" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "HTTP 错误" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "请求出错。\\n%1 (%2)。" + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "集合的协议不支持 MULTIGET" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "服务器出现错误,无法完成您的请求:%1 (%2)" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" +"请求出错。服务器上的项目未删除。\n" +"%1 (%2)。" + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "无效的后端应答" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "设置 XQuery 焦点时发生错误" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "DAV 实现提交了无效的 XQuery" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" +"请求出错。服务器上的项目未修改。\n" +"%1 (%2)。" + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "没有要更改或删除的属性" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "修改属性时出错" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" +"\n" +"服务器返回更多信息:\n" +"%1" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" +"请求出错。服务器上的项目未创建。\n" +"%1 (%2)。" + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" +"请求出错。服务器上的项目未删除。\n" +"%1 (%2)。" + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" +"请求出错。服务器上的项目未修改。\n" +"%1 (%2)。" + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "请求出错。" + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "请求出错。服务器上的项目未创建。" diff --git a/po/zh_TW/libkdav.po b/po/zh_TW/libkdav.po new file mode 100644 index 0000000..3b4a74e --- /dev/null +++ b/po/zh_TW/libkdav.po @@ -0,0 +1,142 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR This file is copyright: +# This file is distributed under the same license as the kdav package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: kdav\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2021-03-09 02:40+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Chinese \n" +"Language: zh_TW\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: common/daverror.cpp:88 +#, kde-format +msgid "Invalid username/password" +msgstr "" + +#: common/daverror.cpp:90 +#, kde-format +msgid "Access forbidden" +msgstr "" + +#: common/daverror.cpp:92 +#, kde-format +msgid "Resource not found" +msgstr "" + +#: common/daverror.cpp:94 +#, kde-format +msgid "HTTP error" +msgstr "" + +#: common/daverror.cpp:96 +#, kde-format +msgid "" +"There was a problem with the request.\n" +"%1 (%2)." +msgstr "" + +#: common/daverror.cpp:99 +#, kde-format +msgid "Protocol for the collection does not support MULTIGET" +msgstr "" + +#: common/daverror.cpp:102 +#, kde-format +msgid "" +"The server encountered an error that prevented it from completing your " +"request: %1 (%2)" +msgstr "" + +#: common/daverror.cpp:105 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been deleted " +"from the server.\n" +"%1 (%2)." +msgstr "" + +#: common/daverror.cpp:108 +#, kde-format +msgid "Invalid responses from backend" +msgstr "" + +#: common/daverror.cpp:111 +#, kde-format +msgid "Error setting focus for XQuery" +msgstr "" + +#: common/daverror.cpp:114 +#, kde-format +msgid "Invalid XQuery submitted by DAV implementation" +msgstr "" + +#: common/daverror.cpp:118 +#, kde-format +msgid "" +"There was a problem with the request. The collection has not been modified " +"on the server.\n" +"%1 (%2)." +msgstr "" + +#: common/daverror.cpp:124 +#, kde-format +msgid "No properties to change or remove" +msgstr "" + +#: common/daverror.cpp:127 +#, kde-format +msgid "There was an error when modifying the properties" +msgstr "" + +#: common/daverror.cpp:129 +#, kde-format +msgid "" +"\n" +"The server returned more information:\n" +"%1" +msgstr "" + +#: common/daverror.cpp:133 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been created on the " +"server.\n" +"%1 (%2)." +msgstr "" + +#: common/daverror.cpp:136 +#, kde-format +msgid "" +"There was a problem with the request. The item has not been deleted from the " +"server.\n" +"%1 (%2)." +msgstr "" + +#: common/daverror.cpp:139 +#, kde-format +msgid "" +"There was a problem with the request. The item was not modified on the " +"server.\n" +"%1 (%2)." +msgstr "" + +#: common/daverror.cpp:142 +#, kde-format +msgid "There was a problem with the request." +msgstr "" + +#: common/daverror.cpp:146 +#, kde-format +msgid "" +"There was a problem with the request. The requested MIME types are not " +"supported." +msgstr "" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..2f01108 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,190 @@ +add_definitions(-DTRANSLATION_DOMAIN=\"libkdav\") + +set(KDAV_INSTALL_INCLUDEDIR "${KDE_INSTALL_INCLUDEDIR_KF}/KDAV") + +add_library(KF5DAV) +add_library(KF5::DAV ALIAS KF5DAV) + +set_target_properties(KF5DAV PROPERTIES + VERSION ${KDAV_VERSION} + SOVERSION ${KDAV_SOVERSION} + EXPORT_NAME DAV +) + +target_sources(KF5DAV PRIVATE + common/davcollection.cpp + common/davcollectiondeletejob.cpp + common/davcollectiondeletejob.h + common/davcollection.h + common/davcollectionmodifyjob.cpp + common/davcollectionmodifyjob.h + common/davcollectionsfetchjob.cpp + common/davcollectionsfetchjob.h + common/davcollectionsmultifetchjob.cpp + common/davcollectionsmultifetchjob.h + common/daverror.cpp + common/daverror.h + common/davitem.cpp + common/davitemcreatejob.cpp + common/davitemcreatejob.h + common/davitemdeletejob.cpp + common/davitemdeletejob.h + common/davitemfetchjob.cpp + common/davitemfetchjob.h + common/davitem.h + common/davitemmodifyjob.cpp + common/davitemmodifyjob.h + common/davitemsfetchjob.cpp + common/davitemsfetchjob.h + common/davitemslistjob.cpp + common/davitemslistjob.h + common/davjobbase.cpp + common/davjobbase.h + common/davjobbase_p.h + common/davmanager.cpp + common/davmanager_p.h + common/davmultigetprotocol.cpp + common/davmultigetprotocol_p.h + common/davprincipalhomesetsfetchjob.cpp + common/davprincipalhomesetsfetchjob.h + common/davprincipalsearchjob.cpp + common/davprincipalsearchjob.h + common/davprotocolbase.cpp + common/davprotocolbase_p.h + common/davurl.cpp + common/davurl.h + common/enums.h + common/etagcache.cpp + common/etagcache.h + common/protocolinfo.cpp + common/protocolinfo.h + common/utils.cpp + common/utils_p.h + + protocols/groupdavprotocol.cpp + protocols/groupdavprotocol_p.h + + #KContacts + protocols/carddavprotocol.cpp + protocols/carddavprotocol_p.h + + #KCalCore + protocols/caldavprotocol.cpp + protocols/caldavprotocol_p.h + ) + + +ecm_generate_headers(KDAV_Camelcase_HEADERS + HEADER_NAMES + DavJobBase + DavCollection + DavCollectionDeleteJob + DavCollectionsFetchJob + DavCollectionModifyJob + DavCollectionsMultiFetchJob + DavError + DavItem + DavItemCreateJob + DavItemDeleteJob + DavItemFetchJob + DavItemModifyJob + DavItemsFetchJob + DavItemsListJob + DavPrincipalHomesetsFetchJob + DavPrincipalSearchJob + DavUrl + Enums + EtagCache + ProtocolInfo + REQUIRED_HEADERS KDAV_HEADERS + PREFIX KDAV + RELATIVE common + ) + +install(FILES + ${KDAV_Camelcase_HEADERS} + DESTINATION ${KDAV_INSTALL_INCLUDEDIR}/KDAV # for C++ namespace KDAV + COMPONENT Devel + ) + +install(FILES + ${KDAV_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/kdav_export.h + + DESTINATION ${KDAV_INSTALL_INCLUDEDIR}/kdav # for C++ namespace KDAV + COMPONENT Devel + ) + +ecm_qt_declare_logging_category(KF5DAV + HEADER libkdav_debug.h + IDENTIFIER KDAV_LOG + CATEGORY_NAME kf.dav + OLD_CATEGORY_NAMES org.kde.pim.kdav + DESCRIPTION "KDAV" + EXPORT KDAV +) + +generate_export_header(KF5DAV BASE_NAME kdav) + +target_include_directories(KF5DAV PRIVATE + common + protocols +) + +target_link_libraries(KF5DAV +PUBLIC + KF5::CoreAddons +PRIVATE + Qt${QT_MAJOR_VERSION}::Xml + Qt${QT_MAJOR_VERSION}::Gui + KF5::KIOCore + KF5::I18n + ) + + +install(TARGETS + KF5DAV + EXPORT KF5DAVTargets + ${KF5_INSTALL_TARGETS_DEFAULT_ARGS} + ) + +ecm_generate_pri_file(BASE_NAME KDAV + LIB_NAME KF5DAV + DEPS "KCoreAddons" + FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KDAV_INSTALL_INCLUDEDIR} + ) + +install(FILES + ${PRI_FILENAME} + DESTINATION ${ECM_MKSPECS_INSTALL_DIR} + ) + +target_include_directories(KF5DAV INTERFACE "$") + +ecm_qt_install_logging_categories(EXPORT KDAV FILE kdav.categories DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR}) + +if (BUILD_QCH) + ecm_add_qch( + KF5DAV_QCH + NAME KDAV + BASE_NAME KF5DAV + VERSION ${KF_VERSION} + ORG_DOMAIN org.kde + SOURCES # using only public headers, to cover only public API + ${KDAV_HEADERS} + MD_MAINPAGE "${CMAKE_SOURCE_DIR}/README.md" + LINK_QCHS + Qt5Gui_QCH + KF5CoreAddons_QCH + INCLUDE_DIRS + ${CMAKE_CURRENT_BINARY_DIR} + BLANK_MACROS + KDAV_EXPORT + KDAV_DEPRECATED_EXPORT + KDAV_DEPRECATED + "KDAV_DEPRECATED_VERSION(x, y, t)" + TAGFILE_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} + QCH_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} + COMPONENT Devel + ) +endif() diff --git a/src/Messages.sh b/src/Messages.sh new file mode 100644 index 0000000..ee93862 --- /dev/null +++ b/src/Messages.sh @@ -0,0 +1,2 @@ +#! /bin/sh +$XGETTEXT `find . -name "*.cpp" -o -name "*.h" | grep -v '/tests/'` -o $podir/libkdav.pot diff --git a/src/common/davcollection.cpp b/src/common/davcollection.cpp new file mode 100644 index 0000000..80a460d --- /dev/null +++ b/src/common/davcollection.cpp @@ -0,0 +1,104 @@ +/* + SPDX-FileCopyrightText: 2009 Grégory Oestreicher + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "davcollection.h" + +#include "davurl.h" + +#include + +using namespace KDAV; + +class DavCollectionPrivate : public QSharedData +{ +public: + DavCollection::ContentTypes mContentTypes; + QString mCTag; + DavUrl mUrl; + QString mDisplayName; + QColor mColor; + Privileges mPrivileges; +}; + +DavCollection::DavCollection() + : d(new DavCollectionPrivate) +{ +} + +DavCollection::DavCollection(const DavUrl &url, const QString &displayName, ContentTypes contentTypes) + : d(new DavCollectionPrivate) +{ + d->mUrl = url; + d->mDisplayName = displayName; + d->mContentTypes = contentTypes; + d->mPrivileges = KDAV::All; +} + +DavCollection::DavCollection(const DavCollection &other) = default; +DavCollection::DavCollection(DavCollection &&) = default; +DavCollection &DavCollection::operator=(const DavCollection &other) = default; +DavCollection &DavCollection::operator=(DavCollection &&) = default; +DavCollection::~DavCollection() = default; + +void DavCollection::setCTag(const QString &ctag) +{ + d->mCTag = ctag; +} + +QString DavCollection::CTag() const +{ + return d->mCTag; +} + +void DavCollection::setUrl(const DavUrl &url) +{ + d->mUrl = url; +} + +DavUrl DavCollection::url() const +{ + return d->mUrl; +} + +void DavCollection::setDisplayName(const QString &displayName) +{ + d->mDisplayName = displayName; +} + +QString DavCollection::displayName() const +{ + return d->mDisplayName; +} + +void DavCollection::setColor(const QColor &color) +{ + d->mColor = color; +} + +QColor DavCollection::color() const +{ + return d->mColor; +} + +void DavCollection::setContentTypes(ContentTypes contentTypes) +{ + d->mContentTypes = contentTypes; +} + +DavCollection::ContentTypes DavCollection::contentTypes() const +{ + return d->mContentTypes; +} + +void DavCollection::setPrivileges(Privileges privs) +{ + d->mPrivileges = privs; +} + +Privileges DavCollection::privileges() const +{ + return d->mPrivileges; +} diff --git a/src/common/davcollection.h b/src/common/davcollection.h new file mode 100644 index 0000000..2346fd5 --- /dev/null +++ b/src/common/davcollection.h @@ -0,0 +1,153 @@ +/* + SPDX-FileCopyrightText: 2009 Grégory Oestreicher + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KDAV_DAVCOLLECTION_H +#define KDAV_DAVCOLLECTION_H + +#include "kdav_export.h" + +#include "enums.h" + +#include +#include +#include + +class QColor; + +class DavCollectionPrivate; + +namespace KDAV +{ +class DavUrl; +} + +namespace KDAV +{ +/** + * @class DavCollection davcollection.h + * + * @short A helper class to store information about DAV collection. + * + * This class is used as container to transfer information about DAV + * collections between the Akonadi resource and the DAV jobs. + */ +class KDAV_EXPORT DavCollection +{ +public: + /** + * Defines a list of DAV collection objects. + */ + typedef QVector List; + + /** + * Describes the possible content type of the DAV collection. + */ + enum ContentType { + Events = 1, ///< The collection can contain event DAV resources. + Todos = 2, ///< The collection can contain todo DAV resources. + Contacts = 4, ///< The collection can contain contact DAV resources. + FreeBusy = 8, ///< The collection can contain free/busy information. + Journal = 16, ///< The collection can contain journal DAV resources. + Calendar = 32, ///< The collection can contain anything calendar-related. + }; + Q_DECLARE_FLAGS(ContentTypes, ContentType) + + /** + * Creates an empty DAV collection. + */ + DavCollection(); + + /** + * Creates a new DAV collection. + * + * @param url The URL that identifies the collection. + * @param displayName The display name of the collection. + * @param contentTypes The possible content types of the collection. + */ + DavCollection(const DavUrl &url, const QString &displayName, ContentTypes contentTypes); + + DavCollection(const DavCollection &other); + DavCollection(DavCollection &&); + DavCollection &operator=(const DavCollection &other); + DavCollection &operator=(DavCollection &&); + + ~DavCollection(); + + /** + * Sets this collection CTag. + * @see https://github.com/apple/ccs-calendarserver/blob/master/doc/Extensions/caldav-ctag.txt + */ + void setCTag(const QString &ctag); + + /** + * Returns this collection CTag. The returned value will be empty + * if no CTag was found. + * @see https://github.com/apple/ccs-calendarserver/blob/master/doc/Extensions/caldav-ctag.txt + */ + Q_REQUIRED_RESULT QString CTag() const; + + /** + * Sets the @p url that identifies the collection. + */ + void setUrl(const DavUrl &url); + + /** + * Returns the URL that identifies the collection. + */ + Q_REQUIRED_RESULT DavUrl url() const; + + /** + * Sets the display @p name of the collection. + */ + void setDisplayName(const QString &name); + + /** + * Returns the display name of the collection. + */ + Q_REQUIRED_RESULT QString displayName() const; + + /** + * Sets the color for this collection + */ + void setColor(const QColor &color); + + /** + * Return the color of the collection, or an empty string if + * none was provided by the backend. + */ + Q_REQUIRED_RESULT QColor color() const; + + /** + * Sets the possible content @p types of the collection. + */ + void setContentTypes(ContentTypes types); + + /** + * Returns the possible content types of the collection. + */ + Q_REQUIRED_RESULT ContentTypes contentTypes() const; + + /** + * Sets the privileges on this collection. + */ + void setPrivileges(Privileges privs); + + /** + * Returns the privileges on this collection. + */ + Q_REQUIRED_RESULT Privileges privileges() const; + +private: + QSharedDataPointer d; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(DavCollection::ContentTypes) + +} + +Q_DECLARE_TYPEINFO(KDAV::DavCollection, Q_MOVABLE_TYPE); + +#endif diff --git a/src/common/davcollectiondeletejob.cpp b/src/common/davcollectiondeletejob.cpp new file mode 100644 index 0000000..a4b62ec --- /dev/null +++ b/src/common/davcollectiondeletejob.cpp @@ -0,0 +1,65 @@ +/* + SPDX-FileCopyrightText: 2010 Grégory Oestreicher + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "davcollectiondeletejob.h" +#include "davjobbase_p.h" + +#include "daverror.h" + +#include +#include + +using namespace KDAV; + +namespace KDAV +{ +class DavCollectionDeleteJobPrivate : public DavJobBasePrivate +{ +public: + void davJobFinished(KJob *job); + + DavUrl mUrl; +}; +} + +DavCollectionDeleteJob::DavCollectionDeleteJob(const DavUrl &url, QObject *parent) + : DavJobBase(new DavCollectionDeleteJobPrivate, parent) +{ + Q_D(DavCollectionDeleteJob); + d->mUrl = url; +} + +void DavCollectionDeleteJob::start() +{ + Q_D(DavCollectionDeleteJob); + KIO::DeleteJob *job = KIO::del(d->mUrl.url(), KIO::HideProgressInfo | KIO::DefaultFlags); + job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true")); + job->addMetaData(QStringLiteral("cookies"), QStringLiteral("none")); + job->addMetaData(QStringLiteral("no-auth-prompt"), QStringLiteral("true")); + + connect(job, &KIO::DeleteJob::result, this, [d](KJob *job) { + d->davJobFinished(job); + }); +} + +void DavCollectionDeleteJobPrivate::davJobFinished(KJob *job) +{ + KIO::DeleteJob *deleteJob = qobject_cast(job); + + if (deleteJob->error() && deleteJob->error() != KIO::ERR_NO_CONTENT) { + const int responseCode = deleteJob->queryMetaData(QStringLiteral("responsecode")).isEmpty() // + ? 0 + : deleteJob->queryMetaData(QStringLiteral("responsecode")).toInt(); + + setLatestResponseCode(responseCode); + setError(ERR_COLLECTIONDELETE); + setJobErrorText(deleteJob->errorText()); + setJobError(deleteJob->error()); + setErrorTextFromDavError(); + } + + emitResult(); +} diff --git a/src/common/davcollectiondeletejob.h b/src/common/davcollectiondeletejob.h new file mode 100644 index 0000000..70f149c --- /dev/null +++ b/src/common/davcollectiondeletejob.h @@ -0,0 +1,49 @@ +/* + SPDX-FileCopyrightText: 2010 Grégory Oestreicher + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KDAV_DAVCOLLECTIONDELETEJOB_H +#define KDAV_DAVCOLLECTIONDELETEJOB_H + +#include "kdav_export.h" + +#include "davjobbase.h" +#include "davurl.h" + +namespace KDAV +{ +class DavCollectionDeleteJobPrivate; + +/** + * @class DavCollectionDeleteJob davcollectiondeletejob.h + * + * @short A job that deletes a DAV collection. + * + * This job is used to delete a DAV collection at a certain URL. + */ +class KDAV_EXPORT DavCollectionDeleteJob : public DavJobBase +{ + Q_OBJECT + +public: + /** + * Creates a new DAV collection delete job. + * + * @param url The DAV URL of the collection to delete + * @param parent The parent object. + */ + explicit DavCollectionDeleteJob(const DavUrl &url, QObject *parent = nullptr); + + /** + * Starts the job. + */ + void start() override; + +private: + Q_DECLARE_PRIVATE(DavCollectionDeleteJob) +}; +} + +#endif diff --git a/src/common/davcollectionmodifyjob.cpp b/src/common/davcollectionmodifyjob.cpp new file mode 100644 index 0000000..8be394c --- /dev/null +++ b/src/common/davcollectionmodifyjob.cpp @@ -0,0 +1,169 @@ +/* + SPDX-FileCopyrightText: 2010 Grégory Oestreicher + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "davcollectionmodifyjob.h" +#include "davjobbase_p.h" +#include "davmanager_p.h" + +#include "daverror.h" +#include "utils_p.h" + +#include +#include + +using namespace KDAV; + +namespace KDAV +{ +class DavCollectionModifyJobPrivate : public DavJobBasePrivate +{ +public: + void davJobFinished(KJob *job); + + DavUrl mUrl; + QDomDocument mQuery; + + QVector mSetProperties; + QVector mRemoveProperties; +}; +} + +DavCollectionModifyJob::DavCollectionModifyJob(const DavUrl &url, QObject *parent) + : DavJobBase(new DavCollectionModifyJobPrivate, parent) +{ + Q_D(DavCollectionModifyJob); + d->mUrl = url; +} + +void DavCollectionModifyJob::setProperty(const QString &prop, const QString &value, const QString &ns) +{ + Q_D(DavCollectionModifyJob); + QDomElement propElement; + + if (ns.isEmpty()) { + propElement = d->mQuery.createElement(prop); + } else { + propElement = d->mQuery.createElementNS(ns, prop); + } + + const QDomText textElement = d->mQuery.createTextNode(value); + propElement.appendChild(textElement); + + d->mSetProperties << propElement; +} + +void DavCollectionModifyJob::removeProperty(const QString &prop, const QString &ns) +{ + Q_D(DavCollectionModifyJob); + QDomElement propElement; + + if (ns.isEmpty()) { + propElement = d->mQuery.createElement(prop); + } else { + propElement = d->mQuery.createElementNS(ns, prop); + } + + d->mRemoveProperties << propElement; +} + +void DavCollectionModifyJob::start() +{ + Q_D(DavCollectionModifyJob); + if (d->mSetProperties.isEmpty() && d->mRemoveProperties.isEmpty()) { + setError(ERR_COLLECTIONMODIFY_NO_PROPERITES); + d->setErrorTextFromDavError(); + emitResult(); + return; + } + + QDomDocument mQuery; + QDomElement propertyUpdateElement = mQuery.createElementNS(QStringLiteral("DAV:"), QStringLiteral("propertyupdate")); + mQuery.appendChild(propertyUpdateElement); + + if (!d->mSetProperties.isEmpty()) { + QDomElement setElement = mQuery.createElementNS(QStringLiteral("DAV:"), QStringLiteral("set")); + propertyUpdateElement.appendChild(setElement); + + QDomElement propElement = mQuery.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop")); + setElement.appendChild(propElement); + + for (const QDomElement &element : std::as_const(d->mSetProperties)) { + propElement.appendChild(element); + } + } + + if (!d->mRemoveProperties.isEmpty()) { + QDomElement removeElement = mQuery.createElementNS(QStringLiteral("DAV:"), QStringLiteral("remove")); + propertyUpdateElement.appendChild(removeElement); + + QDomElement propElement = mQuery.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop")); + removeElement.appendChild(propElement); + + for (const QDomElement &element : std::as_const(d->mSetProperties)) { + propElement.appendChild(element); + } + } + + KIO::DavJob *job = DavManager::self()->createPropPatchJob(d->mUrl.url(), mQuery.toString()); + job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true")); + connect(job, &KIO::DavJob::result, this, [d](KJob *job) { + d->davJobFinished(job); + }); +} + +void DavCollectionModifyJobPrivate::davJobFinished(KJob *job) +{ + KIO::DavJob *davJob = qobject_cast(job); + const QString responseCodeStr = davJob->queryMetaData(QStringLiteral("responsecode")); + const int responseCode = responseCodeStr.isEmpty() ? 0 : responseCodeStr.toInt(); + + // KIO::DavJob does not set error() even if the HTTP status code is a 4xx or a 5xx + if (davJob->error() || (responseCode >= 400 && responseCode < 600)) { + setLatestResponseCode(responseCode); + setError(ERR_COLLECTIONMODIFY); + setJobErrorText(davJob->errorText()); + setJobError(davJob->error()); + setErrorTextFromDavError(); + emitResult(); + return; + } + + QDomDocument response; + response.setContent(davJob->responseData(), true); + QDomElement responseElement = Utils::firstChildElementNS(response.documentElement(), QStringLiteral("DAV:"), QStringLiteral("response")); + + bool hasError = false; + + // parse all propstats answers to get the eventual errors + const QDomNodeList propstats = responseElement.elementsByTagNameNS(QStringLiteral("DAV:"), QStringLiteral("propstat")); + for (int i = 0; i < propstats.length(); ++i) { + const QDomElement propstatElement = propstats.item(i).toElement(); + const QDomElement statusElement = Utils::firstChildElementNS(propstatElement, QStringLiteral("DAV:"), QStringLiteral("status")); + + const QString statusText = statusElement.text(); + if (statusText.contains(QLatin1String("200"))) { + continue; + } else { + // Generic error + hasError = true; + break; + } + } + + if (hasError) { + setError(ERR_COLLECTIONMODIFY_RESPONSE); + + // Trying to get more information about the error + const QDomElement responseDescriptionElement = + Utils::firstChildElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("responsedescription")); + if (!responseDescriptionElement.isNull()) { + setJobErrorText(responseDescriptionElement.text()); + } + setErrorTextFromDavError(); + } + + emitResult(); +} diff --git a/src/common/davcollectionmodifyjob.h b/src/common/davcollectionmodifyjob.h new file mode 100644 index 0000000..8ac34f7 --- /dev/null +++ b/src/common/davcollectionmodifyjob.h @@ -0,0 +1,67 @@ +/* + SPDX-FileCopyrightText: 2010 Grégory Oestreicher + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KDAV_DAVCOLLECTIONMODIFYJOB_H +#define KDAV_DAVCOLLECTIONMODIFYJOB_H + +#include "kdav_export.h" + +#include "davjobbase.h" +#include "davurl.h" + +namespace KDAV +{ +class DavCollectionModifyJobPrivate; + +/** + * @class DavCollectionModifyJob davcollectionmodifyjob.h + * + * @short A job that modifies a DAV collection. + * + * This job is used to modify a property of a DAV collection + * on the DAV server. + */ +class KDAV_EXPORT DavCollectionModifyJob : public DavJobBase +{ + Q_OBJECT + +public: + /** + * Creates a new DAV collection modify job. + * + * @param url The DAV URL that identifies the collection. + * @param parent The parent object. + */ + explicit DavCollectionModifyJob(const DavUrl &url, QObject *parent = nullptr); + + /** + * Sets the property that shall be modified by the job. + * + * @param property The name of the property. + * @param value The value of the property. + * @param ns The XML namespace that shall be used for the property name. + */ + void setProperty(const QString &property, const QString &value, const QString &ns = QString()); + + /** + * Sets the property that shall be removed by the job. + * + * @param property The name of the property. + * @param ns The XML namespace that shall be used for the property name. + */ + void removeProperty(const QString &property, const QString &ns); + + /** + * Starts the job. + */ + void start() override; + +private: + Q_DECLARE_PRIVATE(DavCollectionModifyJob) +}; +} + +#endif diff --git a/src/common/davcollectionsfetchjob.cpp b/src/common/davcollectionsfetchjob.cpp new file mode 100644 index 0000000..f1929e1 --- /dev/null +++ b/src/common/davcollectionsfetchjob.cpp @@ -0,0 +1,356 @@ +/* + SPDX-FileCopyrightText: 2010 Tobias Koenig + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "davcollectionsfetchjob.h" +#include "davjobbase_p.h" + +#include "daverror.h" +#include "davmanager_p.h" +#include "davprincipalhomesetsfetchjob.h" +#include "davprotocolbase_p.h" +#include "utils_p.h" + +#include "libkdav_debug.h" +#include +#include + +#include +#include + +using namespace KDAV; + +namespace KDAV +{ +class DavCollectionsFetchJobPrivate : public DavJobBasePrivate +{ +public: + void principalFetchFinished(KJob *job); + void collectionsFetchFinished(KJob *job); + void doCollectionsFetch(const QUrl &url); + void subjobFinished(); + + DavUrl mUrl; + DavCollection::List mCollections; + uint mSubJobCount = 0; + + Q_DECLARE_PUBLIC(DavCollectionsFetchJob) +}; +} + +DavCollectionsFetchJob::DavCollectionsFetchJob(const DavUrl &url, QObject *parent) + : DavJobBase(new DavCollectionsFetchJobPrivate, parent) +{ + Q_D(DavCollectionsFetchJob); + d->mUrl = url; +} + +void DavCollectionsFetchJob::start() +{ + Q_D(DavCollectionsFetchJob); + if (DavManager::davProtocol(d->mUrl.protocol())->supportsPrincipals()) { + DavPrincipalHomeSetsFetchJob *job = new DavPrincipalHomeSetsFetchJob(d->mUrl); + connect(job, &DavPrincipalHomeSetsFetchJob::result, this, [d](KJob *job) { + d->principalFetchFinished(job); + }); + job->start(); + } else { + d->doCollectionsFetch(d->mUrl.url()); + } +} + +DavCollection::List DavCollectionsFetchJob::collections() const +{ + Q_D(const DavCollectionsFetchJob); + return d->mCollections; +} + +DavUrl DavCollectionsFetchJob::davUrl() const +{ + Q_D(const DavCollectionsFetchJob); + return d->mUrl; +} + +void DavCollectionsFetchJobPrivate::doCollectionsFetch(const QUrl &url) +{ + ++mSubJobCount; + + const QDomDocument collectionQuery = DavManager::davProtocol(mUrl.protocol())->collectionsQuery()->buildQuery(); + + KIO::DavJob *job = DavManager::self()->createPropFindJob(url, collectionQuery.toString()); + QObject::connect(job, &KIO::DavJob::result, q_ptr, [this](KJob *job) { + collectionsFetchFinished(job); + }); + job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true")); +} + +void DavCollectionsFetchJobPrivate::principalFetchFinished(KJob *job) +{ + const DavPrincipalHomeSetsFetchJob *davJob = qobject_cast(job); + + if (davJob->error()) { + if (davJob->latestResponseCode()) { + // If we have a HTTP response code then this may mean that + // the URL was not a principal URL. Retry as if it were a calendar URL. + qCDebug(KDAV_LOG) << job->errorText(); + doCollectionsFetch(mUrl.url()); + } else { + // Just give up here. + setDavError(davJob->davError()); + setErrorTextFromDavError(); + emitResult(); + } + + return; + } + + const QStringList homeSets = davJob->homeSets(); + qCDebug(KDAV_LOG) << "Found" << homeSets.size() << "homesets"; + qCDebug(KDAV_LOG) << homeSets; + + if (homeSets.isEmpty()) { + // Same as above, retry as if it were a calendar URL. + doCollectionsFetch(mUrl.url()); + return; + } + + for (const QString &homeSet : homeSets) { + QUrl url = mUrl.url(); + + if (homeSet.startsWith(QLatin1Char('/'))) { + // homeSet is only a path, use request url to complete + url.setPath(homeSet, QUrl::TolerantMode); + } else { + // homeSet is a complete url + QUrl tmpUrl(homeSet); + tmpUrl.setUserName(url.userName()); + tmpUrl.setPassword(url.password()); + url = tmpUrl; + } + + doCollectionsFetch(url); + } +} + +void DavCollectionsFetchJobPrivate::collectionsFetchFinished(KJob *job) +{ + Q_Q(DavCollectionsFetchJob); + KIO::DavJob *davJob = qobject_cast(job); + const QString responseCodeStr = davJob->queryMetaData(QStringLiteral("responsecode")); + const int responseCode = responseCodeStr.isEmpty() ? 0 : responseCodeStr.toInt(); + + // KIO::DavJob does not set error() even if the HTTP status code is a 4xx or a 5xx + if (davJob->error() || (responseCode >= 400 && responseCode < 600)) { + if (davJob->url() != mUrl.url()) { + // Retry as if the initial URL was a calendar URL. + // We can end up here when retrieving a homeset on + // which a PROPFIND resulted in an error + doCollectionsFetch(mUrl.url()); + --mSubJobCount; + return; + } + + setLatestResponseCode(responseCode); + setError(ERR_PROBLEM_WITH_REQUEST); + setJobErrorText(davJob->errorText()); + setJobError(davJob->error()); + setErrorTextFromDavError(); + } else { + // For use in the collectionDiscovered() signal + QUrl _jobUrl = mUrl.url(); + _jobUrl.setUserInfo(QString()); + const QString jobUrl = _jobUrl.toDisplayString(); + + // Validate that we got a valid PROPFIND response + QDomDocument response; + response.setContent(davJob->responseData(), true); + QDomElement rootElement = response.documentElement(); + if (rootElement.tagName().compare(QLatin1String("multistatus"), Qt::CaseInsensitive) != 0) { + setError(ERR_COLLECTIONFETCH); + setErrorTextFromDavError(); + subjobFinished(); + return; + } + + QByteArray resp = davJob->responseData(); + QDomDocument document; + if (!document.setContent(resp, true)) { + setError(ERR_COLLECTIONFETCH); + setErrorTextFromDavError(); + subjobFinished(); + return; + } + + if (!q->error()) { + /* + * Extract information from a document like the following: + * + * + * + * /caldav.php/test1.user/home/ + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * Test1 User + * + * + * + * + * + * 12345 + * + * HTTP/1.1 200 OK + * + * + * + */ + + const QDomElement responsesElement = document.documentElement(); + + QDomElement responseElement = Utils::firstChildElementNS(responsesElement, QStringLiteral("DAV:"), QStringLiteral("response")); + while (!responseElement.isNull()) { + QDomElement propstatElement; + + // check for the valid propstat, without giving up on first error + { + const QDomNodeList propstats = responseElement.elementsByTagNameNS(QStringLiteral("DAV:"), QStringLiteral("propstat")); + for (int i = 0; i < propstats.length(); ++i) { + const QDomElement propstatCandidate = propstats.item(i).toElement(); + const QDomElement statusElement = Utils::firstChildElementNS(propstatCandidate, QStringLiteral("DAV:"), QStringLiteral("status")); + if (statusElement.text().contains(QLatin1String("200"))) { + propstatElement = propstatCandidate; + } + } + } + + if (propstatElement.isNull()) { + responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); + continue; + } + + // extract url + const QDomElement hrefElement = Utils::firstChildElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("href")); + if (hrefElement.isNull()) { + responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); + continue; + } + + QString href = hrefElement.text(); + if (!href.endsWith(QLatin1Char('/'))) { + href.append(QLatin1Char('/')); + } + + QUrl url = davJob->url(); + url.setUserInfo(QString()); + if (href.startsWith(QLatin1Char('/'))) { + // href is only a path, use request url to complete + url.setPath(href, QUrl::TolerantMode); + } else { + // href is a complete url + url = QUrl::fromUserInput(href); + } + + // don't add this resource if it has already been detected + bool alreadySeen = false; + for (const DavCollection &seen : std::as_const(mCollections)) { + if (seen.url().toDisplayString() == url.toDisplayString()) { + alreadySeen = true; + } + } + if (alreadySeen) { + responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); + continue; + } + + // extract display name + const QDomElement propElement = Utils::firstChildElementNS(propstatElement, QStringLiteral("DAV:"), QStringLiteral("prop")); + if (!DavManager::davProtocol(mUrl.protocol())->containsCollection(propElement)) { + responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); + continue; + } + const QDomElement displaynameElement = Utils::firstChildElementNS(propElement, QStringLiteral("DAV:"), QStringLiteral("displayname")); + const QString displayName = displaynameElement.text(); + + // Extract CTag + const QDomElement CTagElement = Utils::firstChildElementNS(propElement, // + QStringLiteral("http://calendarserver.org/ns/"), + QStringLiteral("getctag")); + QString CTag; + if (!CTagElement.isNull()) { + CTag = CTagElement.text(); + } + + // extract calendar color if provided + const QDomElement colorElement = Utils::firstChildElementNS(propElement, // + QStringLiteral("http://apple.com/ns/ical/"), + QStringLiteral("calendar-color")); + QColor color; + if (!colorElement.isNull()) { + QString colorValue = colorElement.text(); + if (QColor::isValidColor(colorValue)) { + // Color is either #RRGGBBAA or #RRGGBB but QColor expects #AARRGGBB + // so we put the AA in front if the string's length is 9. + if (colorValue.size() == 9) { + QString fixedColorValue = QStringLiteral("#") + colorValue.mid(7, 2) + colorValue.mid(1, 6); + color.setNamedColor(fixedColorValue); + } else { + color.setNamedColor(colorValue); + } + } + } + + // extract allowed content types + const DavCollection::ContentTypes contentTypes = DavManager::davProtocol(mUrl.protocol())->collectionContentTypes(propstatElement); + + auto _url = url; + _url.setUserInfo(mUrl.url().userInfo()); + DavCollection collection(DavUrl(_url, mUrl.protocol()), displayName, contentTypes); + + collection.setCTag(CTag); + if (color.isValid()) { + collection.setColor(color); + } + + // extract privileges + const QDomElement currentPrivsElement = Utils::firstChildElementNS(propElement, // + QStringLiteral("DAV:"), + QStringLiteral("current-user-privilege-set")); + if (currentPrivsElement.isNull()) { + // Assume that we have all privileges + collection.setPrivileges(KDAV::All); + } else { + Privileges privileges = Utils::extractPrivileges(currentPrivsElement); + collection.setPrivileges(privileges); + } + + qCDebug(KDAV_LOG) << url.toDisplayString() << "PRIVS: " << collection.privileges(); + mCollections << collection; + Q_EMIT q->collectionDiscovered(mUrl.protocol(), url.toDisplayString(), jobUrl); + + responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); + } + } + } + + subjobFinished(); +} + +void DavCollectionsFetchJobPrivate::subjobFinished() +{ + if (--mSubJobCount == 0) { + emitResult(); + } +} diff --git a/src/common/davcollectionsfetchjob.h b/src/common/davcollectionsfetchjob.h new file mode 100644 index 0000000..24befb8 --- /dev/null +++ b/src/common/davcollectionsfetchjob.h @@ -0,0 +1,70 @@ +/* + SPDX-FileCopyrightText: 2010 Tobias Koenig + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KDAV_DAVCOLLECTIONSFETCHJOB_H +#define KDAV_DAVCOLLECTIONSFETCHJOB_H + +#include "kdav_export.h" + +#include "davcollection.h" +#include "davjobbase.h" +#include "davurl.h" + +namespace KDAV +{ +class DavCollectionsFetchJobPrivate; + +/** + * @class DavCollectionsFetchJob davcollectionsfetchjob.h + * + * @short A job that fetches all DAV collection. + * + * This job is used to fetch all DAV collection that are available + * under a certain DAV URL. + */ +class KDAV_EXPORT DavCollectionsFetchJob : public DavJobBase +{ + Q_OBJECT + +public: + /** + * Creates a new DAV collections fetch job. + * + * @param url The DAV URL of the DAV collection whose sub collections shall be fetched. + * @param parent The parent object. + */ + explicit DavCollectionsFetchJob(const DavUrl &url, QObject *parent = nullptr); + + /** + * Starts the job. + */ + void start() override; + + /** + * Returns the list of fetched DAV collections. + */ + Q_REQUIRED_RESULT DavCollection::List collections() const; + + /** + * Return the DavUrl used by this job + */ + Q_REQUIRED_RESULT DavUrl davUrl() const; + +Q_SIGNALS: + /** + * This signal is emitted every time a new collection has been discovered. + * + * @param collectionUrl The URL of the discovered collection + * @param configuredUrl The URL given to the job + */ + void collectionDiscovered(KDAV::Protocol protocol, const QString &collectionUrl, const QString &configuredUrl); + +private: + Q_DECLARE_PRIVATE(DavCollectionsFetchJob) +}; +} + +#endif diff --git a/src/common/davcollectionsmultifetchjob.cpp b/src/common/davcollectionsmultifetchjob.cpp new file mode 100644 index 0000000..68c03ca --- /dev/null +++ b/src/common/davcollectionsmultifetchjob.cpp @@ -0,0 +1,70 @@ +/* + SPDX-FileCopyrightText: 2010 Tobias Koenig + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "davcollectionsmultifetchjob.h" + +#include "davcollectionsfetchjob.h" + +using namespace KDAV; + +namespace KDAV +{ +class DavCollectionsMultiFetchJobPrivate +{ +public: + DavCollection::List mCollections; +}; +} + +DavCollectionsMultiFetchJob::DavCollectionsMultiFetchJob(const DavUrl::List &urls, QObject *parent) + : KCompositeJob(parent) + , d(new DavCollectionsMultiFetchJobPrivate) +{ + for (const DavUrl &url : std::as_const(urls)) { + DavCollectionsFetchJob *job = new DavCollectionsFetchJob(url, this); + connect(job, &DavCollectionsFetchJob::collectionDiscovered, this, &DavCollectionsMultiFetchJob::collectionDiscovered); + addSubjob(job); + } +} + +DavCollectionsMultiFetchJob::~DavCollectionsMultiFetchJob() = default; + +void DavCollectionsMultiFetchJob::start() +{ + if (!hasSubjobs()) { + emitResult(); + } else { + for (KJob *job : subjobs()) { + job->start(); + } + } +} + +DavCollection::List DavCollectionsMultiFetchJob::collections() const +{ + return d->mCollections; +} + +void DavCollectionsMultiFetchJob::slotResult(KJob *job) +{ + // If we use KCompositeJob::slotResult(job) we end up with behaviour that's very + // hard to unittest: the valid URLs might or might not get processed. + // Let's wait until all subjobs are done before emitting result. + + if (job->error() && !error()) { + // Store error only if first error + setError(job->error()); + setErrorText(job->errorText()); + } + if (!job->error()) { + DavCollectionsFetchJob *fetchJob = qobject_cast(job); + d->mCollections << fetchJob->collections(); + } + removeSubjob(job); + if (!hasSubjobs()) { + emitResult(); + } +} diff --git a/src/common/davcollectionsmultifetchjob.h b/src/common/davcollectionsmultifetchjob.h new file mode 100644 index 0000000..95ad4a6 --- /dev/null +++ b/src/common/davcollectionsmultifetchjob.h @@ -0,0 +1,74 @@ +/* + SPDX-FileCopyrightText: 2010 Tobias Koenig + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KDAV_DAVCOLLECTIONSMULTIFETCHJOB_H +#define KDAV_DAVCOLLECTIONSMULTIFETCHJOB_H + +#include "kdav_export.h" + +#include "davcollection.h" +#include "davurl.h" + +#include + +#include + +namespace KDAV +{ +class DavCollectionsMultiFetchJobPrivate; + +/** + * @class DavCollectionsMultiFetchJob davcollectionsmultifetchjob.h + * + * @short A job that fetches all DAV collection. + * + * This job is used to fetch all DAV collection that are available + * under a certain list of DAV URLs. + * + * @note This class just combines multiple calls of DavCollectionsFetchJob + * into one job. + */ +class KDAV_EXPORT DavCollectionsMultiFetchJob : public KCompositeJob +{ + Q_OBJECT + +public: + /** + * Creates a new DAV collections multi fetch job. + * + * @param urls The list of DAV URLs whose sub collections shall be fetched. + * @param parent The parent object. + */ + explicit DavCollectionsMultiFetchJob(const DavUrl::List &urls, QObject *parent = nullptr); + ~DavCollectionsMultiFetchJob() override; + + /** + * Starts the job. + */ + void start() override; + + /** + * Returns the list of fetched DAV collections. + */ + Q_REQUIRED_RESULT DavCollection::List collections() const; + +Q_SIGNALS: + /** + * This signal is emitted every time a new collection has been discovered. + * + * @param collectionUrl The URL of the discovered collection + * @param configuredUrl The URL given to the job + */ + void collectionDiscovered(KDAV::Protocol protocol, const QString &collectionUrl, const QString &configuredUrl); + +private: + void slotResult(KJob *) override; + + const std::unique_ptr d; +}; +} + +#endif diff --git a/src/common/daverror.cpp b/src/common/daverror.cpp new file mode 100644 index 0000000..6a189c0 --- /dev/null +++ b/src/common/daverror.cpp @@ -0,0 +1,152 @@ +/* + SPDX-FileCopyrightText: 2016 Sandro Knauß + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "daverror.h" +#include + +#include +#include + +using namespace KDAV; + +namespace KDAV +{ +class ErrorPrivate : public QSharedData +{ +public: + ErrorNumber mErrorNumber = NO_ERR; + int mResponseCode = 0; + int mJobErrorCode = 0; + QString mErrorText; +}; +} + +Error::Error() + : d(new ErrorPrivate) +{ +} + +Error::Error(ErrorNumber errNo, int responseCode, const QString &errorText, int jobErrorCode) + : d(new ErrorPrivate) +{ + d->mErrorNumber = errNo; + d->mResponseCode = responseCode; + d->mErrorText = errorText; + d->mJobErrorCode = jobErrorCode; +} + +Error::Error(const Error &) = default; +Error::Error(Error &&) = default; +Error::~Error() = default; +Error &Error::operator=(const Error &) = default; +Error &Error::operator=(Error &&) = default; + +ErrorNumber Error::errorNumber() const +{ + return d->mErrorNumber; +} + +QString Error::internalErrorText() const +{ + return d->mErrorText; +} + +int Error::jobErrorCode() const +{ + return d->mJobErrorCode; +} + +int Error::responseCode() const +{ + return d->mResponseCode; +} + +QString KDAV::Error::translatedJobError() const +{ + QString err; + if (d->mJobErrorCode > 0 && d->mJobErrorCode != KIO::ERR_WORKER_DEFINED) { + err = KIO::buildErrorString(d->mJobErrorCode, d->mErrorText); + } else { + err = d->mErrorText; + } + return err; +} + +QString Error::errorText() const +{ + QString result; + + QString err = translatedJobError(); + + switch (d->mErrorNumber) { + case ERR_PROBLEM_WITH_REQUEST: + // User-side error + if (d->mResponseCode == 401) { + err = i18n("Invalid username/password"); + } else if (d->mResponseCode == 403) { + err = i18n("Access forbidden"); + } else if (d->mResponseCode == 404) { + err = i18n("Resource not found"); + } else { + err = i18n("HTTP error"); + } + result = i18n("There was a problem with the request.\n%1 (%2).", err, d->mResponseCode); + break; + case ERR_NO_MULTIGET: + result = i18n("Protocol for the collection does not support MULTIGET"); + break; + case ERR_SERVER_UNRECOVERABLE: + result = i18n("The server encountered an error that prevented it from completing your request: %1 (%2)", err, d->mResponseCode); + break; + case ERR_COLLECTIONDELETE: + result = i18n("There was a problem with the request. The collection has not been deleted from the server.\n%1 (%2).", err, d->mResponseCode); + break; + case ERR_COLLECTIONFETCH: + result = i18n("Invalid responses from backend"); + break; + case ERR_COLLECTIONFETCH_XQUERY_SETFOCUS: + result = i18n("Error setting focus for XQuery"); + break; + case ERR_COLLECTIONFETCH_XQUERY_INVALID: + result = i18n("Invalid XQuery submitted by DAV implementation"); + break; + case ERR_COLLECTIONMODIFY: + result = i18n( + "There was a problem with the request. The collection has not been modified on the server.\n" + "%1 (%2).", + err, + d->mResponseCode); + break; + case ERR_COLLECTIONMODIFY_NO_PROPERITES: + result = i18n("No properties to change or remove"); + break; + case ERR_COLLECTIONMODIFY_RESPONSE: + result = i18n("There was an error when modifying the properties"); + if (!d->mErrorText.isEmpty()) { + result.append(i18n("\nThe server returned more information:\n%1", d->mErrorText)); + } + break; + case ERR_ITEMCREATE: + result = i18n("There was a problem with the request. The item has not been created on the server.\n%1 (%2).", err, d->mResponseCode); + break; + case ERR_ITEMDELETE: + result = i18n("There was a problem with the request. The item has not been deleted from the server.\n%1 (%2).", err, d->mResponseCode); + break; + case ERR_ITEMMODIFY: + result = i18n("There was a problem with the request. The item was not modified on the server.\n%1 (%2).", err, d->mResponseCode); + break; + case ERR_ITEMLIST: { + result = i18n("There was a problem with the request."); + break; + }; + case ERR_ITEMLIST_NOMIMETYPE: + result = i18n("There was a problem with the request. The requested MIME types are not supported."); + break; + case NO_ERR: + break; + } + return result; +} diff --git a/src/common/daverror.h b/src/common/daverror.h new file mode 100644 index 0000000..ccb88da --- /dev/null +++ b/src/common/daverror.h @@ -0,0 +1,69 @@ +/* + SPDX-FileCopyrightText: 2016 Sandro Knauß + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KDAV_DAVERROR_H +#define KDAV_DAVERROR_H + +#include "kdav_export.h" + +#include + +#include +#include + +namespace KDAV +{ +/** DAV operation error codes. */ +enum ErrorNumber { + NO_ERR = 0, + ERR_PROBLEM_WITH_REQUEST = KJob::UserDefinedError + 200, // it would be better to request KIO about uts UserDefinedError space. + ERR_NO_MULTIGET, + ERR_SERVER_UNRECOVERABLE, + ERR_COLLECTIONDELETE = ERR_PROBLEM_WITH_REQUEST + 10, + ERR_COLLECTIONFETCH = ERR_PROBLEM_WITH_REQUEST + 20, + ERR_COLLECTIONFETCH_XQUERY_SETFOCUS, + ERR_COLLECTIONFETCH_XQUERY_INVALID, + ERR_COLLECTIONMODIFY = ERR_PROBLEM_WITH_REQUEST + 30, + ERR_COLLECTIONMODIFY_NO_PROPERITES, + ERR_COLLECTIONMODIFY_RESPONSE, + ERR_ITEMCREATE = ERR_PROBLEM_WITH_REQUEST + 100, + ERR_ITEMDELETE = ERR_PROBLEM_WITH_REQUEST + 110, + ERR_ITEMMODIFY = ERR_PROBLEM_WITH_REQUEST + 120, + ERR_ITEMLIST = ERR_PROBLEM_WITH_REQUEST + 130, + ERR_ITEMLIST_NOMIMETYPE, +}; + +class ErrorPrivate; + +/** + * @class Error daverror.h + * + * DAV operation error. + */ +class KDAV_EXPORT Error +{ +public: + explicit Error(); + explicit Error(ErrorNumber errNo, int responseCode, const QString &errorText, int jobErrorCode); + Error(const Error &); + Error(Error &&); + ~Error(); + Error &operator=(const Error &); + Error &operator=(Error &&); + + Q_REQUIRED_RESULT ErrorNumber errorNumber() const; + Q_REQUIRED_RESULT int responseCode() const; + Q_REQUIRED_RESULT QString internalErrorText() const; + Q_REQUIRED_RESULT int jobErrorCode() const; + Q_REQUIRED_RESULT QString translatedJobError() const; + Q_REQUIRED_RESULT QString errorText() const; + +private: + QSharedDataPointer d; +}; +} + +#endif diff --git a/src/common/davitem.cpp b/src/common/davitem.cpp new file mode 100644 index 0000000..a0fc346 --- /dev/null +++ b/src/common/davitem.cpp @@ -0,0 +1,107 @@ +/* + SPDX-FileCopyrightText: 2009 Grégory Oestreicher + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "davitem.h" + +#include "davurl.h" + +using namespace KDAV; + +class DavItemPrivate : public QSharedData +{ +public: + DavUrl mUrl; + QString mContentType; + QByteArray mData; + QString mEtag; +}; + +DavItem::DavItem() + : d(new DavItemPrivate) +{ +} + +DavItem::DavItem(const DavUrl &url, const QString &contentType, const QByteArray &data, const QString &etag) + : d(new DavItemPrivate) +{ + d->mUrl = url; + d->mContentType = contentType; + d->mData = data; + d->mEtag = etag; +} + +DavItem::DavItem(const DavItem &other) = default; +DavItem::DavItem(DavItem &&) = default; +DavItem &DavItem::operator=(const DavItem &other) = default; +DavItem &DavItem::operator=(DavItem &&) = default; +DavItem::~DavItem() = default; + +void DavItem::setUrl(const DavUrl &url) +{ + d->mUrl = url; +} + +DavUrl DavItem::url() const +{ + return d->mUrl; +} + +void DavItem::setContentType(const QString &contentType) +{ + d->mContentType = contentType; +} + +QString DavItem::contentType() const +{ + return d->mContentType; +} + +void DavItem::setData(const QByteArray &data) +{ + d->mData = data; +} + +QByteArray DavItem::data() const +{ + return d->mData; +} + +void DavItem::setEtag(const QString &etag) +{ + d->mEtag = etag; +} + +QString DavItem::etag() const +{ + return d->mEtag; +} + +QDataStream &KDAV::operator<<(QDataStream &stream, const DavItem &item) +{ + stream << item.url(); + stream << item.contentType(); + stream << item.data(); + stream << item.etag(); + + return stream; +} + +QDataStream &KDAV::operator>>(QDataStream &stream, DavItem &item) +{ + QString contentType; + QString etag; + DavUrl url; + QByteArray data; + + stream >> url; + stream >> contentType; + stream >> data; + stream >> etag; + + item = DavItem(url, contentType, data, etag); + + return stream; +} diff --git a/src/common/davitem.h b/src/common/davitem.h new file mode 100644 index 0000000..a38171c --- /dev/null +++ b/src/common/davitem.h @@ -0,0 +1,120 @@ +/* + SPDX-FileCopyrightText: 2009 Grégory Oestreicher + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KDAV_DAVITEM_H +#define KDAV_DAVITEM_H + +#include "kdav_export.h" + +#include +#include +#include +#include +#include + +class DavItemPrivate; + +namespace KDAV +{ +class DavUrl; +} + +namespace KDAV +{ +/** + * @class DavItem davitem.h + * + * @short A helper class to store information about DAV resources. + * + * This class is used as container to transfer information about DAV + * resources between the Akonadi resource and the DAV jobs. + * + * @note While the DAV RFC names them DAV resource we call them items + * to comply to Akonadi terminology. + */ +class KDAV_EXPORT DavItem +{ +public: + /** + * Defines a list of DAV item objects. + */ + typedef QVector List; + + /** + * Creates an empty DAV item. + */ + DavItem(); + + /** + * Creates a new DAV item. + * + * @param url The URL that identifies the item. + * @param contentType The content type of the item. + * @param data The actual raw content data of the item. + * @param etag The ETag of the item. + */ + DavItem(const DavUrl &url, const QString &contentType, const QByteArray &data, const QString &etag); + + DavItem(const DavItem &other); + DavItem(DavItem &&); + DavItem &operator=(const DavItem &other); + DavItem &operator=(DavItem &&); + + ~DavItem(); + + /** + * Sets the @p url that identifies the item. + */ + void setUrl(const DavUrl &url); + + /** + * Returns the URL that identifies the item. + */ + Q_REQUIRED_RESULT DavUrl url() const; + + /** + * Sets the content @p type of the item. + */ + void setContentType(const QString &type); + + /** + * Returns the content type of the item. + */ + Q_REQUIRED_RESULT QString contentType() const; + + /** + * Sets the raw content @p data of the item. + */ + void setData(const QByteArray &data); + + /** + * Returns the raw content data of the item. + */ + Q_REQUIRED_RESULT QByteArray data() const; + + /** + * Sets the @p etag of the item. + * @see https://tools.ietf.org/html/rfc4918#section-8.6 + */ + void setEtag(const QString &etag); + + /** + * Returns the ETag of the item. + * @see https://tools.ietf.org/html/rfc4918#section-8.6 + */ + Q_REQUIRED_RESULT QString etag() const; + +private: + QSharedDataPointer d; +}; + +KDAV_EXPORT QDataStream &operator<<(QDataStream &out, const DavItem &item); +KDAV_EXPORT QDataStream &operator>>(QDataStream &in, DavItem &item); +} + +Q_DECLARE_TYPEINFO(KDAV::DavItem, Q_MOVABLE_TYPE); + +#endif diff --git a/src/common/davitemcreatejob.cpp b/src/common/davitemcreatejob.cpp new file mode 100644 index 0000000..7279142 --- /dev/null +++ b/src/common/davitemcreatejob.cpp @@ -0,0 +1,145 @@ +/* + SPDX-FileCopyrightText: 2010 Tobias Koenig + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "davitemcreatejob.h" +#include "davjobbase_p.h" + +#include "daverror.h" +#include "davitemfetchjob.h" +#include "davmanager_p.h" + +#include +#include + +#include "libkdav_debug.h" + +using namespace KDAV; + +namespace KDAV +{ +class DavItemCreateJobPrivate : public DavJobBasePrivate +{ +public: + void davJobFinished(KJob *job); + void itemRefreshed(KJob *job); + + DavItem mItem; + int mRedirectCount = 0; + + Q_DECLARE_PUBLIC(DavItemCreateJob) +}; +} + +DavItemCreateJob::DavItemCreateJob(const DavItem &item, QObject *parent) + : DavJobBase(new DavItemCreateJobPrivate, parent) +{ + Q_D(DavItemCreateJob); + d->mItem = item; +} + +void DavItemCreateJob::start() +{ + Q_D(DavItemCreateJob); + QString headers = QStringLiteral("Content-Type: "); + headers += d->mItem.contentType(); + headers += QLatin1String("\r\n"); + headers += QLatin1String("If-None-Match: *"); + + KIO::StoredTransferJob *job = KIO::storedPut(d->mItem.data(), itemUrl(), -1, KIO::HideProgressInfo | KIO::DefaultFlags); + job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true")); + job->addMetaData(QStringLiteral("customHTTPHeader"), headers); + job->addMetaData(QStringLiteral("cookies"), QStringLiteral("none")); + job->addMetaData(QStringLiteral("no-auth-prompt"), QStringLiteral("true")); + job->setRedirectionHandlingEnabled(false); + + connect(job, &KIO::StoredTransferJob::result, this, [d](KJob *job) { + d->davJobFinished(job); + }); +} + +DavItem DavItemCreateJob::item() const +{ + Q_D(const DavItemCreateJob); + return d->mItem; +} + +QUrl DavItemCreateJob::itemUrl() const +{ + Q_D(const DavItemCreateJob); + return d->mItem.url().url(); +} + +void DavItemCreateJobPrivate::davJobFinished(KJob *job) +{ + Q_Q(DavItemCreateJob); + KIO::StoredTransferJob *storedJob = qobject_cast(job); + const QString responseCodeStr = storedJob->queryMetaData(QStringLiteral("responsecode")); + const int responseCode = responseCodeStr.isEmpty() ? 0 : responseCodeStr.toInt(); + if (storedJob->error()) { + setLatestResponseCode(responseCode); + setError(ERR_ITEMCREATE); + setJobErrorText(storedJob->errorText()); + setJobError(storedJob->error()); + setErrorTextFromDavError(); + + emitResult(); + return; + } + + // The 'Location:' HTTP header is used to indicate the new URL + const QStringList allHeaders = storedJob->queryMetaData(QStringLiteral("HTTP-Headers")).split(QLatin1Char('\n')); + QString location; + for (const QString &header : allHeaders) { + if (header.startsWith(QLatin1String("location:"), Qt::CaseInsensitive)) { + location = header.section(QLatin1Char(' '), 1); + } + } + + QUrl url; + if (location.isEmpty()) { + url = storedJob->url(); + } else if (location.startsWith(QLatin1Char('/'))) { + url = storedJob->url(); + url.setPath(location, QUrl::TolerantMode); + } else { + url = QUrl::fromUserInput(location); + } + + if (responseCode == 301 || responseCode == 302 || responseCode == 307 || responseCode == 308) { + if (mRedirectCount > 4) { + setLatestResponseCode(responseCode); + setError(DavItemCreateJob::UserDefinedError + responseCode); + emitResult(); + } else { + QUrl _itemUrl(url); + _itemUrl.setUserInfo(q->itemUrl().userInfo()); + mItem.setUrl(DavUrl(_itemUrl, mItem.url().protocol())); + + ++mRedirectCount; + q->start(); + } + + return; + } + + url.setUserInfo(q->itemUrl().userInfo()); + mItem.setUrl(DavUrl(url, mItem.url().protocol())); + + DavItemFetchJob *fetchJob = new DavItemFetchJob(mItem); + QObject::connect(fetchJob, &DavItemFetchJob::result, q, [this](KJob *job) { + itemRefreshed(job); + }); + fetchJob->start(); +} + +void DavItemCreateJobPrivate::itemRefreshed(KJob *job) +{ + if (!job->error()) { + DavItemFetchJob *fetchJob = qobject_cast(job); + mItem.setEtag(fetchJob->item().etag()); + } + emitResult(); +} diff --git a/src/common/davitemcreatejob.h b/src/common/davitemcreatejob.h new file mode 100644 index 0000000..fb38a5c --- /dev/null +++ b/src/common/davitemcreatejob.h @@ -0,0 +1,56 @@ +/* + SPDX-FileCopyrightText: 2010 Tobias Koenig + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KDAV_DAVITEMCREATEJOB_H +#define KDAV_DAVITEMCREATEJOB_H + +#include "kdav_export.h" + +#include "davitem.h" +#include "davjobbase.h" +#include "davurl.h" + +namespace KDAV +{ +class DavItemCreateJobPrivate; + +/** + * @class DavItemCreateJob davitemcreatejob.h + * + * @short A job to create a DAV item on the DAV server. + */ +class KDAV_EXPORT DavItemCreateJob : public DavJobBase +{ + Q_OBJECT + +public: + /** + * Creates a new DAV item create job. + * + * @param item The item that shall be created. + * @param parent The parent object. + */ + explicit DavItemCreateJob(const DavItem &item, QObject *parent = nullptr); + + /** + * Starts the job. + */ + void start() override; + + /** + * Returns the created DAV item including the correct identifier URL + * and current ETag information. + */ + Q_REQUIRED_RESULT DavItem item() const; + + Q_REQUIRED_RESULT QUrl itemUrl() const; + +private: + Q_DECLARE_PRIVATE(DavItemCreateJob) +}; +} + +#endif diff --git a/src/common/davitemdeletejob.cpp b/src/common/davitemdeletejob.cpp new file mode 100644 index 0000000..63d6107 --- /dev/null +++ b/src/common/davitemdeletejob.cpp @@ -0,0 +1,106 @@ +/* + SPDX-FileCopyrightText: 2010 Tobias Koenig + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "davitemdeletejob.h" +#include "davjobbase_p.h" + +#include "daverror.h" +#include "davitemfetchjob.h" +#include "davmanager_p.h" + +#include +#include + +using namespace KDAV; + +namespace KDAV +{ +class DavItemDeleteJobPrivate : public DavJobBasePrivate +{ +public: + void davJobFinished(KJob *job); + void conflictingItemFetched(KJob *job); + + DavItem mItem; + DavItem mFreshItem; + int mFreshResponseCode = -1; +}; +} + +DavItemDeleteJob::DavItemDeleteJob(const DavItem &item, QObject *parent) + : DavJobBase(new DavItemDeleteJobPrivate, parent) +{ + Q_D(DavItemDeleteJob); + d->mItem = item; +} + +void DavItemDeleteJob::start() +{ + Q_D(DavItemDeleteJob); + KIO::DeleteJob *job = KIO::del(d->mItem.url().url(), KIO::HideProgressInfo | KIO::DefaultFlags); + job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true")); + job->addMetaData(QStringLiteral("customHTTPHeader"), QStringLiteral("If-Match: ") + d->mItem.etag()); + job->addMetaData(QStringLiteral("cookies"), QStringLiteral("none")); + job->addMetaData(QStringLiteral("no-auth-prompt"), QStringLiteral("true")); + + connect(job, &KIO::DeleteJob::result, this, [d](KJob *job) { + d->davJobFinished(job); + }); +} + +DavItem DavItemDeleteJob::freshItem() const +{ + Q_D(const DavItemDeleteJob); + return d->mFreshItem; +} + +int DavItemDeleteJob::freshResponseCode() const +{ + Q_D(const DavItemDeleteJob); + return d->mFreshResponseCode; +} + +void DavItemDeleteJobPrivate::davJobFinished(KJob *job) +{ + KIO::DeleteJob *deleteJob = qobject_cast(job); + + if (deleteJob->error() && deleteJob->error() != KIO::ERR_NO_CONTENT) { + const int responseCode = deleteJob->queryMetaData(QStringLiteral("responsecode")).isEmpty() // + ? 0 + : deleteJob->queryMetaData(QStringLiteral("responsecode")).toInt(); + + if (responseCode != 404 && responseCode != 410) { + setLatestResponseCode(responseCode); + setError(ERR_ITEMDELETE); + setJobErrorText(deleteJob->errorText()); + setJobError(deleteJob->error()); + setErrorTextFromDavError(); + } + + if (q_ptr->hasConflict()) { + DavItemFetchJob *fetchJob = new DavItemFetchJob(mItem); + QObject::connect(fetchJob, &DavItemFetchJob::result, q_ptr, [this](KJob *job) { + conflictingItemFetched(job); + }); + fetchJob->start(); + return; + } + } + + emitResult(); +} + +void DavItemDeleteJobPrivate::conflictingItemFetched(KJob *job) +{ + DavItemFetchJob *fetchJob = qobject_cast(job); + mFreshResponseCode = fetchJob->latestResponseCode(); + + if (!job->error()) { + mFreshItem = fetchJob->item(); + } + + emitResult(); +} diff --git a/src/common/davitemdeletejob.h b/src/common/davitemdeletejob.h new file mode 100644 index 0000000..e24a1d3 --- /dev/null +++ b/src/common/davitemdeletejob.h @@ -0,0 +1,58 @@ +/* + SPDX-FileCopyrightText: 2010 Tobias Koenig + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KDAV_DAVITEMDELETEJOB_H +#define KDAV_DAVITEMDELETEJOB_H + +#include "kdav_export.h" + +#include "davitem.h" +#include "davjobbase.h" +#include "davurl.h" + +namespace KDAV +{ +class DavItemDeleteJobPrivate; + +/** + * @class DavItemDeleteJob davitemdeletejob.h + * + * @short A job to delete a DAV item on the DAV server. + */ +class KDAV_EXPORT DavItemDeleteJob : public DavJobBase +{ + Q_OBJECT + +public: + /** + * Creates a new DAV item delete job. + * + * @param item The item that shall be deleted. + * @param parent The parent object. + */ + explicit DavItemDeleteJob(const DavItem &item, QObject *parent = nullptr); + + /** + * Starts the job. + */ + void start() override; + + /** + * Returns the item that triggered the conflict, if any. + */ + Q_REQUIRED_RESULT DavItem freshItem() const; + + /** + * Returns the response code we got when fetching the fresh item. + */ + Q_REQUIRED_RESULT int freshResponseCode() const; + +private: + Q_DECLARE_PRIVATE(DavItemDeleteJob) +}; +} + +#endif diff --git a/src/common/davitemfetchjob.cpp b/src/common/davitemfetchjob.cpp new file mode 100644 index 0000000..2954c61 --- /dev/null +++ b/src/common/davitemfetchjob.cpp @@ -0,0 +1,94 @@ +/* + SPDX-FileCopyrightText: 2010 Tobias Koenig + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "davitemfetchjob.h" +#include "davjobbase_p.h" + +#include "daverror.h" +#include "davmanager_p.h" + +#include +#include + +using namespace KDAV; +namespace KDAV +{ +class DavItemFetchJobPrivate : public DavJobBasePrivate +{ +public: + void davJobFinished(KJob *job); + + DavUrl mUrl; + DavItem mItem; +}; +} + +static QString etagFromHeaders(const QString &headers) +{ + const QStringList allHeaders = headers.split(QLatin1Char('\n')); + + QString etag; + for (const QString &header : allHeaders) { + if (header.startsWith(QLatin1String("etag:"), Qt::CaseInsensitive)) { + etag = header.section(QLatin1Char(' '), 1); + } + } + + return etag; +} + +DavItemFetchJob::DavItemFetchJob(const DavItem &item, QObject *parent) + : DavJobBase(new DavItemFetchJobPrivate, parent) +{ + Q_D(DavItemFetchJob); + d->mItem = item; +} + +void DavItemFetchJob::start() +{ + Q_D(DavItemFetchJob); + KIO::StoredTransferJob *job = KIO::storedGet(d->mItem.url().url(), KIO::Reload, KIO::HideProgressInfo | KIO::DefaultFlags); + job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true")); + // Work around a strange bug in Zimbra (seen at least on CE 5.0.18) : if the user-agent + // contains "Mozilla", some strange debug data is displayed in the shared calendars. + // This kinda mess up the events parsing... + job->addMetaData(QStringLiteral("UserAgent"), QStringLiteral("KDE DAV groupware client")); + job->addMetaData(QStringLiteral("cookies"), QStringLiteral("none")); + job->addMetaData(QStringLiteral("no-auth-prompt"), QStringLiteral("true")); + + connect(job, &KIO::StoredTransferJob::result, this, [d](KJob *job) { + d->davJobFinished(job); + }); +} + +DavItem DavItemFetchJob::item() const +{ + Q_D(const DavItemFetchJob); + return d->mItem; +} + +void DavItemFetchJobPrivate::davJobFinished(KJob *job) +{ + KIO::StoredTransferJob *storedJob = qobject_cast(job); + const QString responseCodeStr = storedJob->queryMetaData(QStringLiteral("responsecode")); + const int responseCode = responseCodeStr.isEmpty() ? 0 : responseCodeStr.toInt(); + + setLatestResponseCode(responseCode); + + if (storedJob->error()) { + setLatestResponseCode(responseCode); + setError(ERR_PROBLEM_WITH_REQUEST); + setJobErrorText(storedJob->errorText()); + setJobError(storedJob->error()); + setErrorTextFromDavError(); + } else { + mItem.setData(storedJob->data()); + mItem.setContentType(storedJob->queryMetaData(QStringLiteral("content-type"))); + mItem.setEtag(etagFromHeaders(storedJob->queryMetaData(QStringLiteral("HTTP-Headers")))); + } + + emitResult(); +} diff --git a/src/common/davitemfetchjob.h b/src/common/davitemfetchjob.h new file mode 100644 index 0000000..a545149 --- /dev/null +++ b/src/common/davitemfetchjob.h @@ -0,0 +1,53 @@ +/* + SPDX-FileCopyrightText: 2010 Tobias Koenig + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KDAV_DAVITEMFETCHJOB_H +#define KDAV_DAVITEMFETCHJOB_H + +#include "kdav_export.h" + +#include "davitem.h" +#include "davjobbase.h" +#include "davurl.h" + +namespace KDAV +{ +class DavItemFetchJobPrivate; + +/** + * @class DavItemFetchJob davitemfetchjob.h + * + * @short A job that fetches a DAV item from the DAV server. + */ +class KDAV_EXPORT DavItemFetchJob : public DavJobBase +{ + Q_OBJECT + +public: + /** + * Creates a new DAV item fetch job. + * + * @param item The item that shall be fetched. + * @param parent The parent object. + */ + explicit DavItemFetchJob(const DavItem &item, QObject *parent = nullptr); + + /** + * Starts the job. + */ + void start() override; + + /** + * Returns the fetched item including current ETag information. + */ + Q_REQUIRED_RESULT DavItem item() const; + +private: + Q_DECLARE_PRIVATE(DavItemFetchJob) +}; +} + +#endif diff --git a/src/common/davitemmodifyjob.cpp b/src/common/davitemmodifyjob.cpp new file mode 100644 index 0000000..81df8fb --- /dev/null +++ b/src/common/davitemmodifyjob.cpp @@ -0,0 +1,163 @@ +/* + SPDX-FileCopyrightText: 2010 Tobias Koenig + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "davitemmodifyjob.h" +#include "davjobbase_p.h" + +#include "daverror.h" +#include "davitemfetchjob.h" +#include "davmanager_p.h" + +#include + +using namespace KDAV; +namespace KDAV +{ +class DavItemModifyJobPrivate : public DavJobBasePrivate +{ +public: + void davJobFinished(KJob *job); + void itemRefreshed(KJob *job); + void conflictingItemFetched(KJob *job); + + DavItem mItem; + DavItem mFreshItem; + int mFreshResponseCode = 0; + + Q_DECLARE_PUBLIC(DavItemModifyJob) +}; +} + +DavItemModifyJob::DavItemModifyJob(const DavItem &item, QObject *parent) + : DavJobBase(new DavItemModifyJobPrivate, parent) +{ + Q_D(DavItemModifyJob); + d->mItem = item; +} + +void DavItemModifyJob::start() +{ + Q_D(DavItemModifyJob); + QString headers = QStringLiteral("Content-Type: "); + headers += d->mItem.contentType(); + headers += QLatin1String("\r\n"); + headers += QLatin1String("If-Match: ") + d->mItem.etag(); + + KIO::StoredTransferJob *job = KIO::storedPut(d->mItem.data(), itemUrl(), -1, KIO::HideProgressInfo | KIO::DefaultFlags); + job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true")); + job->addMetaData(QStringLiteral("customHTTPHeader"), headers); + job->addMetaData(QStringLiteral("cookies"), QStringLiteral("none")); + job->addMetaData(QStringLiteral("no-auth-prompt"), QStringLiteral("true")); + + connect(job, &KIO::StoredTransferJob::result, this, [d](KJob *job) { + d->davJobFinished(job); + }); +} + +DavItem DavItemModifyJob::item() const +{ + Q_D(const DavItemModifyJob); + return d->mItem; +} + +DavItem DavItemModifyJob::freshItem() const +{ + Q_D(const DavItemModifyJob); + return d->mFreshItem; +} + +int DavItemModifyJob::freshResponseCode() const +{ + Q_D(const DavItemModifyJob); + return d->mFreshResponseCode; +} + +QUrl DavItemModifyJob::itemUrl() const +{ + Q_D(const DavItemModifyJob); + return d->mItem.url().url(); +} + +void DavItemModifyJobPrivate::davJobFinished(KJob *job) +{ + Q_Q(DavItemModifyJob); + KIO::StoredTransferJob *storedJob = qobject_cast(job); + + if (storedJob->error()) { + const int responseCode = storedJob->queryMetaData(QStringLiteral("responsecode")).isEmpty() // + ? 0 + : storedJob->queryMetaData(QStringLiteral("responsecode")).toInt(); + + setLatestResponseCode(responseCode); + setError(ERR_ITEMMODIFY); + setJobErrorText(storedJob->errorText()); + setJobError(storedJob->error()); + setErrorTextFromDavError(); + + if (q->hasConflict()) { + DavItemFetchJob *fetchJob = new DavItemFetchJob(mItem); + QObject::connect(fetchJob, &DavItemFetchJob::result, q, [this](KJob *job) { + conflictingItemFetched(job); + }); + fetchJob->start(); + } else { + emitResult(); + } + + return; + } + + // The 'Location:' HTTP header is used to indicate the new URL + const QStringList allHeaders = storedJob->queryMetaData(QStringLiteral("HTTP-Headers")).split(QLatin1Char('\n')); + QString location; + for (const QString &header : allHeaders) { + if (header.startsWith(QLatin1String("location:"), Qt::CaseInsensitive)) { + location = header.section(QLatin1Char(' '), 1); + } + } + + QUrl url; + if (location.isEmpty()) { + url = storedJob->url(); + } else if (location.startsWith(QLatin1Char('/'))) { + url = storedJob->url(); + url.setPath(location, QUrl::TolerantMode); + } else { + url = QUrl::fromUserInput(location); + } + + url.setUserInfo(q->itemUrl().userInfo()); + mItem.setUrl(DavUrl(url, mItem.url().protocol())); + + DavItemFetchJob *fetchJob = new DavItemFetchJob(mItem); + QObject::connect(fetchJob, &DavItemFetchJob::result, q, [this](KJob *job) { + itemRefreshed(job); + }); + fetchJob->start(); +} + +void DavItemModifyJobPrivate::itemRefreshed(KJob *job) +{ + if (!job->error()) { + DavItemFetchJob *fetchJob = qobject_cast(job); + mItem.setEtag(fetchJob->item().etag()); + } else { + mItem.setEtag(QString()); + } + emitResult(); +} + +void DavItemModifyJobPrivate::conflictingItemFetched(KJob *job) +{ + DavItemFetchJob *fetchJob = qobject_cast(job); + mFreshResponseCode = fetchJob->latestResponseCode(); + + if (!job->error()) { + mFreshItem = fetchJob->item(); + } + + emitResult(); +} diff --git a/src/common/davitemmodifyjob.h b/src/common/davitemmodifyjob.h new file mode 100644 index 0000000..911f25e --- /dev/null +++ b/src/common/davitemmodifyjob.h @@ -0,0 +1,65 @@ +/* + SPDX-FileCopyrightText: 2010 Tobias Koenig + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KDAV_DAVITEMMODIFYJOB_H +#define KDAV_DAVITEMMODIFYJOB_H + +#include "kdav_export.h" + +#include "davitem.h" +#include "davjobbase.h" +#include "davurl.h" + +namespace KDAV +{ +class DavItemModifyJobPrivate; + +/** + * @class DavItemModifyJob davitemmodifyjob.h + * + * @short A job that modifies a DAV item on the DAV server. + */ +class KDAV_EXPORT DavItemModifyJob : public DavJobBase +{ + Q_OBJECT + +public: + /** + * Creates a new DAV item modify job. + * + * @param item The item that shall be modified. + * @param parent The parent object. + */ + explicit DavItemModifyJob(const DavItem &item, QObject *parent = nullptr); + + /** + * Starts the job. + */ + void start() override; + + /** + * Returns the modified item including the updated ETag information. + */ + Q_REQUIRED_RESULT DavItem item() const; + + Q_REQUIRED_RESULT QUrl itemUrl() const; + + /** + * Returns the item that triggered the conflict, if any. + */ + Q_REQUIRED_RESULT DavItem freshItem() const; + + /** + * Returns the response code we got when fetching the fresh item. + */ + Q_REQUIRED_RESULT int freshResponseCode() const; + +private: + Q_DECLARE_PRIVATE(DavItemModifyJob) +}; +} + +#endif diff --git a/src/common/davitemsfetchjob.cpp b/src/common/davitemsfetchjob.cpp new file mode 100644 index 0000000..93cf9e4 --- /dev/null +++ b/src/common/davitemsfetchjob.cpp @@ -0,0 +1,167 @@ +/* + SPDX-FileCopyrightText: 2010 Grégory Oestreicher + + Based on DavItemsListJob: + SPDX-FileCopyrightText: 2010 Tobias Koenig + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "davitemsfetchjob.h" +#include "davjobbase_p.h" + +#include "daverror.h" +#include "davmanager_p.h" +#include "davmultigetprotocol_p.h" +#include "utils_p.h" + +#include +#include + +using namespace KDAV; + +namespace KDAV +{ +class DavItemsFetchJobPrivate : public DavJobBasePrivate +{ +public: + void davJobFinished(KJob *job); + + DavUrl mCollectionUrl; + QStringList mUrls; + QMap mItems; +}; +} + +DavItemsFetchJob::DavItemsFetchJob(const DavUrl &collectionUrl, const QStringList &urls, QObject *parent) + : DavJobBase(new DavItemsFetchJobPrivate, parent) +{ + Q_D(DavItemsFetchJob); + d->mCollectionUrl = collectionUrl; + d->mUrls = urls; +} + +void DavItemsFetchJob::start() +{ + Q_D(DavItemsFetchJob); + const DavMultigetProtocol *protocol = dynamic_cast(DavManager::davProtocol(d->mCollectionUrl.protocol())); + if (!protocol) { + setError(ERR_NO_MULTIGET); + d->setErrorTextFromDavError(); + emitResult(); + return; + } + + const QDomDocument report = protocol->itemsReportQuery(d->mUrls)->buildQuery(); + KIO::DavJob *job = DavManager::self()->createReportJob(d->mCollectionUrl.url(), report.toString(), QStringLiteral("0")); + job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true")); + connect(job, &KIO::DavJob::result, this, [d](KJob *job) { + d->davJobFinished(job); + }); +} + +DavItem::List DavItemsFetchJob::items() const +{ + Q_D(const DavItemsFetchJob); + DavItem::List values; + values.reserve(d->mItems.size()); + for (const auto &value : std::as_const(d->mItems)) { + values << value; + } + return values; +} + +DavItem DavItemsFetchJob::item(const QString &url) const +{ + Q_D(const DavItemsFetchJob); + return d->mItems.value(url); +} + +void DavItemsFetchJobPrivate::davJobFinished(KJob *job) +{ + KIO::DavJob *davJob = qobject_cast(job); + const QString responseCodeStr = davJob->queryMetaData(QStringLiteral("responsecode")); + const int responseCode = responseCodeStr.isEmpty() ? 0 : responseCodeStr.toInt(); + + // KIO::DavJob does not set error() even if the HTTP status code is a 4xx or a 5xx + if (davJob->error() || (responseCode >= 400 && responseCode < 600)) { + setLatestResponseCode(responseCode); + setError(ERR_PROBLEM_WITH_REQUEST); + setJobErrorText(davJob->errorText()); + setJobError(davJob->error()); + setErrorTextFromDavError(); + + emitResult(); + return; + } + + const DavMultigetProtocol *protocol = static_cast(DavManager::davProtocol(mCollectionUrl.protocol())); + + QDomDocument document; + document.setContent(davJob->responseData(), true); + const QDomElement documentElement = document.documentElement(); + + QDomElement responseElement = Utils::firstChildElementNS(documentElement, QStringLiteral("DAV:"), QStringLiteral("response")); + + while (!responseElement.isNull()) { + QDomElement propstatElement = Utils::firstChildElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("propstat")); + + if (propstatElement.isNull()) { + responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); + continue; + } + + // Check for errors + const QDomElement statusElement = Utils::firstChildElementNS(propstatElement, QStringLiteral("DAV:"), QStringLiteral("status")); + if (!statusElement.text().contains(QLatin1String("200"))) { + responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); + continue; + } + + const QDomElement propElement = Utils::firstChildElementNS(propstatElement, QStringLiteral("DAV:"), QStringLiteral("prop")); + + DavItem item; + + // extract path + const QDomElement hrefElement = Utils::firstChildElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("href")); + const QString href = hrefElement.text(); + + QUrl url = davJob->url(); + if (href.startsWith(QLatin1Char('/'))) { + // href is only a path, use request url to complete + url.setPath(href, QUrl::TolerantMode); + } else { + // href is a complete url + url = QUrl::fromUserInput(href); + } + + auto _url = url; + _url.setUserInfo(mCollectionUrl.url().userInfo()); + item.setUrl(DavUrl(_url, mCollectionUrl.protocol())); + + // extract ETag + const QDomElement getetagElement = Utils::firstChildElementNS(propElement, QStringLiteral("DAV:"), QStringLiteral("getetag")); + item.setEtag(getetagElement.text()); + + // extract content + const QDomElement dataElement = Utils::firstChildElementNS(propElement, protocol->responseNamespace(), protocol->dataTagName()); + + if (dataElement.isNull()) { + responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); + continue; + } + + const QByteArray data = dataElement.firstChild().toText().data().toUtf8(); + if (data.isEmpty()) { + responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); + continue; + } + + item.setData(data); + + mItems.insert(item.url().toDisplayString(), item); + responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); + } + + emitResult(); +} diff --git a/src/common/davitemsfetchjob.h b/src/common/davitemsfetchjob.h new file mode 100644 index 0000000..f08dd97 --- /dev/null +++ b/src/common/davitemsfetchjob.h @@ -0,0 +1,64 @@ +/* + SPDX-FileCopyrightText: 2010 Grégory Oestreicher + + Based on DavItemsListJob: + SPDX-FileCopyrightText: 2010 Tobias Koenig + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KDAV_DAVITEMSFETCHJOB_H +#define KDAV_DAVITEMSFETCHJOB_H + +#include "kdav_export.h" + +#include "davitem.h" +#include "davjobbase.h" +#include "davurl.h" + +#include + +namespace KDAV +{ +class DavItemsFetchJobPrivate; + +/** + * @class DavItemsFetchJob davitemsfetchjob.h + * + * @short A job that fetches a list of items from a DAV server using a MULTIGET query. + */ +class KDAV_EXPORT DavItemsFetchJob : public DavJobBase +{ + Q_OBJECT + +public: + /** + * Creates a new items fetch job. + * + * @param collectionUrl The DAV collection on which to run the query + * @param urls The list of URLs to fetch + * @param parent The parent object + */ + DavItemsFetchJob(const DavUrl &collectionUrl, const QStringList &urls, QObject *parent = nullptr); + + /** + * Starts the job. + */ + void start() override; + + /** + * Returns the list of fetched items + */ + Q_REQUIRED_RESULT DavItem::List items() const; + + /** + * Return the item found at @p url + */ + Q_REQUIRED_RESULT DavItem item(const QString &url) const; + +private: + Q_DECLARE_PRIVATE(DavItemsFetchJob) +}; +} + +#endif diff --git a/src/common/davitemslistjob.cpp b/src/common/davitemslistjob.cpp new file mode 100644 index 0000000..702374f --- /dev/null +++ b/src/common/davitemslistjob.cpp @@ -0,0 +1,267 @@ +/* + SPDX-FileCopyrightText: 2010 Tobias Koenig + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "davitemslistjob.h" +#include "davjobbase_p.h" + +#include "daverror.h" +#include "davmanager_p.h" +#include "davprotocolbase_p.h" +#include "davurl.h" +#include "etagcache.h" +#include "utils_p.h" + +#include +#include + +#include + +using namespace KDAV; + +namespace KDAV +{ +class DavItemsListJobPrivate : public DavJobBasePrivate +{ +public: + void davJobFinished(KJob *job); + + DavUrl mUrl; + std::shared_ptr mEtagCache; + QStringList mMimeTypes; + QString mRangeStart; + QString mRangeEnd; + DavItem::List mItems; + std::set mSeenUrls; // to prevent events duplication with some servers + DavItem::List mChangedItems; + QStringList mDeletedItems; + uint mSubJobCount = 0; +}; +} + +DavItemsListJob::DavItemsListJob(const DavUrl &url, const std::shared_ptr &cache, QObject *parent) + : DavJobBase(new DavItemsListJobPrivate, parent) +{ + Q_D(DavItemsListJob); + d->mUrl = url; + d->mEtagCache = cache; +} + +DavItemsListJob::~DavItemsListJob() = default; + +void DavItemsListJob::setContentMimeTypes(const QStringList &types) +{ + Q_D(DavItemsListJob); + d->mMimeTypes = types; +} + +void DavItemsListJob::setTimeRange(const QString &start, const QString &end) +{ + Q_D(DavItemsListJob); + d->mRangeStart = start; + d->mRangeEnd = end; +} + +void DavItemsListJob::start() +{ + Q_D(DavItemsListJob); + const DavProtocolBase *protocol = DavManager::davProtocol(d->mUrl.protocol()); + Q_ASSERT(protocol); + + const auto queries = protocol->itemsQueries(); + for (XMLQueryBuilder::Ptr builder : queries) { + if (!d->mRangeStart.isEmpty()) { + builder->setParameter(QStringLiteral("start"), d->mRangeStart); + } + if (!d->mRangeEnd.isEmpty()) { + builder->setParameter(QStringLiteral("end"), d->mRangeEnd); + } + + const QDomDocument props = builder->buildQuery(); + const QString mimeType = builder->mimeType(); + + if (d->mMimeTypes.isEmpty() || d->mMimeTypes.contains(mimeType)) { + ++d->mSubJobCount; + if (protocol->useReport()) { + KIO::DavJob *job = DavManager::self()->createReportJob(d->mUrl.url(), props.toString()); + job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true")); + job->setProperty("davType", QStringLiteral("report")); + job->setProperty("itemsMimeType", mimeType); + connect(job, &KIO::DavJob::result, this, [d](KJob *job) { + d->davJobFinished(job); + }); + } else { + KIO::DavJob *job = DavManager::self()->createPropFindJob(d->mUrl.url(), props.toString()); + job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true")); + job->setProperty("davType", QStringLiteral("propFind")); + job->setProperty("itemsMimeType", mimeType); + connect(job, &KIO::DavJob::result, this, [d](KJob *job) { + d->davJobFinished(job); + }); + } + } + } + + if (d->mSubJobCount == 0) { + setError(ERR_ITEMLIST_NOMIMETYPE); + d->setErrorTextFromDavError(); + emitResult(); + } +} + +DavItem::List DavItemsListJob::items() const +{ + Q_D(const DavItemsListJob); + return d->mItems; +} + +DavItem::List DavItemsListJob::changedItems() const +{ + Q_D(const DavItemsListJob); + return d->mChangedItems; +} + +QStringList DavItemsListJob::deletedItems() const +{ + Q_D(const DavItemsListJob); + return d->mDeletedItems; +} + +void DavItemsListJobPrivate::davJobFinished(KJob *job) +{ + KIO::DavJob *davJob = qobject_cast(job); + const int responseCode = davJob->queryMetaData(QStringLiteral("responsecode")).isEmpty() // + ? 0 + : davJob->queryMetaData(QStringLiteral("responsecode")).toInt(); + + // KIO::DavJob does not set error() even if the HTTP status code is a 4xx or a 5xx + if (davJob->error() || (responseCode >= 400 && responseCode < 600)) { + setLatestResponseCode(responseCode); + setError(ERR_PROBLEM_WITH_REQUEST); + setJobErrorText(davJob->errorText()); + setJobError(davJob->error()); + setErrorTextFromDavError(); + } else { + /* + * Extract data from a document like the following: + * + * + * + * /caldav.php/test1.user/home/KOrganizer-166749289.780.ics + * + * + * "b4bbea0278f4f63854c4167a7656024a" + * + * HTTP/1.1 200 OK + * + * + * + * /caldav.php/test1.user/home/KOrganizer-399416366.464.ics + * + * + * "52eb129018398a7da4f435b2bc4c6cd5" + * + * HTTP/1.1 200 OK + * + * + * + */ + + const QString itemsMimeType = job->property("itemsMimeType").toString(); + QDomDocument document; + document.setContent(davJob->responseData(), true); + const QDomElement documentElement = document.documentElement(); + + QDomElement responseElement = Utils::firstChildElementNS(documentElement, QStringLiteral("DAV:"), QStringLiteral("response")); + while (!responseElement.isNull()) { + QDomElement propstatElement; + + // check for the valid propstat, without giving up on first error + { + const QDomNodeList propstats = responseElement.elementsByTagNameNS(QStringLiteral("DAV:"), QStringLiteral("propstat")); + for (int i = 0; i < propstats.length(); ++i) { + const QDomElement propstatCandidate = propstats.item(i).toElement(); + const QDomElement statusElement = Utils::firstChildElementNS(propstatCandidate, QStringLiteral("DAV:"), QStringLiteral("status")); + if (statusElement.text().contains(QLatin1String("200"))) { + propstatElement = propstatCandidate; + } + } + } + + if (propstatElement.isNull()) { + responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); + continue; + } + + const QDomElement propElement = Utils::firstChildElementNS(propstatElement, QStringLiteral("DAV:"), QStringLiteral("prop")); + + // check whether it is a DAV collection ... + const QDomElement resourcetypeElement = Utils::firstChildElementNS(propElement, QStringLiteral("DAV:"), QStringLiteral("resourcetype")); + if (!resourcetypeElement.isNull()) { + const QDomElement collectionElement = Utils::firstChildElementNS(resourcetypeElement, QStringLiteral("DAV:"), QStringLiteral("collection")); + if (!collectionElement.isNull()) { + responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); + continue; + } + } + + // ... if not it is an item + DavItem item; + item.setContentType(itemsMimeType); + + // extract path + const QDomElement hrefElement = Utils::firstChildElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("href")); + const QString href = hrefElement.text(); + + QUrl url = davJob->url(); + url.setUserInfo(QString()); + if (href.startsWith(QLatin1Char('/'))) { + // href is only a path, use request url to complete + url.setPath(href, QUrl::TolerantMode); + } else { + // href is a complete url + url = QUrl::fromUserInput(href); + } + + const QString itemUrl = url.toDisplayString(); + const auto [it, isInserted] = mSeenUrls.insert(itemUrl); + if (!isInserted) { + responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); + continue; + } + + auto _url = url; + _url.setUserInfo(mUrl.url().userInfo()); + item.setUrl(DavUrl(_url, mUrl.protocol())); + + // extract ETag + const QDomElement getetagElement = Utils::firstChildElementNS(propElement, QStringLiteral("DAV:"), QStringLiteral("getetag")); + + item.setEtag(getetagElement.text()); + + mItems << item; + + if (mEtagCache->etagChanged(itemUrl, item.etag())) { + mChangedItems << item; + } + + responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); + } + } + + mDeletedItems.clear(); + + const auto map = mEtagCache->etagCacheMap(); + for (auto it = map.cbegin(); it != map.cend(); ++it) { + const QString remoteId = it.key(); + if (mSeenUrls.find(remoteId) == mSeenUrls.cend()) { + mDeletedItems.append(remoteId); + } + } + + if (--mSubJobCount == 0) { + emitResult(); + } +} diff --git a/src/common/davitemslistjob.h b/src/common/davitemslistjob.h new file mode 100644 index 0000000..d326f4f --- /dev/null +++ b/src/common/davitemslistjob.h @@ -0,0 +1,88 @@ +/* + SPDX-FileCopyrightText: 2010 Tobias Koenig + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KDAV_DAVITEMSLISTJOB_H +#define KDAV_DAVITEMSLISTJOB_H + +#include "kdav_export.h" + +#include "davitem.h" +#include "davjobbase.h" + +#include + +#include + +namespace KDAV +{ +class EtagCache; +class DavUrl; +class DavItemsListJobPrivate; + +/** + * @class DavItemsListJob davitemslistjob.h + * + * @short A job that lists all DAV items inside a DAV collection. + */ +class KDAV_EXPORT DavItemsListJob : public DavJobBase +{ + Q_OBJECT + +public: + /** + * Creates a new DAV items list job. + * + * @param url The URL of the DAV collection. + * @param parent The parent object. + */ + DavItemsListJob(const DavUrl &url, const std::shared_ptr &cache, QObject *parent = nullptr); + + ~DavItemsListJob() override; + + /** + * Limits the mime types of the items requested. + * + * If no mime type is given then all will be requested. + * + * @param types The list of mime types to include + */ + void setContentMimeTypes(const QStringList &types); + + /** + * Sets the start and end time to list items for. + * + * @param start The range start, in format "date with UTC time" + * @param end The range end, in format "date with UTC time" + */ + void setTimeRange(const QString &start, const QString &end); + + /** + * Starts the job. + */ + void start() override; + + /** + * Returns the list of items seen including identifier URL and ETag information. + */ + Q_REQUIRED_RESULT DavItem::List items() const; + + /** + * Returns the list of items that were changed on the server. + */ + Q_REQUIRED_RESULT DavItem::List changedItems() const; + + /** + * Returns the list of items URLs that were not seen in the backend. + * As this is based on the ETag cache this may contain dependent items. + */ + Q_REQUIRED_RESULT QStringList deletedItems() const; + +private: + Q_DECLARE_PRIVATE(DavItemsListJob) +}; +} + +#endif diff --git a/src/common/davjobbase.cpp b/src/common/davjobbase.cpp new file mode 100644 index 0000000..ab1c28d --- /dev/null +++ b/src/common/davjobbase.cpp @@ -0,0 +1,127 @@ +/* + SPDX-FileCopyrightText: 2014 Gregory Oestreicher + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "davjobbase.h" +#include "davjobbase_p.h" + +#include "daverror.h" + +using namespace KDAV; + +DavJobBase::DavJobBase(QObject *parent) + : KJob(parent) + , d_ptr(new DavJobBasePrivate()) +{ + d_ptr->q_ptr = this; +} + +DavJobBase::DavJobBase(DavJobBasePrivate *dd, QObject *parent) + : KJob(parent) + , d_ptr(dd) +{ + d_ptr->q_ptr = this; +} + +DavJobBase::~DavJobBase() = default; + +int DavJobBase::latestResponseCode() const +{ + return d_ptr->mLatestResponseCode; +} + +bool DavJobBase::canRetryLater() const +{ + bool ret = false; + + // Be explicit and readable by splitting the if/else if clauses + + if (latestResponseCode() == 0 && error()) { + // Likely a timeout or a connection failure. + ret = true; + } else if (latestResponseCode() == 401) { + // Authentication required + ret = true; + } else if (latestResponseCode() == 402) { + // Payment required + ret = true; + } else if (latestResponseCode() == 407) { + // Proxy authentication required + ret = true; + } else if (latestResponseCode() == 408) { + // Request timeout + ret = true; + } else if (latestResponseCode() == 423) { + // Locked + ret = true; + } else if (latestResponseCode() == 429) { + // Too many requests + ret = true; + } else if (latestResponseCode() >= 501 && latestResponseCode() <= 504) { + // Various server-side errors + ret = true; + } else if (latestResponseCode() == 507) { + // Insufficient storage + ret = true; + } else if (latestResponseCode() == 511) { + // Network authentication required + ret = true; + } + + return ret; +} + +bool DavJobBase::hasConflict() const +{ + return latestResponseCode() == 412; +} + +void DavJobBasePrivate::setLatestResponseCode(int code) +{ + mLatestResponseCode = code; +} + +Error DavJobBase::davError() const +{ + return Error(static_cast(error()), d_ptr->mLatestResponseCode, d_ptr->mInternalErrorText, d_ptr->mJobErrorCode); +} + +void DavJobBasePrivate::setJobErrorText(const QString &errorText) +{ + mInternalErrorText = errorText; +} + +void DavJobBasePrivate::setJobError(int jobErrorCode) +{ + mJobErrorCode = jobErrorCode; +} + +void DavJobBasePrivate::setErrorTextFromDavError() +{ + q_ptr->setErrorText(q_ptr->davError().errorText()); +} + +void DavJobBasePrivate::setDavError(const Error &error) +{ + q_ptr->setError(error.errorNumber()); + setLatestResponseCode(error.responseCode()); + setJobErrorText(error.internalErrorText()); + setJobError(error.jobErrorCode()); +} + +void DavJobBasePrivate::setError(int errorCode) +{ + q_ptr->setError(errorCode); +} + +void DavJobBasePrivate::setErrorText(const QString &errorText) +{ + q_ptr->setErrorText(errorText); +} + +void DavJobBasePrivate::emitResult() +{ + q_ptr->emitResult(); +} diff --git a/src/common/davjobbase.h b/src/common/davjobbase.h new file mode 100644 index 0000000..1a4d9fc --- /dev/null +++ b/src/common/davjobbase.h @@ -0,0 +1,82 @@ +/* + SPDX-FileCopyrightText: 2014 Gregory Oestreicher + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KDAV_DAVJOBBASE_H +#define KDAV_DAVJOBBASE_H + +#include "kdav_export.h" + +#include + +#include + +namespace KDAV +{ +class DavJobBasePrivate; +class Error; + +/** + * @class DavJobBase davjobbase.h + * + * @short base class for the jobs used by the resource. + */ +class KDAV_EXPORT DavJobBase : public KJob +{ + Q_OBJECT + +public: + explicit DavJobBase(QObject *parent = nullptr); + ~DavJobBase() override; + + /** + * Get the latest response code. + * + * If no response code has been set then 0 will be returned, but will + * be meaningless unless error() is non-zero. In that case this means + * that the latest error was not at the HTTP level. + */ + Q_REQUIRED_RESULT int latestResponseCode() const; + + /** + * Check if the job can be retried later. + * + * This will return true for transient errors, i.e. if the response code + * is either zero and error() is set or if the HTTP response code hints + * at a temporary error. + * + * The HTTP response codes considered retryable are: + * - 401 + * - 402 + * - 407 + * - 408 + * - 423 + * - 429 + * - 501 to 504, inclusive + * - 507 + * - 511 + */ + Q_REQUIRED_RESULT bool canRetryLater() const; + + /** + * Check if the job failed because of a conflict + */ + Q_REQUIRED_RESULT bool hasConflict() const; + + /** + * Returns a instance of the KDAV:Error to be able to translate the error + */ + Q_REQUIRED_RESULT Error davError() const; + +protected: + Q_DECL_HIDDEN explicit DavJobBase(DavJobBasePrivate *dd, QObject *parent = nullptr); + std::unique_ptr d_ptr; + +private: + Q_DECLARE_PRIVATE(DavJobBase) +}; +} + +#endif diff --git a/src/common/davjobbase_p.h b/src/common/davjobbase_p.h new file mode 100644 index 0000000..bba4427 --- /dev/null +++ b/src/common/davjobbase_p.h @@ -0,0 +1,51 @@ +/* + SPDX-FileCopyrightText: 2014 Gregory Oestreicher + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KDAV_DAVJOBBASE_P_H +#define KDAV_DAVJOBBASE_P_H + +#include + +#include + +namespace KDAV +{ +class DavJobBase; + +class DavJobBasePrivate +{ +public: + virtual ~DavJobBasePrivate() = default; + + /** + * Sets the latest response code received. + * + * Only really useful in case of error, though success codes can + * also be set. + * + * @param code The code to set, should be a valid HTTP response code or zero. + */ + void setLatestResponseCode(int code); + + void setJobErrorText(const QString &errorText); + void setJobError(int jobErrorCode); + void setErrorTextFromDavError(); + void setDavError(const Error &error); + + // forwarded protected KJob API, so we can use this from subclasses of this + void setError(int errorCode); + void setErrorText(const QString &errorText); + void emitResult(); + + DavJobBase *q_ptr = nullptr; + int mLatestResponseCode = 0; + int mJobErrorCode = 0; + QString mInternalErrorText; +}; + +} + +#endif diff --git a/src/common/davmanager.cpp b/src/common/davmanager.cpp new file mode 100644 index 0000000..f28a770 --- /dev/null +++ b/src/common/davmanager.cpp @@ -0,0 +1,83 @@ +/* + SPDX-FileCopyrightText: 2010 Tobias Koenig + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "davmanager_p.h" + +#include "protocols/caldavprotocol_p.h" +#include "protocols/carddavprotocol_p.h" +#include "protocols/groupdavprotocol_p.h" + +#include + +#include "libkdav_debug.h" + +#include + +using namespace KDAV; + +DavManager::DavManager() = default; +DavManager::~DavManager() = default; + +DavManager *DavManager::self() +{ + static DavManager sSelf; + return &sSelf; +} + +KIO::DavJob *DavManager::createPropFindJob(const QUrl &url, const QString &document, const QString &depth) const +{ + KIO::DavJob *job = KIO::davPropFind(url, document, depth, KIO::HideProgressInfo | KIO::DefaultFlags); + + job->addMetaData(QStringLiteral("cookies"), QStringLiteral("none")); + job->addMetaData(QStringLiteral("no-auth-prompt"), QStringLiteral("true")); + job->setProperty("davDepth", QVariant::fromValue(depth)); + + return job; +} + +KIO::DavJob *DavManager::createReportJob(const QUrl &url, const QString &document, const QString &depth) const +{ + KIO::DavJob *job = KIO::davReport(url, document, depth, KIO::HideProgressInfo | KIO::DefaultFlags); + + job->addMetaData(QStringLiteral("cookies"), QStringLiteral("none")); + job->addMetaData(QStringLiteral("no-auth-prompt"), QStringLiteral("true")); + job->setProperty("davDepth", QVariant::fromValue(depth)); + + return job; +} + +KIO::DavJob *DavManager::createPropPatchJob(const QUrl &url, const QString &document) const +{ + KIO::DavJob *job = KIO::davPropPatch(url, document, KIO::HideProgressInfo | KIO::DefaultFlags); + const QString header = QStringLiteral("Content-Type: text/xml"); + job->addMetaData(QStringLiteral("customHTTPHeader"), header); + job->addMetaData(QStringLiteral("cookies"), QStringLiteral("none")); + job->addMetaData(QStringLiteral("no-auth-prompt"), QStringLiteral("true")); + return job; +} + +const DavProtocolBase *DavManager::davProtocol(Protocol protocol) +{ + const auto d = DavManager::self(); + if (!d->mProtocols[protocol]) { + switch (protocol) { + case KDAV::CalDav: + d->mProtocols[KDAV::CalDav].reset(new CaldavProtocol()); + break; + case KDAV::CardDav: + d->mProtocols[KDAV::CardDav].reset(new CarddavProtocol()); + break; + case KDAV::GroupDav: + d->mProtocols[KDAV::GroupDav].reset(new GroupdavProtocol()); + break; + default: + qCCritical(KDAV_LOG) << "Unknown protocol: " << static_cast(protocol); + return nullptr; + } + } + + return d->mProtocols[protocol].get(); +} diff --git a/src/common/davmanager_p.h b/src/common/davmanager_p.h new file mode 100644 index 0000000..4951001 --- /dev/null +++ b/src/common/davmanager_p.h @@ -0,0 +1,89 @@ +/* + SPDX-FileCopyrightText: 2010 Tobias Koenig + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KDAV_DAVMANAGER_P_H +#define KDAV_DAVMANAGER_P_H + +#include "enums.h" + +#include + +#include + +namespace KIO +{ +class DavJob; +} + +class QUrl; + +/** CalDav/CardDav protocol implementation. */ +namespace KDAV +{ +class DavProtocolBase; + +/** + * @short A factory class for handling DAV jobs. + * + * This class provides factory methods to create preconfigured + * low-level DAV jobs and has access to the global DAV protocol dialect + * objects which abstract the access to the various DAV protocol dialects. + */ +class DavManager +{ +public: + /** + * Destroys the DAV manager. + */ + ~DavManager(); + + /** + * Returns the global instance of the DAV manager. + */ + static DavManager *self(); + + /** + * Returns a preconfigured DAV PROPFIND job. + * + * @param url The target URL of the job. + * @param document The query XML document. + * @param depth The Depth: value to send in the HTTP request + */ + KIO::DavJob *createPropFindJob(const QUrl &url, const QString &document, const QString &depth = QStringLiteral("1")) const; + + /** + * Returns a preconfigured DAV REPORT job. + * + * @param url The target URL of the job. + * @param document The query XML document. + * @param depth The Depth: value to send in the HTTP request + */ + KIO::DavJob *createReportJob(const QUrl &url, const QString &document, const QString &depth = QStringLiteral("1")) const; + + /** + * Returns a preconfigured DAV PROPPATCH job. + * + * @param url The target URL of the job. + * @param document The query XML document. + */ + KIO::DavJob *createPropPatchJob(const QUrl &url, const QString &document) const; + + /** + * Returns the DAV protocol dialect object for the given DAV @p protocol. + */ + static const DavProtocolBase *davProtocol(Protocol protocol); + +private: + /** + * Creates a new DAV manager. + */ + DavManager(); + + std::unique_ptr mProtocols[3]; +}; +} + +#endif diff --git a/src/common/davmultigetprotocol.cpp b/src/common/davmultigetprotocol.cpp new file mode 100644 index 0000000..3323a37 --- /dev/null +++ b/src/common/davmultigetprotocol.cpp @@ -0,0 +1,13 @@ +/* + SPDX-FileCopyrightText: 2010 Grégory Oestreicher + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "davmultigetprotocol_p.h" + +using namespace KDAV; + +DavMultigetProtocol::~DavMultigetProtocol() +{ +} diff --git a/src/common/davmultigetprotocol_p.h b/src/common/davmultigetprotocol_p.h new file mode 100644 index 0000000..78d9113 --- /dev/null +++ b/src/common/davmultigetprotocol_p.h @@ -0,0 +1,45 @@ +/* + SPDX-FileCopyrightText: 2010 Grégory Oestreicher + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KDAV_DAVMULTIGETPROTOCOL_H +#define KDAV_DAVMULTIGETPROTOCOL_H + +#include "kdav_export.h" + +#include "davprotocolbase_p.h" + +namespace KDAV +{ +/** + * @short Base class for protocols that implement MULTIGET capabilities + */ +class DavMultigetProtocol : public DavProtocolBase +{ +public: + /** + * Destroys the DAV protocol + */ + ~DavMultigetProtocol() override; + + /** + * Returns the XML document that represents a MULTIGET DAV query to + * list all DAV resources with the given @p urls. + */ + virtual XMLQueryBuilder::Ptr itemsReportQuery(const QStringList &urls) const = 0; + + /** + * Returns the namespace used by protocol-specific elements found in responses. + */ + virtual QString responseNamespace() const = 0; + + /** + * Returns the tag name of data elements found in responses. + */ + virtual QString dataTagName() const = 0; +}; +} + +#endif diff --git a/src/common/davprincipalhomesetsfetchjob.cpp b/src/common/davprincipalhomesetsfetchjob.cpp new file mode 100644 index 0000000..3530a3b --- /dev/null +++ b/src/common/davprincipalhomesetsfetchjob.cpp @@ -0,0 +1,247 @@ +/* + SPDX-FileCopyrightText: 2010 Grégory Oestreicher + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "davprincipalhomesetsfetchjob.h" +#include "davjobbase_p.h" + +#include "daverror.h" +#include "davmanager_p.h" +#include "davprotocolbase_p.h" +#include "protocolinfo.h" +#include "utils_p.h" + +#include +#include + +using namespace KDAV; + +namespace KDAV +{ +class DavPrincipalHomeSetsFetchJobPrivate : public DavJobBasePrivate +{ +public: + void davJobFinished(KJob *job); + /** + * Start the fetch process. + * + * There may be two rounds necessary if the first request + * does not returns the home sets, but only the current-user-principal + * or the principal-URL. The bool flag is here to prevent requesting + * those last two on each request, as they are only fetched in + * the first round. + * + * @param fetchHomeSetsOnly If set to true the request will not include + * the current-user-principal and principal-URL props. + */ + void fetchHomeSets(bool fetchHomeSetsOnly); + + DavUrl mUrl; + QStringList mHomeSets; +}; +} + +DavPrincipalHomeSetsFetchJob::DavPrincipalHomeSetsFetchJob(const DavUrl &url, QObject *parent) + : DavJobBase(new DavPrincipalHomeSetsFetchJobPrivate, parent) +{ + Q_D(DavPrincipalHomeSetsFetchJob); + d->mUrl = url; +} + +void DavPrincipalHomeSetsFetchJob::start() +{ + Q_D(DavPrincipalHomeSetsFetchJob); + d->fetchHomeSets(false); +} + +void DavPrincipalHomeSetsFetchJobPrivate::fetchHomeSets(bool homeSetsOnly) +{ + QDomDocument document; + + QDomElement propfindElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("propfind")); + document.appendChild(propfindElement); + + QDomElement propElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop")); + propfindElement.appendChild(propElement); + + const QString homeSet = ProtocolInfo::principalHomeSet(mUrl.protocol()); + const QString homeSetNS = ProtocolInfo::principalHomeSetNS(mUrl.protocol()); + propElement.appendChild(document.createElementNS(homeSetNS, homeSet)); + + if (!homeSetsOnly) { + propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("current-user-principal"))); + propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("principal-URL"))); + } + + KIO::DavJob *job = DavManager::self()->createPropFindJob(mUrl.url(), document.toString(), QStringLiteral("0")); + job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true")); + QObject::connect(job, &KIO::DavJob::result, q_ptr, [this](KJob *job) { + davJobFinished(job); + }); +} + +QStringList DavPrincipalHomeSetsFetchJob::homeSets() const +{ + Q_D(const DavPrincipalHomeSetsFetchJob); + return d->mHomeSets; +} + +void DavPrincipalHomeSetsFetchJobPrivate::davJobFinished(KJob *job) +{ + KIO::DavJob *davJob = qobject_cast(job); + const QString responseCodeStr = davJob->queryMetaData(QStringLiteral("responsecode")); + const int responseCode = responseCodeStr.isEmpty() ? 0 : responseCodeStr.toInt(); + + // KIO::DavJob does not set error() even if the HTTP status code is a 4xx or a 5xx + if (davJob->error() || (responseCode >= 400 && responseCode < 600)) { + QString err; + if (davJob->error() && davJob->error() != KIO::ERR_WORKER_DEFINED) { + err = KIO::buildErrorString(davJob->error(), davJob->errorText()); + } else { + err = davJob->errorText(); + } + + setLatestResponseCode(responseCode); + setError(ERR_PROBLEM_WITH_REQUEST); + setJobErrorText(davJob->errorText()); + setJobError(davJob->error()); + setErrorTextFromDavError(); + + emitResult(); + return; + } + + /* + * Extract information from a document like the following (if no homeset is defined) : + * + * + * + * /dav/ + * + * HTTP/1.1 200 OK + * + * + * /principals/users/gdacoin/ + * + * + * + * + * HTTP/1.1 404 Not Found + * + * + * + * + * + * + * + * + * Or like this (if the homeset is defined): + * + * + * + * + * /principals/users/greg%40kamago.net/ + * + * + * + * /greg%40kamago.net/ + * + * + * HTTP/1.1 200 OK + * + * + * + */ + + const QString homeSet = ProtocolInfo::principalHomeSet(mUrl.protocol()); + const QString homeSetNS = ProtocolInfo::principalHomeSetNS(mUrl.protocol()); + QString nextRoundHref; // The content of the href element that will be used if no homeset was found. + // This is either given by current-user-principal or by principal-URL. + + QDomDocument document; + document.setContent(davJob->responseData(), true); + const QDomElement multistatusElement = document.documentElement(); + + QDomElement responseElement = Utils::firstChildElementNS(multistatusElement, QStringLiteral("DAV:"), QStringLiteral("response")); + while (!responseElement.isNull()) { + QDomElement propstatElement; + + // check for the valid propstat, without giving up on first error + { + const QDomNodeList propstats = responseElement.elementsByTagNameNS(QStringLiteral("DAV:"), QStringLiteral("propstat")); + for (int i = 0; i < propstats.length(); ++i) { + const QDomElement propstatCandidate = propstats.item(i).toElement(); + const QDomElement statusElement = Utils::firstChildElementNS(propstatCandidate, QStringLiteral("DAV:"), QStringLiteral("status")); + if (statusElement.text().contains(QLatin1String("200"))) { + propstatElement = propstatCandidate; + } + } + } + + if (propstatElement.isNull()) { + responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); + continue; + } + + // extract home sets + const QDomElement propElement = Utils::firstChildElementNS(propstatElement, QStringLiteral("DAV:"), QStringLiteral("prop")); + const QDomElement homeSetElement = Utils::firstChildElementNS(propElement, homeSetNS, homeSet); + + if (!homeSetElement.isNull()) { + QDomElement hrefElement = Utils::firstChildElementNS(homeSetElement, QStringLiteral("DAV:"), QStringLiteral("href")); + + while (!hrefElement.isNull()) { + const QString href = hrefElement.text(); + if (!mHomeSets.contains(href)) { + mHomeSets << href; + } + + hrefElement = Utils::nextSiblingElementNS(hrefElement, QStringLiteral("DAV:"), QStringLiteral("href")); + } + } else { + // Trying to get the principal url, given either by current-user-principal or principal-URL + QDomElement urlHolder = Utils::firstChildElementNS(propElement, QStringLiteral("DAV:"), QStringLiteral("current-user-principal")); + if (urlHolder.isNull()) { + urlHolder = Utils::firstChildElementNS(propElement, QStringLiteral("DAV:"), QStringLiteral("principal-URL")); + } + + if (!urlHolder.isNull()) { + // Getting the href that will be used for the next round + QDomElement hrefElement = Utils::firstChildElementNS(urlHolder, QStringLiteral("DAV:"), QStringLiteral("href")); + if (!hrefElement.isNull()) { + nextRoundHref = hrefElement.text(); + } + } + } + + responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); + } + + /* + * Now either we got one or more homesets, or we got an href for the next round + * or nothing can be found by this job. + * If we have homesets, we're done here and can notify the caller. + * Else we must ensure that we have an href for the next round. + */ + if (!mHomeSets.isEmpty() || nextRoundHref.isEmpty()) { + emitResult(); + } else { + QUrl nextRoundUrl(mUrl.url()); + + if (nextRoundHref.startsWith(QLatin1Char('/'))) { + // nextRoundHref is only a path, use request url to complete + nextRoundUrl.setPath(nextRoundHref, QUrl::TolerantMode); + } else { + // href is a complete url + nextRoundUrl = QUrl::fromUserInput(nextRoundHref); + nextRoundUrl.setUserName(mUrl.url().userName()); + nextRoundUrl.setPassword(mUrl.url().password()); + } + + mUrl.setUrl(nextRoundUrl); + // And one more round, fetching only homesets + fetchHomeSets(true); + } +} diff --git a/src/common/davprincipalhomesetsfetchjob.h b/src/common/davprincipalhomesetsfetchjob.h new file mode 100644 index 0000000..46de971 --- /dev/null +++ b/src/common/davprincipalhomesetsfetchjob.h @@ -0,0 +1,54 @@ +/* + SPDX-FileCopyrightText: 2010 Grégory Oestreicher + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KDAV_DAVPRINCIPALHOMESETSFETCHJOB_H +#define KDAV_DAVPRINCIPALHOMESETSFETCHJOB_H + +#include "kdav_export.h" + +#include "davjobbase.h" +#include "davurl.h" + +#include + +namespace KDAV +{ +class DavPrincipalHomeSetsFetchJobPrivate; + +/** + * @class DavPrincipalHomeSetsFetchJob davprincipalhomesetsfetchjob.h + * + * @short A job that fetches home sets for a principal. + */ +class KDAV_EXPORT DavPrincipalHomeSetsFetchJob : public DavJobBase +{ + Q_OBJECT + +public: + /** + * Creates a new DAV principals home sets fetch job. + * + * @param url The DAV URL of the DAV principal. + * @param parent The parent object. + */ + explicit DavPrincipalHomeSetsFetchJob(const DavUrl &url, QObject *parent = nullptr); + + /** + * Starts the job. + */ + void start() override; + + /** + * Returns the found home sets. + */ + Q_REQUIRED_RESULT QStringList homeSets() const; + +private: + Q_DECLARE_PRIVATE(DavPrincipalHomeSetsFetchJob) +}; +} + +#endif diff --git a/src/common/davprincipalsearchjob.cpp b/src/common/davprincipalsearchjob.cpp new file mode 100644 index 0000000..45708bd --- /dev/null +++ b/src/common/davprincipalsearchjob.cpp @@ -0,0 +1,386 @@ +/* + SPDX-FileCopyrightText: 2011 Grégory Oestreicher + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "davprincipalsearchjob.h" +#include "davjobbase_p.h" + +#include "daverror.h" +#include "davmanager_p.h" +#include "utils_p.h" + +#include +#include + +#include + +using namespace KDAV; + +namespace KDAV +{ +class DavPrincipalSearchJobPrivate : public DavJobBasePrivate +{ +public: + void buildReportQuery(QDomDocument &query) const; + void principalCollectionSetSearchFinished(KJob *job); + void principalPropertySearchFinished(KJob *job); + + DavUrl mUrl; + DavPrincipalSearchJob::FilterType mType; + QString mFilter; + int mPrincipalPropertySearchSubJobCount = 0; + bool mPrincipalPropertySearchSubJobSuccessful = false; + struct PropertyInfo { + QString propNS; + QString propName; + }; + std::vector mFetchProperties; + QVector mResults; +}; +} + +DavPrincipalSearchJob::DavPrincipalSearchJob(const DavUrl &url, DavPrincipalSearchJob::FilterType type, const QString &filter, QObject *parent) + : DavJobBase(new DavPrincipalSearchJobPrivate, parent) +{ + Q_D(DavPrincipalSearchJob); + d->mUrl = url; + d->mType = type; + d->mFilter = filter; +} + +void DavPrincipalSearchJob::fetchProperty(const QString &name, const QString &ns) +{ + Q_D(DavPrincipalSearchJob); + d->mFetchProperties.push_back({!ns.isEmpty() ? ns : QStringLiteral("DAV:"), name}); +} + +DavUrl DavPrincipalSearchJob::davUrl() const +{ + Q_D(const DavPrincipalSearchJob); + return d->mUrl; +} + +void DavPrincipalSearchJob::start() +{ + Q_D(DavPrincipalSearchJob); + /* + * The first step is to try to locate the URL that contains the principals. + * This is done with a PROPFIND request and a XML like this: + * + * + * + * + * + * + */ + QDomDocument query; + + QDomElement propfind = query.createElementNS(QStringLiteral("DAV:"), QStringLiteral("propfind")); + query.appendChild(propfind); + + QDomElement prop = query.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop")); + propfind.appendChild(prop); + + QDomElement principalCollectionSet = query.createElementNS(QStringLiteral("DAV:"), QStringLiteral("principal-collection-set")); + prop.appendChild(principalCollectionSet); + + KIO::DavJob *job = DavManager::self()->createPropFindJob(d->mUrl.url(), query.toString()); + job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true")); + connect(job, &KIO::DavJob::result, this, [d](KJob *job) { + d->principalCollectionSetSearchFinished(job); + }); + job->start(); +} + +void DavPrincipalSearchJobPrivate::principalCollectionSetSearchFinished(KJob *job) +{ + KIO::DavJob *davJob = qobject_cast(job); + const QString responseCodeStr = davJob->queryMetaData(QStringLiteral("responsecode")); + const int responseCode = responseCodeStr.isEmpty() ? 0 : responseCodeStr.toInt(); + // KIO::DavJob does not set error() even if the HTTP status code is a 4xx or a 5xx + if (davJob->error() || (responseCode >= 400 && responseCode < 600)) { + setLatestResponseCode(responseCode); + setError(ERR_PROBLEM_WITH_REQUEST); + setJobErrorText(davJob->errorText()); + setJobError(davJob->error()); + setErrorTextFromDavError(); + + emitResult(); + return; + } + + if (job->error()) { + setError(job->error()); + setErrorText(job->errorText()); + emitResult(); + return; + } + + /* + * Extract information from a document like the following: + * + * + * + * + * http://www.example.com/papers/ + * + * + * + * http://www.example.com/acl/users/ + * http://www.example.com/acl/groups/ + * + * + * HTTP/1.1 200 OK + * + * + * + */ + + QDomDocument document; + document.setContent(davJob->responseData(), true); + QDomElement documentElement = document.documentElement(); + + QDomElement responseElement = Utils::firstChildElementNS(documentElement, QStringLiteral("DAV:"), QStringLiteral("response")); + if (responseElement.isNull()) { + emitResult(); + return; + } + + // check for the valid propstat, without giving up on first error + QDomElement propstatElement; + { + const QDomNodeList propstats = responseElement.elementsByTagNameNS(QStringLiteral("DAV:"), QStringLiteral("propstat")); + for (int i = 0; i < propstats.length(); ++i) { + const QDomElement propstatCandidate = propstats.item(i).toElement(); + const QDomElement statusElement = Utils::firstChildElementNS(propstatCandidate, QStringLiteral("DAV:"), QStringLiteral("status")); + if (statusElement.text().contains(QLatin1String("200"))) { + propstatElement = propstatCandidate; + } + } + } + + if (propstatElement.isNull()) { + emitResult(); + return; + } + + QDomElement propElement = Utils::firstChildElementNS(propstatElement, QStringLiteral("DAV:"), QStringLiteral("prop")); + if (propElement.isNull()) { + emitResult(); + return; + } + + QDomElement principalCollectionSetElement = Utils::firstChildElementNS(propElement, QStringLiteral("DAV:"), QStringLiteral("principal-collection-set")); + if (principalCollectionSetElement.isNull()) { + emitResult(); + return; + } + + QDomNodeList hrefNodes = principalCollectionSetElement.elementsByTagNameNS(QStringLiteral("DAV:"), QStringLiteral("href")); + for (int i = 0; i < hrefNodes.size(); ++i) { + QDomElement hrefElement = hrefNodes.at(i).toElement(); + QString href = hrefElement.text(); + + QUrl url = mUrl.url(); + if (href.startsWith(QLatin1Char('/'))) { + // href is only a path, use request url to complete + url.setPath(href, QUrl::TolerantMode); + } else { + // href is a complete url + QUrl tmpUrl(href); + tmpUrl.setUserName(url.userName()); + tmpUrl.setPassword(url.password()); + url = tmpUrl; + } + + QDomDocument principalPropertySearchQuery; + buildReportQuery(principalPropertySearchQuery); + KIO::DavJob *reportJob = DavManager::self()->createReportJob(url, principalPropertySearchQuery.toString()); + reportJob->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true")); + QObject::connect(reportJob, &KIO::DavJob::result, q_ptr, [this](KJob *job) { + principalPropertySearchFinished(job); + }); + ++mPrincipalPropertySearchSubJobCount; + reportJob->start(); + } +} + +void DavPrincipalSearchJobPrivate::principalPropertySearchFinished(KJob *job) +{ + --mPrincipalPropertySearchSubJobCount; + + if (job->error() && !mPrincipalPropertySearchSubJobSuccessful) { + setError(job->error()); + setErrorText(job->errorText()); + if (mPrincipalPropertySearchSubJobCount == 0) { + emitResult(); + } + return; + } + + KIO::DavJob *davJob = qobject_cast(job); + + const int responseCode = davJob->queryMetaData(QStringLiteral("responsecode")).toInt(); + + if (responseCode > 499 && responseCode < 600 && !mPrincipalPropertySearchSubJobSuccessful) { + // Server-side error, unrecoverable + setLatestResponseCode(responseCode); + setError(ERR_SERVER_UNRECOVERABLE); + setJobErrorText(davJob->errorText()); + setJobError(davJob->error()); + setErrorTextFromDavError(); + if (mPrincipalPropertySearchSubJobCount == 0) { + emitResult(); + } + return; + } else if (responseCode > 399 && responseCode < 500 && !mPrincipalPropertySearchSubJobSuccessful) { + setLatestResponseCode(responseCode); + setError(ERR_PROBLEM_WITH_REQUEST); + setJobErrorText(davJob->errorText()); + setJobError(davJob->error()); + setErrorTextFromDavError(); + + if (mPrincipalPropertySearchSubJobCount == 0) { + emitResult(); + } + return; + } + + if (!mPrincipalPropertySearchSubJobSuccessful) { + setError(0); // nope, everything went fine + mPrincipalPropertySearchSubJobSuccessful = true; + } + + /* + * Extract infos from a document like the following: + * + * + * + * http://www.example.com/users/jdoe + * + * + * John Doe + * + * HTTP/1.1 200 OK + * + * + */ + + QDomDocument document; + document.setContent(davJob->responseData(), true); + const QDomElement documentElement = document.documentElement(); + + QDomElement responseElement = Utils::firstChildElementNS(documentElement, QStringLiteral("DAV:"), QStringLiteral("response")); + if (responseElement.isNull()) { + if (mPrincipalPropertySearchSubJobCount == 0) { + emitResult(); + } + return; + } + + // check for the valid propstat, without giving up on first error + QDomElement propstatElement; + { + const QDomNodeList propstats = responseElement.elementsByTagNameNS(QStringLiteral("DAV:"), QStringLiteral("propstat")); + const int propStatsEnd(propstats.length()); + for (int i = 0; i < propStatsEnd; ++i) { + const QDomElement propstatCandidate = propstats.item(i).toElement(); + const QDomElement statusElement = Utils::firstChildElementNS(propstatCandidate, QStringLiteral("DAV:"), QStringLiteral("status")); + if (statusElement.text().contains(QLatin1String("200"))) { + propstatElement = propstatCandidate; + } + } + } + + if (propstatElement.isNull()) { + if (mPrincipalPropertySearchSubJobCount == 0) { + emitResult(); + } + return; + } + + QDomElement propElement = Utils::firstChildElementNS(propstatElement, QStringLiteral("DAV:"), QStringLiteral("prop")); + if (propElement.isNull()) { + if (mPrincipalPropertySearchSubJobCount == 0) { + emitResult(); + } + return; + } + + // All requested properties are now under propElement, so let's find them + for (const auto &[propNS, propName] : mFetchProperties) { + const QDomNodeList fetchNodes = propElement.elementsByTagNameNS(propNS, propName); + mResults.reserve(mResults.size() + fetchNodes.size()); + for (int i = 0; i < fetchNodes.size(); ++i) { + const QDomElement fetchElement = fetchNodes.at(i).toElement(); + mResults.push_back({propNS, propName, fetchElement.text()}); + } + } + + if (mPrincipalPropertySearchSubJobCount == 0) { + emitResult(); + } +} + +QVector DavPrincipalSearchJob::results() const +{ + Q_D(const DavPrincipalSearchJob); + return d->mResults; +} + +void DavPrincipalSearchJobPrivate::buildReportQuery(QDomDocument &query) const +{ + /* + * Build a document like the following, where XXX will + * be replaced by the properties the user want to fetch: + * + * + * + * + * + * + * + * FILTER + * + * + * XXX + * + * + */ + + QDomElement principalPropertySearch = query.createElementNS(QStringLiteral("DAV:"), QStringLiteral("principal-property-search")); + query.appendChild(principalPropertySearch); + + QDomElement propertySearch = query.createElementNS(QStringLiteral("DAV:"), QStringLiteral("property-search")); + principalPropertySearch.appendChild(propertySearch); + + QDomElement prop = query.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop")); + propertySearch.appendChild(prop); + + if (mType == DavPrincipalSearchJob::DisplayName) { + QDomElement displayName = query.createElementNS(QStringLiteral("DAV:"), QStringLiteral("displayname")); + prop.appendChild(displayName); + } else if (mType == DavPrincipalSearchJob::EmailAddress) { + QDomElement calendarUserAddressSet = + query.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("calendar-user-address-set")); + prop.appendChild(calendarUserAddressSet); + // QDomElement hrefElement = query.createElementNS( "DAV:", "href" ); + // prop.appendChild( hrefElement ); + } + + QDomElement match = query.createElementNS(QStringLiteral("DAV:"), QStringLiteral("match")); + propertySearch.appendChild(match); + + QDomText propFilter = query.createTextNode(mFilter); + match.appendChild(propFilter); + + prop = query.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop")); + principalPropertySearch.appendChild(prop); + + for (const auto &[propNS, propName] : mFetchProperties) { + QDomElement elem = query.createElementNS(propNS, propName); + prop.appendChild(elem); + } +} diff --git a/src/common/davprincipalsearchjob.h b/src/common/davprincipalsearchjob.h new file mode 100644 index 0000000..59e20a1 --- /dev/null +++ b/src/common/davprincipalsearchjob.h @@ -0,0 +1,94 @@ +/* + SPDX-FileCopyrightText: 2011 Grégory Oestreicher + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KDAV_DAVPRINCIPALSEARCHJOB_H +#define KDAV_DAVPRINCIPALSEARCHJOB_H + +#include "kdav_export.h" + +#include "davjobbase.h" +#include "davurl.h" + +#include + +namespace KDAV +{ +class DavPrincipalSearchJobPrivate; + +/** + * @class DavPrincipalSearchJob davprincipalsearchjob.h + * + * @short A job that search a DAV principal on a server + * + * This job is used to search a principal on a server + * that implement the dav-property-search REPORT (RFC3744). + * + * The properties to fetch are set with @ref fetchProperty(). + */ +class KDAV_EXPORT DavPrincipalSearchJob : public DavJobBase +{ + Q_OBJECT + +public: + /** + * Types of search that are supported by this job. + * DisplayName will match on the DAV displayname property. + * EmailAddress will match on the CalDav calendar-user-address-set property. + */ + enum FilterType { + DisplayName, + EmailAddress, + }; + + /** + * Simple struct to hold the search job results + */ + struct Result { + QString propertyNamespace; + QString property; + QString value; + }; + + /** + * Creates a new DAV principal search job + * + * @param url The URL to use in the REPORT query. + * @param type The type that the filter will match. + * @param filter The filter that will be used to match the displayname attribute. + * @param parent The parent object. + */ + explicit DavPrincipalSearchJob(const DavUrl &url, FilterType type, const QString &filter, QObject *parent = nullptr); + + /** + * Add a new property to fetch from the server. + * + * @param name The name of the property. + * @param ns The namespace of this property, defaults to 'DAV:'. + */ + void fetchProperty(const QString &name, const QString &ns = QString()); + + /** + * Starts the job + */ + void start() override; + + /** + * Return the DavUrl used by this job + */ + Q_REQUIRED_RESULT DavUrl davUrl() const; + + /** + * Get the job results. + */ + Q_REQUIRED_RESULT QVector results() const; + +private: + Q_DECLARE_PRIVATE(DavPrincipalSearchJob) +}; +} + +Q_DECLARE_TYPEINFO(KDAV::DavPrincipalSearchJob::Result, Q_MOVABLE_TYPE); +#endif diff --git a/src/common/davprotocolbase.cpp b/src/common/davprotocolbase.cpp new file mode 100644 index 0000000..d2e868f --- /dev/null +++ b/src/common/davprotocolbase.cpp @@ -0,0 +1,43 @@ +/* + SPDX-FileCopyrightText: 2009 Grégory Oestreicher + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "davprotocolbase_p.h" + +#include + +using namespace KDAV; + +XMLQueryBuilder::~XMLQueryBuilder() +{ +} + +void XMLQueryBuilder::setParameter(const QString &key, const QVariant &value) +{ + mParameters[key] = value; +} + +QVariant XMLQueryBuilder::parameter(const QString &key) const +{ + QVariant ret; + if (mParameters.contains(key)) { + ret = mParameters.value(key); + } + return ret; +} + +DavProtocolBase::~DavProtocolBase() +{ +} + +QString DavProtocolBase::principalHomeSet() const +{ + return QString(); +} + +QString DavProtocolBase::principalHomeSetNS() const +{ + return QString(); +} diff --git a/src/common/davprotocolbase_p.h b/src/common/davprotocolbase_p.h new file mode 100644 index 0000000..a0ebb0d --- /dev/null +++ b/src/common/davprotocolbase_p.h @@ -0,0 +1,124 @@ +/* + SPDX-FileCopyrightText: 2009 Grégory Oestreicher + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KDAV_DAVPROTOCOLBASE_H +#define KDAV_DAVPROTOCOLBASE_H + +#include "kdav_export.h" + +#include "davcollection.h" + +#include +#include +#include +#include + +namespace KDAV +{ +/** + * @short Base class for XML query builders + */ +class XMLQueryBuilder +{ +public: + typedef std::shared_ptr Ptr; + + virtual ~XMLQueryBuilder(); + + virtual QDomDocument buildQuery() const = 0; + virtual QString mimeType() const = 0; + + void setParameter(const QString &key, const QVariant &value); + QVariant parameter(const QString &key) const; + +private: + QMap mParameters; +}; + +/** + * @short Base class for various DAV groupware dialects. + * + * This class provides an interface to query the DAV dialect + * specific features and abstract them. + * + * The functionality is implemented in: + * @li CaldavProtocol + * @li CarddavProtocol + * @li GroupdavProtocol + */ +class DavProtocolBase +{ +public: + /** + * Destroys the DAV protocol base. + */ + virtual ~DavProtocolBase(); + + /** + * Returns whether the DAV protocol dialect supports principal + * queries. If true, it must return the home set it provides + * access to with principalHomeSet() and the home set namespace + * with principalHomeSetNS(); + */ + virtual bool supportsPrincipals() const = 0; + + /** + * Returns whether the DAV protocol dialect supports the REPORT + * command to query all resources of a collection. + * If not, PROPFIND command will be used instead. + */ + virtual bool useReport() const = 0; + + /** + * Returns whether the DAV protocol dialect supports the MULTIGET command. + * + * If MULTIGET is supported, the content of all DAV resources + * can be fetched in Akonadi::ResourceBase::retrieveItems() already and + * there is no need to call Akonadi::ResourceBase::retrieveItem() for every single + * DAV resource. + * + * Protocols that have MULTIGET capabilities must inherit from + * DavMultigetProtocol instead of this class. + */ + virtual bool useMultiget() const = 0; + + /** + * Returns the home set that this protocol supports. + */ + virtual QString principalHomeSet() const; + + /** + * Returns the namespace of the home set. + */ + virtual QString principalHomeSetNS() const; + + /** + * Returns the XML document that represents the DAV query to + * list all available DAV collections. + */ + virtual XMLQueryBuilder::Ptr collectionsQuery() const = 0; + + /** + * Returns @c true if the given element of a multistatus response contains a + * valid collection for this protocol. + */ + virtual bool containsCollection(const QDomElement &propElem) const = 0; + + /** + * Returns a list of XML documents that represent DAV queries to + * list all available DAV resources inside a specific DAV collection. + */ + virtual QVector itemsQueries() const = 0; + + /** + * Returns the possible content types for the collection that + * is described by the passed @p propstat element of a PROPFIND result. + */ + virtual DavCollection::ContentTypes collectionContentTypes(const QDomElement &propstat) const = 0; +}; +} + +#endif diff --git a/src/common/davurl.cpp b/src/common/davurl.cpp new file mode 100644 index 0000000..1a76699 --- /dev/null +++ b/src/common/davurl.cpp @@ -0,0 +1,86 @@ +/* + SPDX-FileCopyrightText: 2010 Tobias Koenig + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "davurl.h" + + +using namespace KDAV; + +namespace KDAV +{ +class DavUrlPrivate : public QSharedData +{ +public: + Protocol mProtocol = KDAV::CalDav; + QUrl mUrl; +}; +} + +DavUrl::DavUrl() + : d(new DavUrlPrivate) +{ +} + +DavUrl::DavUrl(const QUrl &url, Protocol protocol) + : d(new DavUrlPrivate) +{ + d->mUrl = url; + d->mProtocol = protocol; +} + +DavUrl::DavUrl(const DavUrl &) = default; +DavUrl::DavUrl(DavUrl &&) = default; +DavUrl::~DavUrl() = default; +DavUrl &DavUrl::operator=(const DavUrl &) = default; +DavUrl &DavUrl::operator=(DavUrl &&) = default; + +void DavUrl::setUrl(const QUrl &url) +{ + d->mUrl = url; +} + +QUrl DavUrl::url() const +{ + return d->mUrl; +} + +void DavUrl::setProtocol(Protocol protocol) +{ + d->mProtocol = protocol; +} + +Protocol DavUrl::protocol() const +{ + return d->mProtocol; +} + +QString DavUrl::toDisplayString() const +{ + auto url = d->mUrl; + url.setUserInfo(QString()); + return url.toDisplayString(); +} + +QDataStream &KDAV::operator<<(QDataStream &stream, const DavUrl &url) +{ + stream << QString::number(url.protocol()); + stream << url.url(); + + return stream; +} + +QDataStream &KDAV::operator>>(QDataStream &stream, DavUrl &davUrl) +{ + QUrl url; + QString p; + + stream >> p; + stream >> url; + + davUrl = DavUrl(url, static_cast(p.toInt())); + + return stream; +} diff --git a/src/common/davurl.h b/src/common/davurl.h new file mode 100644 index 0000000..1221397 --- /dev/null +++ b/src/common/davurl.h @@ -0,0 +1,87 @@ +/* + SPDX-FileCopyrightText: 2010 Tobias Koenig + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KDAV_DAVURL_H +#define KDAV_DAVURL_H + +#include "kdav_export.h" + +#include "enums.h" + +#include +#include +#include + +namespace KDAV +{ +class DavUrlPrivate; +/** + * @class DavUrl davurl.h + * + * @short A helper class to combine URL and protocol of a DAV URL. + */ +class KDAV_EXPORT DavUrl +{ +public: + /** + * Defines a list of DAV URL objects. + */ + typedef QVector List; + + /** + * Creates an empty DAV URL. + */ + DavUrl(); + DavUrl(const DavUrl &); + DavUrl(DavUrl &&); + ~DavUrl(); + DavUrl &operator=(const DavUrl &); + DavUrl &operator=(DavUrl &&); + + /** + * Creates a new DAV URL. + * + * @param url The URL that identifies the DAV object. + * @param protocol The DAV protocol dialect that is used to retrieve the DAV object. + */ + DavUrl(const QUrl &url, Protocol protocol); + + /** + * Sets the @p url that identifies the DAV object. + */ + void setUrl(const QUrl &url); + + /** + * Returns the URL that identifies the DAV object. + */ + Q_REQUIRED_RESULT QUrl url() const; + + /** + * Returns the URL in a user-friendly way without login information. + */ + Q_REQUIRED_RESULT QString toDisplayString() const; + + /** + * Sets the DAV @p protocol dialect that is used to retrieve the DAV object. + */ + void setProtocol(Protocol protocol); + + /** + * Returns the DAV protocol dialect that is used to retrieve the DAV object. + */ + Q_REQUIRED_RESULT Protocol protocol() const; + +private: + QSharedDataPointer d; +}; + +KDAV_EXPORT QDataStream &operator<<(QDataStream &out, const DavUrl &url); +KDAV_EXPORT QDataStream &operator>>(QDataStream &in, DavUrl &url); +} + +Q_DECLARE_TYPEINFO(KDAV::DavUrl, Q_MOVABLE_TYPE); + +#endif diff --git a/src/common/enums.h b/src/common/enums.h new file mode 100644 index 0000000..ea16c7e --- /dev/null +++ b/src/common/enums.h @@ -0,0 +1,47 @@ +/* + SPDX-FileCopyrightText: 2010 Tobias Koenig + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KDAV_ENUMS_H +#define KDAV_ENUMS_H + +#include + +/** + * The KDAV namespace. + */ +namespace KDAV +{ +/** + * Describes the DAV protocol dialect. + */ +enum Protocol { + CalDav = 0, ///< The CalDav protocol as defined in https://devguide.calconnect.org/CalDAV + CardDav, ///< The CardDav protocol as defined in https://devguide.calconnect.org/CardDAV + GroupDav, ///< The GroupDav protocol as defined in http://www.groupdav.org +}; + +/** + * Describes the DAV privileges on a resource (see RFC3744) + */ +enum Privilege { + None = 0x0, + Read = 0x1, + Write = 0x2, + WriteProperties = 0x4, + WriteContent = 0x8, + Unlock = 0x10, + ReadAcl = 0x20, + ReadCurrentUserPrivilegeSet = 0x40, + WriteAcl = 0x80, + Bind = 0x100, + Unbind = 0x200, + All = 0x400, +}; +Q_DECLARE_FLAGS(Privileges, Privilege) +Q_DECLARE_OPERATORS_FOR_FLAGS(Privileges) +} + +#endif diff --git a/src/common/etagcache.cpp b/src/common/etagcache.cpp new file mode 100644 index 0000000..10d2784 --- /dev/null +++ b/src/common/etagcache.cpp @@ -0,0 +1,86 @@ +/* + SPDX-FileCopyrightText: 2010 Grégory Oestreicher + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "etagcache.h" + +#include +#include + +using namespace KDAV; + +namespace KDAV +{ +class EtagCachePrivate +{ +public: + QMap mCache; + QSet mChangedRemoteIds; +}; +} + +EtagCache::EtagCache(QObject *parent) + : QObject(parent) + , d(new EtagCachePrivate) +{ +} + +EtagCache::~EtagCache() = default; + +void EtagCache::setEtag(const QString &remoteId, const QString &etag) +{ + setEtagInternal(remoteId, etag); + + d->mChangedRemoteIds.remove(remoteId); +} + +void EtagCache::setEtagInternal(const QString &remoteId, const QString &etag) +{ + d->mCache[remoteId] = etag; +} + +bool EtagCache::contains(const QString &remoteId) const +{ + return d->mCache.contains(remoteId); +} + +bool EtagCache::etagChanged(const QString &remoteId, const QString &refEtag) const +{ + if (!contains(remoteId)) { + return true; + } + return d->mCache.value(remoteId) != refEtag; +} + +void EtagCache::markAsChanged(const QString &remoteId) +{ + d->mChangedRemoteIds.insert(remoteId); +} + +bool EtagCache::isOutOfDate(const QString &remoteId) const +{ + return d->mChangedRemoteIds.contains(remoteId); +} + +void EtagCache::removeEtag(const QString &remoteId) +{ + d->mChangedRemoteIds.remove(remoteId); + d->mCache.remove(remoteId); +} + +QMap EtagCache::etagCacheMap() const +{ + return d->mCache; +} + +QStringList EtagCache::urls() const +{ + return d->mCache.keys(); +} + +QStringList EtagCache::changedRemoteIds() const +{ + return d->mChangedRemoteIds.values(); +} diff --git a/src/common/etagcache.h b/src/common/etagcache.h new file mode 100644 index 0000000..8c6fb5a --- /dev/null +++ b/src/common/etagcache.h @@ -0,0 +1,104 @@ +/* + SPDX-FileCopyrightText: 2010 Grégory Oestreicher + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KDAV_ETAGCACHE_H +#define KDAV_ETAGCACHE_H + +#include "kdav_export.h" + +#include +#include + +#include + +namespace KDAV +{ +class EtagCachePrivate; + +/** + * @class EtagCache etagcache.h + * + * @short A helper class to cache ETags. + * + * The EtagCache caches the remote ids and ETags of all items + * in a given collection. This cache is needed to find + * out which items have been changed in the backend and have to + * be refetched on the next call of Akonadi::ResourceBase::retrieveItems() + */ +class KDAV_EXPORT EtagCache : public QObject +{ + Q_OBJECT + +public: + /** + * Creates a new ETag cache and populates it with the ETags + * of items found in @p collection. + */ + explicit EtagCache(QObject *parent = nullptr); + ~EtagCache() override; + + /** + * Sets the ETag for the remote ID. If the remote ID is marked as + * changed (is contained in the return of changedRemoteIds), remove + * it from the changed list. + */ + void setEtag(const QString &remoteId, const QString &etag); + + /** + * Checks if the given item is in the cache + */ + Q_REQUIRED_RESULT bool contains(const QString &remoteId) const; + + /** + * Check if the known ETag for the remote ID is equal to @p refEtag. + */ + Q_REQUIRED_RESULT bool etagChanged(const QString &remoteId, const QString &refEtag) const; + + /** + * Mark an item as changed in the backend. + */ + void markAsChanged(const QString &remoteId); + + /** + * Returns true if the remote ID is marked as changed (is contained in the + * return of changedRemoteIds) + */ + Q_REQUIRED_RESULT bool isOutOfDate(const QString &remoteId) const; + + /** + * Removes the entry for item with remote ID @p remoteId. + */ + void removeEtag(const QString &remoteId); + + /** + * Returns the list of all items URLs. + */ + Q_REQUIRED_RESULT QStringList urls() const; + + /** + * Returns the list of remote ids of items that have been changed + * in the backend. + */ + Q_REQUIRED_RESULT QStringList changedRemoteIds() const; + +protected: + /** + * Sets the ETag for the remote ID. + */ + void setEtagInternal(const QString &remoteId, const QString &etag); + +private: + const std::unique_ptr d; + + friend class DavItemsListJobPrivate; + // @internal + // Returns a map of remote Id and corresponding etag string key/value pairs. + // Only used by DavItemsListJobPrivate + Q_DECL_HIDDEN QMap etagCacheMap() const; +}; +} + +#endif diff --git a/src/common/protocolinfo.cpp b/src/common/protocolinfo.cpp new file mode 100644 index 0000000..c31c686 --- /dev/null +++ b/src/common/protocolinfo.cpp @@ -0,0 +1,70 @@ +/* + SPDX-FileCopyrightText: 2010 Tobias Koenig + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "protocolinfo.h" +#include "davmanager_p.h" +#include "davprotocolbase_p.h" +#include "libkdav_debug.h" + +using namespace KDAV; + +bool ProtocolInfo::useMultiget(KDAV::Protocol protocol) +{ + return DavManager::davProtocol(protocol)->useMultiget(); +} + +QString ProtocolInfo::principalHomeSet(KDAV::Protocol protocol) +{ + return DavManager::davProtocol(protocol)->principalHomeSet(); +} + +QString ProtocolInfo::principalHomeSetNS(KDAV::Protocol protocol) +{ + return DavManager::davProtocol(protocol)->principalHomeSetNS(); +} + +QString ProtocolInfo::protocolName(KDAV::Protocol protocol) +{ + switch (protocol) { + case KDAV::CalDav: + return QStringLiteral("CalDav"); + case KDAV::CardDav: + return QStringLiteral("CardDav"); + case KDAV::GroupDav: + return QStringLiteral("GroupDav"); + } + return {}; +} + +KDAV::Protocol ProtocolInfo::protocolByName(const QString &name) +{ + Protocol protocol = KDAV::CalDav; + + if (name == QLatin1String("CalDav")) { + protocol = KDAV::CalDav; + } else if (name == QLatin1String("CardDav")) { + protocol = KDAV::CardDav; + } else if (name == QLatin1String("GroupDav")) { + protocol = KDAV::GroupDav; + } else { + qCCritical(KDAV_LOG) << "Unexpected protocol name : " << name; + } + + return protocol; +} + +QString ProtocolInfo::contactsMimeType(KDAV::Protocol protocol) +{ + QString ret; + + if (protocol == KDAV::CardDav) { + ret = QStringLiteral("text/vcard"); + } else if (protocol == KDAV::GroupDav) { + ret = QStringLiteral("text/x-vcard"); + } + + return ret; +} diff --git a/src/common/protocolinfo.h b/src/common/protocolinfo.h new file mode 100644 index 0000000..e558af0 --- /dev/null +++ b/src/common/protocolinfo.h @@ -0,0 +1,53 @@ +/* + SPDX-FileCopyrightText: 2019 Volker Krause + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KDAV_PROTOCOLINFO_H +#define KDAV_PROTOCOLINFO_H + +#include "enums.h" +#include "kdav_export.h" + +namespace KDAV +{ +/** Information about a DAV protocol. */ +namespace ProtocolInfo +{ +/** + * Returns whether the @p protocol dialect supports the MULTIGET command. + * + * If MULTIGET is supported, the content of all DAV resources + * can be fetched in Akonadi::ResourceBase::retrieveItems() already and + * there is no need to call Akonadi::ResourceBase::retrieveItem() for every single + * DAV resource. + */ +Q_REQUIRED_RESULT KDAV_EXPORT bool useMultiget(KDAV::Protocol protocol); + +/** Returns the principal home set of @p protocol. */ +Q_REQUIRED_RESULT KDAV_EXPORT QString principalHomeSet(KDAV::Protocol protocol); + +/** Returns the principal home set namespace of @p protocol. */ +Q_REQUIRED_RESULT KDAV_EXPORT QString principalHomeSetNS(KDAV::Protocol protocol); + +/** + * Returns the untranslated name of the given DAV @p protocol dialect. + */ +Q_REQUIRED_RESULT KDAV_EXPORT QString protocolName(KDAV::Protocol protocol); + +/** + * Returns the protocol matching the given name. This is the opposite of + * ProtocolInfo::protocolName(). + */ +Q_REQUIRED_RESULT KDAV_EXPORT KDAV::Protocol protocolByName(const QString &name); + +/** + * Returns the mimetype that shall be used for contact DAV resources using @p protocol. + */ +Q_REQUIRED_RESULT KDAV_EXPORT QString contactsMimeType(KDAV::Protocol protocol); +} + +} + +#endif // KDAV_PROTOCOLINFO_H diff --git a/src/common/utils.cpp b/src/common/utils.cpp new file mode 100644 index 0000000..218b773 --- /dev/null +++ b/src/common/utils.cpp @@ -0,0 +1,110 @@ +/* + SPDX-FileCopyrightText: 2010 Tobias Koenig + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "protocolinfo.h" +#include "utils_p.h" + +#include "enums.h" + +#include "davitem.h" +#include "davmanager_p.h" +#include "davprotocolbase_p.h" + +#include + +#include "libkdav_debug.h" + +using namespace KDAV; + +QDomElement Utils::firstChildElementNS(const QDomElement &parent, const QString &namespaceUri, const QString &tagName) +{ + for (QDomNode child = parent.firstChild(); !child.isNull(); child = child.nextSibling()) { + if (child.isElement()) { + const QDomElement elt = child.toElement(); + if (tagName.isEmpty() || (elt.tagName() == tagName && elt.namespaceURI() == namespaceUri)) { + return elt; + } + } + } + + return QDomElement(); +} + +QDomElement Utils::nextSiblingElementNS(const QDomElement &element, const QString &namespaceUri, const QString &tagName) +{ + for (QDomNode sib = element.nextSibling(); !sib.isNull(); sib = sib.nextSibling()) { + if (sib.isElement()) { + const QDomElement elt = sib.toElement(); + if (tagName.isEmpty() || (elt.tagName() == tagName && elt.namespaceURI() == namespaceUri)) { + return elt; + } + } + } + + return QDomElement(); +} + +Privileges Utils::extractPrivileges(const QDomElement &element) +{ + Privileges final = None; + QDomElement privElement = firstChildElementNS(element, QStringLiteral("DAV:"), QStringLiteral("privilege")); + + while (!privElement.isNull()) { + QDomElement child = privElement.firstChildElement(); + + while (!child.isNull()) { + final |= parsePrivilege(child); + child = child.nextSiblingElement(); + } + + privElement = Utils::nextSiblingElementNS(privElement, QStringLiteral("DAV:"), QStringLiteral("privilege")); + } + + return final; +} + +Privileges Utils::parsePrivilege(const QDomElement &element) +{ + Privileges final = None; + + if (!element.childNodes().isEmpty()) { + // This is an aggregate privilege, parse each of its children + QDomElement child = element.firstChildElement(); + while (!child.isNull()) { + final |= parsePrivilege(child); + child = child.nextSiblingElement(); + } + } else { + // This is a normal privilege + const QString privname = element.localName(); + + if (privname == QLatin1String("read")) { + final |= KDAV::Read; + } else if (privname == QLatin1String("write")) { + final |= KDAV::Write; + } else if (privname == QLatin1String("write-properties")) { + final |= KDAV::WriteProperties; + } else if (privname == QLatin1String("write-content")) { + final |= KDAV::WriteContent; + } else if (privname == QLatin1String("unlock")) { + final |= KDAV::Unlock; + } else if (privname == QLatin1String("read-acl")) { + final |= KDAV::ReadAcl; + } else if (privname == QLatin1String("read-current-user-privilege-set")) { + final |= KDAV::ReadCurrentUserPrivilegeSet; + } else if (privname == QLatin1String("write-acl")) { + final |= KDAV::WriteAcl; + } else if (privname == QLatin1String("bind")) { + final |= KDAV::Bind; + } else if (privname == QLatin1String("unbind")) { + final |= KDAV::Unbind; + } else if (privname == QLatin1String("all")) { + final |= KDAV::All; + } + } + + return final; +} diff --git a/src/common/utils_p.h b/src/common/utils_p.h new file mode 100644 index 0000000..9ec7f9e --- /dev/null +++ b/src/common/utils_p.h @@ -0,0 +1,41 @@ +/* + SPDX-FileCopyrightText: 2010 Tobias Koenig + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KDAV_DAVUTILS_P_H +#define KDAV_DAVUTILS_P_H + +#include "enums.h" + +#include + +namespace KDAV +{ +namespace Utils +{ +/** + * Returns the first child element of @p parent that has the given @p tagName and is part of the @p namespaceUri. + */ +Q_REQUIRED_RESULT QDomElement firstChildElementNS(const QDomElement &parent, const QString &namespaceUri, const QString &tagName); + +/** + * Returns the next sibling element of @p element that has the given @p tagName and is part of the @p namespaceUri. + */ +Q_REQUIRED_RESULT QDomElement nextSiblingElementNS(const QDomElement &element, const QString &namespaceUri, const QString &tagName); + +/** + * Extracts privileges from @p element. The tags are expected to be first level children of @p element. + */ +Q_REQUIRED_RESULT Privileges extractPrivileges(const QDomElement &element); + +/** + * Parses a single tag and returns the final Privileges. + */ +Q_REQUIRED_RESULT Privileges parsePrivilege(const QDomElement &element); + +} +} + +#endif diff --git a/src/protocols/caldavprotocol.cpp b/src/protocols/caldavprotocol.cpp new file mode 100644 index 0000000..d1118ea --- /dev/null +++ b/src/protocols/caldavprotocol.cpp @@ -0,0 +1,408 @@ +/* + SPDX-FileCopyrightText: 2009 Grégory Oestreicher + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "caldavprotocol_p.h" +#include "common/utils_p.h" + +#include +#include +#include + +using namespace KDAV; + +class CaldavCollectionQueryBuilder : public XMLQueryBuilder +{ +public: + QDomDocument buildQuery() const override + { + QDomDocument document; + + QDomElement propfindElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("propfind")); + document.appendChild(propfindElement); + + QDomElement propElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop")); + propfindElement.appendChild(propElement); + + propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("displayname"))); + propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("resourcetype"))); + propElement.appendChild(document.createElementNS(QStringLiteral("http://apple.com/ns/ical/"), QStringLiteral("calendar-color"))); + propElement.appendChild(document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("supported-calendar-component-set"))); + propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("current-user-privilege-set"))); + propElement.appendChild(document.createElementNS(QStringLiteral("http://calendarserver.org/ns/"), QStringLiteral("getctag"))); + + return document; + } + + QString mimeType() const override + { + return QString(); + } +}; + +class CaldavListEventQueryBuilder : public XMLQueryBuilder +{ +public: + QDomDocument buildQuery() const override + { + QString startTime = parameter(QStringLiteral("start")).toString(); + QString endTime = parameter(QStringLiteral("end")).toString(); + QDomDocument document; + + QDomElement queryElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("calendar-query")); + document.appendChild(queryElement); + + QDomElement propElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop")); + queryElement.appendChild(propElement); + + QDomElement getetagElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("getetag")); + propElement.appendChild(getetagElement); + + QDomElement getRTypeElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("resourcetype")); + propElement.appendChild(getRTypeElement); + + QDomElement filterElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("filter")); + queryElement.appendChild(filterElement); + + QDomElement compfilterElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("comp-filter")); + + QDomAttr nameAttribute = document.createAttribute(QStringLiteral("name")); + nameAttribute.setValue(QStringLiteral("VCALENDAR")); + compfilterElement.setAttributeNode(nameAttribute); + filterElement.appendChild(compfilterElement); + + QDomElement subcompfilterElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("comp-filter")); + nameAttribute = document.createAttribute(QStringLiteral("name")); + nameAttribute.setValue(QStringLiteral("VEVENT")); + subcompfilterElement.setAttributeNode(nameAttribute); + + if (!startTime.isEmpty() || !endTime.isEmpty()) { + QDomElement timeRangeElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("time-range")); + + if (!startTime.isEmpty()) { + QDomAttr startAttribute = document.createAttribute(QStringLiteral("start")); + startAttribute.setValue(startTime); + timeRangeElement.setAttributeNode(startAttribute); + } + + if (!endTime.isEmpty()) { + QDomAttr endAttribute = document.createAttribute(QStringLiteral("end")); + endAttribute.setValue(endTime); + timeRangeElement.setAttributeNode(endAttribute); + } + + subcompfilterElement.appendChild(timeRangeElement); + } + + compfilterElement.appendChild(subcompfilterElement); + + return document; + } + + QString mimeType() const override + { + return QStringLiteral("application/x-vnd.akonadi.calendar.event"); + } +}; + +class CaldavListTodoQueryBuilder : public XMLQueryBuilder +{ +public: + QDomDocument buildQuery() const override + { + QString startTime = parameter(QStringLiteral("start")).toString(); + QString endTime = parameter(QStringLiteral("end")).toString(); + QDomDocument document; + + QDomElement queryElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("calendar-query")); + document.appendChild(queryElement); + + QDomElement propElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop")); + queryElement.appendChild(propElement); + + QDomElement getetagElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("getetag")); + propElement.appendChild(getetagElement); + + QDomElement getRTypeElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("resourcetype")); + propElement.appendChild(getRTypeElement); + + QDomElement filterElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("filter")); + queryElement.appendChild(filterElement); + + QDomElement compfilterElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("comp-filter")); + + QDomAttr nameAttribute = document.createAttribute(QStringLiteral("name")); + nameAttribute.setValue(QStringLiteral("VCALENDAR")); + compfilterElement.setAttributeNode(nameAttribute); + filterElement.appendChild(compfilterElement); + + QDomElement subcompfilterElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("comp-filter")); + nameAttribute = document.createAttribute(QStringLiteral("name")); + nameAttribute.setValue(QStringLiteral("VTODO")); + subcompfilterElement.setAttributeNode(nameAttribute); + + if (!startTime.isEmpty() || !endTime.isEmpty()) { + QDomElement timeRangeElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("time-range")); + + if (!startTime.isEmpty()) { + QDomAttr startAttribute = document.createAttribute(QStringLiteral("start")); + startAttribute.setValue(startTime); + timeRangeElement.setAttributeNode(startAttribute); + } + + if (!endTime.isEmpty()) { + QDomAttr endAttribute = document.createAttribute(QStringLiteral("end")); + endAttribute.setValue(endTime); + timeRangeElement.setAttributeNode(endAttribute); + } + + subcompfilterElement.appendChild(timeRangeElement); + } + + compfilterElement.appendChild(subcompfilterElement); + + return document; + } + + QString mimeType() const override + { + return QStringLiteral("application/x-vnd.akonadi.calendar.todo"); + } +}; + +class CaldavListJournalQueryBuilder : public XMLQueryBuilder +{ +public: + QDomDocument buildQuery() const override + { + QString startTime = parameter(QStringLiteral("start")).toString(); + QString endTime = parameter(QStringLiteral("end")).toString(); + QDomDocument document; + + QDomElement queryElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("calendar-query")); + document.appendChild(queryElement); + + QDomElement propElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop")); + queryElement.appendChild(propElement); + + QDomElement getetagElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("getetag")); + propElement.appendChild(getetagElement); + + QDomElement getRTypeElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("resourcetype")); + propElement.appendChild(getRTypeElement); + + QDomElement filterElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("filter")); + queryElement.appendChild(filterElement); + + QDomElement compfilterElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("comp-filter")); + + QDomAttr nameAttribute = document.createAttribute(QStringLiteral("name")); + nameAttribute.setValue(QStringLiteral("VCALENDAR")); + compfilterElement.setAttributeNode(nameAttribute); + filterElement.appendChild(compfilterElement); + + QDomElement subcompfilterElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("comp-filter")); + nameAttribute = document.createAttribute(QStringLiteral("name")); + nameAttribute.setValue(QStringLiteral("VJOURNAL")); + subcompfilterElement.setAttributeNode(nameAttribute); + + if (!startTime.isEmpty() || !endTime.isEmpty()) { + QDomElement timeRangeElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("time-range")); + + if (!startTime.isEmpty()) { + QDomAttr startAttribute = document.createAttribute(QStringLiteral("start")); + startAttribute.setValue(startTime); + timeRangeElement.setAttributeNode(startAttribute); + } + + if (!endTime.isEmpty()) { + QDomAttr endAttribute = document.createAttribute(QStringLiteral("end")); + endAttribute.setValue(endTime); + timeRangeElement.setAttributeNode(endAttribute); + } + + subcompfilterElement.appendChild(timeRangeElement); + } + + compfilterElement.appendChild(subcompfilterElement); + + return document; + } + + QString mimeType() const override + { + return QStringLiteral("application/x-vnd.akonadi.calendar.journal"); + } +}; + +class CaldavMultigetQueryBuilder : public XMLQueryBuilder +{ +public: + QDomDocument buildQuery() const override + { + QDomDocument document; + const QStringList urls = parameter(QStringLiteral("urls")).toStringList(); + if (urls.isEmpty()) { + return document; + } + + QDomElement multigetElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("calendar-multiget")); + document.appendChild(multigetElement); + + QDomElement propElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop")); + multigetElement.appendChild(propElement); + + propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("getetag"))); + propElement.appendChild(document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("calendar-data"))); + + for (const QString &url : urls) { + QDomElement hrefElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("href")); + const QUrl pathUrl = QUrl::fromUserInput(url); + const QDomText textNode = document.createTextNode(pathUrl.path()); + hrefElement.appendChild(textNode); + + multigetElement.appendChild(hrefElement); + } + + return document; + } + + QString mimeType() const override + { + return QString(); + } +}; + +CaldavProtocol::CaldavProtocol() +{ +} + +bool CaldavProtocol::supportsPrincipals() const +{ + return true; +} + +bool CaldavProtocol::useReport() const +{ + return true; +} + +bool CaldavProtocol::useMultiget() const +{ + return true; +} + +QString CaldavProtocol::principalHomeSet() const +{ + return QStringLiteral("calendar-home-set"); +} + +QString CaldavProtocol::principalHomeSetNS() const +{ + return QStringLiteral("urn:ietf:params:xml:ns:caldav"); +} + +XMLQueryBuilder::Ptr CaldavProtocol::collectionsQuery() const +{ + return XMLQueryBuilder::Ptr(new CaldavCollectionQueryBuilder()); +} + +bool CaldavProtocol::containsCollection(const QDomElement &propElem) const +{ + return !propElem.elementsByTagNameNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("calendar")).isEmpty(); +} + +QVector CaldavProtocol::itemsQueries() const +{ + QVector ret; + ret << XMLQueryBuilder::Ptr(new CaldavListEventQueryBuilder()); + ret << XMLQueryBuilder::Ptr(new CaldavListTodoQueryBuilder()); + ret << XMLQueryBuilder::Ptr(new CaldavListJournalQueryBuilder()); + return ret; +} + +XMLQueryBuilder::Ptr CaldavProtocol::itemsReportQuery(const QStringList &urls) const +{ + XMLQueryBuilder::Ptr ret(new CaldavMultigetQueryBuilder()); + ret->setParameter(QStringLiteral("urls"), urls); + return ret; +} + +QString CaldavProtocol::responseNamespace() const +{ + return QStringLiteral("urn:ietf:params:xml:ns:caldav"); +} + +QString CaldavProtocol::dataTagName() const +{ + return QStringLiteral("calendar-data"); +} + +DavCollection::ContentTypes CaldavProtocol::collectionContentTypes(const QDomElement &propstatElement) const +{ + /* + * Extract the content type information from a propstat like the following + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * Test1 User + * + * HTTP/1.1 200 OK + * + */ + + const QDomElement propElement = Utils::firstChildElementNS(propstatElement, QStringLiteral("DAV:"), QStringLiteral("prop")); + const QDomElement supportedcomponentElement = Utils::firstChildElementNS(propElement, // + QStringLiteral("urn:ietf:params:xml:ns:caldav"), + QStringLiteral("supported-calendar-component-set")); + + DavCollection::ContentTypes contentTypes; + QDomElement compElement = Utils::firstChildElementNS(supportedcomponentElement, QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("comp")); + + /* + * Assign the content-type if the server didn't return anything. + * According to RFC4791, §5.2.3: + * In the absence of this property, the server MUST accept all + * component types, and the client can assume that all component + * types are accepted. + */ + if (compElement.isNull()) { + contentTypes |= DavCollection::Calendar; + contentTypes |= DavCollection::Events; + contentTypes |= DavCollection::Todos; + contentTypes |= DavCollection::FreeBusy; + contentTypes |= DavCollection::Journal; + } + + while (!compElement.isNull()) { + const QString type = compElement.attribute(QStringLiteral("name")).toLower(); + if (type == QLatin1String("vcalendar")) { + contentTypes |= DavCollection::Calendar; + } else if (type == QLatin1String("vevent")) { + contentTypes |= DavCollection::Events; + } else if (type == QLatin1String("vtodo")) { + contentTypes |= DavCollection::Todos; + } else if (type == QLatin1String("vfreebusy")) { + contentTypes |= DavCollection::FreeBusy; + } else if (type == QLatin1String("vjournal")) { + contentTypes |= DavCollection::Journal; + } + + compElement = Utils::nextSiblingElementNS(compElement, QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("comp")); + } + + return contentTypes; +} diff --git a/src/protocols/caldavprotocol_p.h b/src/protocols/caldavprotocol_p.h new file mode 100644 index 0000000..7b83acb --- /dev/null +++ b/src/protocols/caldavprotocol_p.h @@ -0,0 +1,31 @@ +/* + SPDX-FileCopyrightText: 2009 Grégory Oestreicher + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KDAV_CALDAVPROTOCOL_H +#define KDAV_CALDAVPROTOCOL_H + +#include "common/davmultigetprotocol_p.h" + +class CaldavProtocol : public KDAV::DavMultigetProtocol +{ +public: + CaldavProtocol(); + Q_REQUIRED_RESULT bool supportsPrincipals() const override; + Q_REQUIRED_RESULT bool useReport() const override; + Q_REQUIRED_RESULT bool useMultiget() const override; + Q_REQUIRED_RESULT QString principalHomeSet() const override; + Q_REQUIRED_RESULT QString principalHomeSetNS() const override; + Q_REQUIRED_RESULT KDAV::XMLQueryBuilder::Ptr collectionsQuery() const override; + Q_REQUIRED_RESULT bool containsCollection(const QDomElement &propElem) const override; + Q_REQUIRED_RESULT QVector itemsQueries() const override; + Q_REQUIRED_RESULT KDAV::XMLQueryBuilder::Ptr itemsReportQuery(const QStringList &urls) const override; + Q_REQUIRED_RESULT QString responseNamespace() const override; + Q_REQUIRED_RESULT QString dataTagName() const override; + + Q_REQUIRED_RESULT KDAV::DavCollection::ContentTypes collectionContentTypes(const QDomElement &propstat) const override; +}; + +#endif diff --git a/src/protocols/carddavprotocol.cpp b/src/protocols/carddavprotocol.cpp new file mode 100644 index 0000000..d0519f1 --- /dev/null +++ b/src/protocols/carddavprotocol.cpp @@ -0,0 +1,173 @@ +/* + SPDX-FileCopyrightText: 2010 Tobias Koenig + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "carddavprotocol_p.h" + +#include +#include +#include + +using namespace KDAV; + +class CarddavCollectionQueryBuilder : public XMLQueryBuilder +{ +public: + QDomDocument buildQuery() const override + { + QDomDocument document; + + QDomElement propfindElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("propfind")); + document.appendChild(propfindElement); + + QDomElement propElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop")); + propfindElement.appendChild(propElement); + + propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("displayname"))); + propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("resourcetype"))); + propElement.appendChild(document.createElementNS(QStringLiteral("http://calendarserver.org/ns/"), QStringLiteral("getctag"))); + + return document; + } + + QString mimeType() const override + { + return QString(); + } +}; + +class CarddavListItemsQueryBuilder : public XMLQueryBuilder +{ +public: + QDomDocument buildQuery() const override + { + QDomDocument document; + + QDomElement propfindElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("propfind")); + document.appendChild(propfindElement); + + QDomElement propElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop")); + propfindElement.appendChild(propElement); + + propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("displayname"))); + propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("resourcetype"))); + propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("getetag"))); + + return document; + } + + QString mimeType() const override + { + return QStringLiteral("text/directory"); + } +}; + +class CarddavMultigetQueryBuilder : public XMLQueryBuilder +{ +public: + QDomDocument buildQuery() const override + { + QDomDocument document; + const QStringList urls = parameter(QStringLiteral("urls")).toStringList(); + if (urls.isEmpty()) { + return document; + } + + QDomElement multigetElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:carddav"), QStringLiteral("addressbook-multiget")); + document.appendChild(multigetElement); + + QDomElement propElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop")); + multigetElement.appendChild(propElement); + + propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("getetag"))); + QDomElement addressDataElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:carddav"), QStringLiteral("address-data")); + addressDataElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("allprop"))); + propElement.appendChild(addressDataElement); + + for (const QString &url : urls) { + QDomElement hrefElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("href")); + const QUrl pathUrl = QUrl::fromUserInput(url); + const QDomText textNode = document.createTextNode(pathUrl.toString()); + hrefElement.appendChild(textNode); + + multigetElement.appendChild(hrefElement); + } + + return document; + } + + QString mimeType() const override + { + return QString(); + } +}; + +CarddavProtocol::CarddavProtocol() +{ +} + +bool CarddavProtocol::supportsPrincipals() const +{ + return true; +} + +bool CarddavProtocol::useReport() const +{ + return false; +} + +bool CarddavProtocol::useMultiget() const +{ + return true; +} + +QString CarddavProtocol::principalHomeSet() const +{ + return QStringLiteral("addressbook-home-set"); +} + +QString CarddavProtocol::principalHomeSetNS() const +{ + return QStringLiteral("urn:ietf:params:xml:ns:carddav"); +} + +XMLQueryBuilder::Ptr CarddavProtocol::collectionsQuery() const +{ + return XMLQueryBuilder::Ptr(new CarddavCollectionQueryBuilder()); +} + +bool CarddavProtocol::containsCollection(const QDomElement &propElem) const +{ + return !propElem.elementsByTagNameNS(QStringLiteral("urn:ietf:params:xml:ns:carddav"), QStringLiteral("addressbook")).isEmpty(); +} + +QVector CarddavProtocol::itemsQueries() const +{ + QVector ret; + ret << XMLQueryBuilder::Ptr(new CarddavListItemsQueryBuilder()); + return ret; +} + +XMLQueryBuilder::Ptr CarddavProtocol::itemsReportQuery(const QStringList &urls) const +{ + XMLQueryBuilder::Ptr ret(new CarddavMultigetQueryBuilder()); + ret->setParameter(QStringLiteral("urls"), urls); + return ret; +} + +QString CarddavProtocol::responseNamespace() const +{ + return QStringLiteral("urn:ietf:params:xml:ns:carddav"); +} + +QString CarddavProtocol::dataTagName() const +{ + return QStringLiteral("address-data"); +} + +DavCollection::ContentTypes CarddavProtocol::collectionContentTypes(const QDomElement &) const +{ + return DavCollection::Contacts; +} diff --git a/src/protocols/carddavprotocol_p.h b/src/protocols/carddavprotocol_p.h new file mode 100644 index 0000000..b51da62 --- /dev/null +++ b/src/protocols/carddavprotocol_p.h @@ -0,0 +1,31 @@ +/* + SPDX-FileCopyrightText: 2010 Tobias Koenig + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KDAV_CARDDAVPROTOCOL_H +#define KDAV_CARDDAVPROTOCOL_H + +#include "common/davmultigetprotocol_p.h" + +class CarddavProtocol : public KDAV::DavMultigetProtocol +{ +public: + CarddavProtocol(); + Q_REQUIRED_RESULT bool supportsPrincipals() const override; + Q_REQUIRED_RESULT bool useReport() const override; + Q_REQUIRED_RESULT bool useMultiget() const override; + Q_REQUIRED_RESULT QString principalHomeSet() const override; + Q_REQUIRED_RESULT QString principalHomeSetNS() const override; + Q_REQUIRED_RESULT KDAV::XMLQueryBuilder::Ptr collectionsQuery() const override; + Q_REQUIRED_RESULT bool containsCollection(const QDomElement &propElem) const override; + Q_REQUIRED_RESULT QVector itemsQueries() const override; + Q_REQUIRED_RESULT KDAV::XMLQueryBuilder::Ptr itemsReportQuery(const QStringList &urls) const override; + Q_REQUIRED_RESULT QString responseNamespace() const override; + Q_REQUIRED_RESULT QString dataTagName() const override; + + Q_REQUIRED_RESULT KDAV::DavCollection::ContentTypes collectionContentTypes(const QDomElement &propstat) const override; +}; + +#endif diff --git a/src/protocols/groupdavprotocol.cpp b/src/protocols/groupdavprotocol.cpp new file mode 100644 index 0000000..5849ebe --- /dev/null +++ b/src/protocols/groupdavprotocol.cpp @@ -0,0 +1,140 @@ +/* + SPDX-FileCopyrightText: 2009 Grégory Oestreicher + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "groupdavprotocol_p.h" + +#include "common/utils_p.h" + +#include + +using namespace KDAV; + +class GroupdavCollectionQueryBuilder : public XMLQueryBuilder +{ +public: + QDomDocument buildQuery() const override + { + QDomDocument document; + + QDomElement propfindElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("propfind")); + document.appendChild(propfindElement); + + QDomElement propElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop")); + propfindElement.appendChild(propElement); + + propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("displayname"))); + propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("resourcetype"))); + + return document; + } + + QString mimeType() const override + { + return QString(); + } +}; + +class GroupdavItemQueryBuilder : public XMLQueryBuilder +{ +public: + QDomDocument buildQuery() const override + { + QDomDocument document; + + QDomElement propfindElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("propfind")); + document.appendChild(propfindElement); + + QDomElement propElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop")); + propfindElement.appendChild(propElement); + + propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("displayname"))); + propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("resourcetype"))); + propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("getetag"))); + + return document; + } + + QString mimeType() const override + { + return QString(); + } +}; + +GroupdavProtocol::GroupdavProtocol() +{ +} + +bool GroupdavProtocol::supportsPrincipals() const +{ + return false; +} + +bool GroupdavProtocol::useReport() const +{ + return false; +} + +bool GroupdavProtocol::useMultiget() const +{ + return false; +} + +XMLQueryBuilder::Ptr GroupdavProtocol::collectionsQuery() const +{ + return XMLQueryBuilder::Ptr(new GroupdavCollectionQueryBuilder()); +} + +bool GroupdavProtocol::containsCollection(const QDomElement &propElem) const +{ + return !propElem.elementsByTagNameNS(QStringLiteral("http://groupdav.org/"), QStringLiteral("vevent-collection")).isEmpty() + || !propElem.elementsByTagNameNS(QStringLiteral("http://groupdav.org/"), QStringLiteral("vtodo-collection")).isEmpty() + || !propElem.elementsByTagNameNS(QStringLiteral("http://groupdav.org/"), QStringLiteral("vcard-collection")).isEmpty(); +} + +QVector GroupdavProtocol::itemsQueries() const +{ + QVector ret; + ret << XMLQueryBuilder::Ptr(new GroupdavItemQueryBuilder()); + return ret; +} + +DavCollection::ContentTypes GroupdavProtocol::collectionContentTypes(const QDomElement &propstatElement) const +{ + /* + * Extract the content type information from a propstat like the following + * + * + * HTTP/1.1 200 OK + * + * Tasks + * + * + * + * + * Sat, 30 Jan 2010 17:52:41 -0100 + * + * + */ + + const QDomElement propElement = Utils::firstChildElementNS(propstatElement, QStringLiteral("DAV:"), QStringLiteral("prop")); + const QDomElement resourcetypeElement = Utils::firstChildElementNS(propElement, QStringLiteral("DAV:"), QStringLiteral("resourcetype")); + + DavCollection::ContentTypes contentTypes; + + if (!Utils::firstChildElementNS(resourcetypeElement, QStringLiteral("http://groupdav.org/"), QStringLiteral("vevent-collection")).isNull()) { + contentTypes |= DavCollection::Events; + } + + if (!Utils::firstChildElementNS(resourcetypeElement, QStringLiteral("http://groupdav.org/"), QStringLiteral("vtodo-collection")).isNull()) { + contentTypes |= DavCollection::Todos; + } + + if (!Utils::firstChildElementNS(resourcetypeElement, QStringLiteral("http://groupdav.org/"), QStringLiteral("vcard-collection")).isNull()) { + contentTypes |= DavCollection::Contacts; + } + + return contentTypes; +} diff --git a/src/protocols/groupdavprotocol_p.h b/src/protocols/groupdavprotocol_p.h new file mode 100644 index 0000000..dc49e65 --- /dev/null +++ b/src/protocols/groupdavprotocol_p.h @@ -0,0 +1,26 @@ +/* + SPDX-FileCopyrightText: 2009 Grégory Oestreicher + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef GROUPDAVPROTOCOL_H +#define GROUPDAVPROTOCOL_H + +#include "common/davprotocolbase_p.h" + +class GroupdavProtocol : public KDAV::DavProtocolBase +{ +public: + GroupdavProtocol(); + Q_REQUIRED_RESULT bool supportsPrincipals() const override; + Q_REQUIRED_RESULT bool useReport() const override; + Q_REQUIRED_RESULT bool useMultiget() const override; + Q_REQUIRED_RESULT KDAV::XMLQueryBuilder::Ptr collectionsQuery() const override; + Q_REQUIRED_RESULT bool containsCollection(const QDomElement &propElem) const override; + Q_REQUIRED_RESULT QVector itemsQueries() const override; + + Q_REQUIRED_RESULT KDAV::DavCollection::ContentTypes collectionContentTypes(const QDomElement &propstat) const override; +}; + +#endif diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..b232eee --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,11 @@ +kde_enable_exceptions() +set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) + +add_executable(testserver testserver.cpp) + +target_link_libraries(testserver + Qt${QT_MAJOR_VERSION}::Core + KF5::DAV + Qt${QT_MAJOR_VERSION}::Xml + ) + diff --git a/test/testserver.cpp b/test/testserver.cpp new file mode 100644 index 0000000..bac0135 --- /dev/null +++ b/test/testserver.cpp @@ -0,0 +1,164 @@ +/* + SPDX-FileCopyrightText: 2016 Sandro Knauß + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + + QUrl mainUrl(QStringLiteral("https://apps.kolabnow.com/addressbooks/test1%40kolab.org")); + mainUrl.setUserName(QStringLiteral("test1@kolab.org")); + mainUrl.setPassword(QStringLiteral("Welcome2KolabSystems")); + KDAV::DavUrl davUrl(mainUrl, KDAV::CardDav); + + auto *job = new KDAV::DavCollectionsFetchJob(davUrl); + job->exec(); + + const auto collections = job->collections(); + for (const auto &collection : collections) { + qDebug() << collection.displayName() << "PRIVS: " << collection.privileges(); + auto collectionUrl = collection.url(); + std::shared_ptr cache(new KDAV::EtagCache()); + int anz = -1; + // Get all items in a collection add them to cache and make sure, that afterward no item is changed + { + auto itemListJob = new KDAV::DavItemsListJob(collectionUrl, cache); + itemListJob->exec(); + anz = itemListJob->items().size(); + qDebug() << "items:" << itemListJob->items().size(); + qDebug() << "changed Items:" << itemListJob->changedItems().size(); + qDebug() << "deleted Items:" << itemListJob->deletedItems(); + const auto changedItems = itemListJob->changedItems(); + for (const auto &item : changedItems) { + qDebug() << item.url().url() << item.contentType() << item.data(); + auto itemFetchJob = new KDAV::DavItemFetchJob(item); + itemFetchJob->exec(); + const auto fetchedItem = itemFetchJob->item(); + qDebug() << fetchedItem.contentType() << fetchedItem.data(); + + auto itemsFetchJob = new KDAV::DavItemsFetchJob(collectionUrl, QStringList() << item.url().toDisplayString()); + itemsFetchJob->exec(); + if (itemsFetchJob->item(item.url().toDisplayString()).contentType() != fetchedItem.contentType()) { // itemsfetchjob do not get contentType + qDebug() << "Fetched same item but got different contentType:" << itemsFetchJob->item(item.url().toDisplayString()).contentType(); + } + + if (itemsFetchJob->item(item.url().toDisplayString()).data() != fetchedItem.data()) { + qDebug() << "Fetched same item but got different data:" << itemsFetchJob->item(item.url().toDisplayString()).data(); + } + + cache->setEtag(item.url().toDisplayString(), item.etag()); + } + cache->setEtag(QStringLiteral("invalid"), QStringLiteral("invalid")); + } + { + qDebug() << "second run: (should be empty)."; + auto itemListJob = new KDAV::DavItemsListJob(collectionUrl, cache); + itemListJob->exec(); + if (itemListJob->items().size() != anz) { + qDebug() << "Items have added/deleted on server."; + } + if (itemListJob->changedItems().size() != 0) { + qDebug() << "Items have changed on server."; + } + if (itemListJob->deletedItems() != QStringList() << QStringLiteral("invalid")) { + qDebug() << "more items deleted:" << itemListJob->deletedItems(); + } + } + } + + { + QUrl url(QStringLiteral("https://apps.kolabnow.com/addressbooks/test1%40kolab.org/cbbf386d-7e9b-4e72-947d-0b813ea9b347/")); + url.setUserInfo(mainUrl.userInfo()); + KDAV::DavUrl collectionUrl(url, KDAV::CardDav); + auto collectionDeleteJob = new KDAV::DavCollectionDeleteJob(collectionUrl); + collectionDeleteJob->exec(); + if (collectionDeleteJob->error()) { + qDebug() << collectionDeleteJob->errorString(); + } + } + + { + QUrl url(QStringLiteral("https://apps.kolabnow.com/addressbooks/test1%40kolab.org/9290e784-c876-412f-8385-be292d64b2c6/")); + url.setUserInfo(mainUrl.userInfo()); + KDAV::DavUrl testCollectionUrl(url, KDAV::CardDav); + auto collectionModifyJob = new KDAV::DavCollectionModifyJob(testCollectionUrl); + collectionModifyJob->setProperty(QStringLiteral("displayname"), QStringLiteral("test234")); + collectionModifyJob->exec(); + if (collectionModifyJob->error()) { + qDebug() << collectionModifyJob->errorString(); + } + } + + // create element with "wrong put url" test if we get the correct url back + { + QUrl url(QStringLiteral("https://apps.kolabnow.com/addressbooks/test1%40kolab.org/9290e784-c876-412f-8385-be292d64b2c6/xxx.vcf")); + url.setUserInfo(mainUrl.userInfo()); + KDAV::DavUrl testItemUrl(url, KDAV::CardDav); + QByteArray data = + "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Kolab//iRony DAV Server 0.3.1//Sabre//Sabre VObject " + "2.1.7//EN\r\nUID:12345678-1234-1234-1234-123456789abc\r\nFN:John " + "Doe\r\nN:Doe;John;;;\r\nEMAIL;TYPE=INTERNET;TYPE=HOME:john.doe@example.com\r\nREV;VALUE=DATE-TIME:20161221T145611Z\r\nEND:VCARD\r\n"; + KDAV::DavItem item(testItemUrl, QStringLiteral("text/x-vcard"), data, QString()); + auto createJob = new KDAV::DavItemCreateJob(item); + createJob->exec(); + if (createJob->error()) { + qDebug() << createJob->errorString(); + } + if (createJob->item().url().toDisplayString() + != QLatin1String( + "https://apps.kolabnow.com/addressbooks/test1%40kolab.org/9290e784-c876-412f-8385-be292d64b2c6/12345678-1234-1234-1234-123456789abc.vcf")) { + qDebug() << "unexpected url" << createJob->item().url().url(); + } + } + + { + QUrl url(QStringLiteral( + "https://apps.kolabnow.com/addressbooks/test1%40kolab.org/9290e784-c876-412f-8385-be292d64b2c6/12345678-1234-1234-1234-123456789abc.vcf")); + url.setUserInfo(mainUrl.userInfo()); + KDAV::DavUrl testItemUrl(url, KDAV::CardDav); + QByteArray data = + "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Kolab//iRony DAV Server 0.3.1//Sabre//Sabre VObject " + "2.1.7//EN\r\nUID:12345678-1234-1234-1234-123456789abc\r\nFN:John2 " + "Doe\r\nN:Doe;John2;;;\r\nEMAIL;TYPE=INTERNET;TYPE=HOME:john2.doe@example.com\r\nREV;VALUE=DATE-TIME:20161221T145611Z\r\nEND:VCARD\r\n"; + KDAV::DavItem item(testItemUrl, QStringLiteral("text/x-vcard"), data, QString()); + auto modifyJob = new KDAV::DavItemModifyJob(item); + modifyJob->exec(); + if (modifyJob->error()) { + qDebug() << modifyJob->errorString(); + } + } + + { + QUrl url(QStringLiteral( + "https://apps.kolabnow.com/addressbooks/test1%40kolab.org/9290e784-c876-412f-8385-be292d64b2c6/12345678-1234-1234-1234-123456789abc.vcf")); + url.setUserInfo(mainUrl.userInfo()); + KDAV::DavUrl testItemUrl(url, KDAV::CardDav); + QByteArray data = + "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Kolab//iRony DAV Server 0.3.1//Sabre//Sabre VObject " + "2.1.7//EN\r\nUID:12345678-1234-1234-1234-123456789abc\r\nFN:John2 " + "Doe\r\nN:Doe;John2;;;\r\nEMAIL;TYPE=INTERNET;TYPE=HOME:john2.doe@example.com\r\nREV;VALUE=DATE-TIME:20161221T145611Z\r\nEND:VCARD\r\n"; + KDAV::DavItem item(testItemUrl, QStringLiteral("text/x-vcard"), data, QString()); + auto deleteJob = new KDAV::DavItemDeleteJob(item); + deleteJob->exec(); + if (deleteJob->error()) { + qDebug() << deleteJob->errorString(); + } + } +}