Import kdav_5.97.0.orig.tar.xz
authorAurélien COUDERC <coucouf@debian.org>
Sun, 14 Aug 2022 16:55:39 +0000 (17:55 +0100)
committerAurélien COUDERC <coucouf@debian.org>
Sun, 14 Aug 2022 16:55:39 +0000 (17:55 +0100)
[dgit import orig kdav_5.97.0.orig.tar.xz]

130 files changed:
.gitignore [new file with mode: 0644]
.gitlab-ci.yml [new file with mode: 0644]
.kde-ci.yml [new file with mode: 0644]
CMakeLists.txt [new file with mode: 0644]
KF5DAVConfig.cmake.in [new file with mode: 0644]
LICENSES/CC0-1.0.txt [new file with mode: 0644]
LICENSES/GPL-2.0-or-later.txt [new file with mode: 0644]
LICENSES/LGPL-2.0-or-later.txt [new file with mode: 0644]
README.md [new file with mode: 0644]
autotests/CMakeLists.txt [new file with mode: 0644]
autotests/data/dataitemfetchjob.txt [new file with mode: 0644]
autotests/data/dataitemmultifetchjob-caldav-collections.txt [new file with mode: 0644]
autotests/data/dataitemmultifetchjob-caldav.txt [new file with mode: 0644]
autotests/data/dataitemmultifetchjob-carddav-collections.txt [new file with mode: 0644]
autotests/data/dataitemmultifetchjob-carddav.txt [new file with mode: 0644]
autotests/data/dataitemmultifetchjob-error.txt [new file with mode: 0644]
autotests/davcollectionsmultifetchjobtest.cpp [new file with mode: 0644]
autotests/davcollectionsmultifetchjobtest.h [new file with mode: 0644]
autotests/davcollectiontest.cpp [new file with mode: 0644]
autotests/davcollectiontest.h [new file with mode: 0644]
autotests/davitemfetchjobtest.cpp [new file with mode: 0644]
autotests/davitemfetchjobtest.h [new file with mode: 0644]
autotests/davitemslistjobtest.cpp [new file with mode: 0644]
autotests/davitemslistjobtest.h [new file with mode: 0644]
autotests/davitemtest.cpp [new file with mode: 0644]
autotests/davitemtest.h [new file with mode: 0644]
autotests/davurltest.cpp [new file with mode: 0644]
autotests/davurltest.h [new file with mode: 0644]
autotests/fakeserver.cpp [new file with mode: 0644]
autotests/fakeserver.h [new file with mode: 0644]
metainfo.yaml [new file with mode: 0644]
po/ar/libkdav.po [new file with mode: 0644]
po/az/libkdav.po [new file with mode: 0644]
po/bg/libkdav.po [new file with mode: 0644]
po/ca/libkdav.po [new file with mode: 0644]
po/ca@valencia/libkdav.po [new file with mode: 0644]
po/cs/libkdav.po [new file with mode: 0644]
po/de/libkdav.po [new file with mode: 0644]
po/el/libkdav.po [new file with mode: 0644]
po/en_GB/libkdav.po [new file with mode: 0644]
po/es/libkdav.po [new file with mode: 0644]
po/et/libkdav.po [new file with mode: 0644]
po/eu/libkdav.po [new file with mode: 0644]
po/fi/libkdav.po [new file with mode: 0644]
po/fr/libkdav.po [new file with mode: 0644]
po/gl/libkdav.po [new file with mode: 0644]
po/hi/libkdav.po [new file with mode: 0644]
po/ia/libkdav.po [new file with mode: 0644]
po/it/libkdav.po [new file with mode: 0644]
po/ja/libkdav.po [new file with mode: 0644]
po/ka/libkdav.po [new file with mode: 0644]
po/ko/libkdav.po [new file with mode: 0644]
po/lt/libkdav.po [new file with mode: 0644]
po/nb/libkdav.po [new file with mode: 0644]
po/nl/libkdav.po [new file with mode: 0644]
po/nn/libkdav.po [new file with mode: 0644]
po/pl/libkdav.po [new file with mode: 0644]
po/pt/libkdav.po [new file with mode: 0644]
po/pt_BR/libkdav.po [new file with mode: 0644]
po/ro/libkdav.po [new file with mode: 0644]
po/ru/libkdav.po [new file with mode: 0644]
po/sk/libkdav.po [new file with mode: 0644]
po/sl/libkdav.po [new file with mode: 0644]
po/sr/libkdav.po [new file with mode: 0644]
po/sr@ijekavian/libkdav.po [new file with mode: 0644]
po/sr@ijekavianlatin/libkdav.po [new file with mode: 0644]
po/sr@latin/libkdav.po [new file with mode: 0644]
po/sv/libkdav.po [new file with mode: 0644]
po/tr/libkdav.po [new file with mode: 0644]
po/uk/libkdav.po [new file with mode: 0644]
po/zh_CN/libkdav.po [new file with mode: 0644]
po/zh_TW/libkdav.po [new file with mode: 0644]
src/CMakeLists.txt [new file with mode: 0644]
src/Messages.sh [new file with mode: 0644]
src/common/davcollection.cpp [new file with mode: 0644]
src/common/davcollection.h [new file with mode: 0644]
src/common/davcollectiondeletejob.cpp [new file with mode: 0644]
src/common/davcollectiondeletejob.h [new file with mode: 0644]
src/common/davcollectionmodifyjob.cpp [new file with mode: 0644]
src/common/davcollectionmodifyjob.h [new file with mode: 0644]
src/common/davcollectionsfetchjob.cpp [new file with mode: 0644]
src/common/davcollectionsfetchjob.h [new file with mode: 0644]
src/common/davcollectionsmultifetchjob.cpp [new file with mode: 0644]
src/common/davcollectionsmultifetchjob.h [new file with mode: 0644]
src/common/daverror.cpp [new file with mode: 0644]
src/common/daverror.h [new file with mode: 0644]
src/common/davitem.cpp [new file with mode: 0644]
src/common/davitem.h [new file with mode: 0644]
src/common/davitemcreatejob.cpp [new file with mode: 0644]
src/common/davitemcreatejob.h [new file with mode: 0644]
src/common/davitemdeletejob.cpp [new file with mode: 0644]
src/common/davitemdeletejob.h [new file with mode: 0644]
src/common/davitemfetchjob.cpp [new file with mode: 0644]
src/common/davitemfetchjob.h [new file with mode: 0644]
src/common/davitemmodifyjob.cpp [new file with mode: 0644]
src/common/davitemmodifyjob.h [new file with mode: 0644]
src/common/davitemsfetchjob.cpp [new file with mode: 0644]
src/common/davitemsfetchjob.h [new file with mode: 0644]
src/common/davitemslistjob.cpp [new file with mode: 0644]
src/common/davitemslistjob.h [new file with mode: 0644]
src/common/davjobbase.cpp [new file with mode: 0644]
src/common/davjobbase.h [new file with mode: 0644]
src/common/davjobbase_p.h [new file with mode: 0644]
src/common/davmanager.cpp [new file with mode: 0644]
src/common/davmanager_p.h [new file with mode: 0644]
src/common/davmultigetprotocol.cpp [new file with mode: 0644]
src/common/davmultigetprotocol_p.h [new file with mode: 0644]
src/common/davprincipalhomesetsfetchjob.cpp [new file with mode: 0644]
src/common/davprincipalhomesetsfetchjob.h [new file with mode: 0644]
src/common/davprincipalsearchjob.cpp [new file with mode: 0644]
src/common/davprincipalsearchjob.h [new file with mode: 0644]
src/common/davprotocolbase.cpp [new file with mode: 0644]
src/common/davprotocolbase_p.h [new file with mode: 0644]
src/common/davurl.cpp [new file with mode: 0644]
src/common/davurl.h [new file with mode: 0644]
src/common/enums.h [new file with mode: 0644]
src/common/etagcache.cpp [new file with mode: 0644]
src/common/etagcache.h [new file with mode: 0644]
src/common/protocolinfo.cpp [new file with mode: 0644]
src/common/protocolinfo.h [new file with mode: 0644]
src/common/utils.cpp [new file with mode: 0644]
src/common/utils_p.h [new file with mode: 0644]
src/protocols/caldavprotocol.cpp [new file with mode: 0644]
src/protocols/caldavprotocol_p.h [new file with mode: 0644]
src/protocols/carddavprotocol.cpp [new file with mode: 0644]
src/protocols/carddavprotocol_p.h [new file with mode: 0644]
src/protocols/groupdavprotocol.cpp [new file with mode: 0644]
src/protocols/groupdavprotocol_p.h [new file with mode: 0644]
test/CMakeLists.txt [new file with mode: 0644]
test/testserver.cpp [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..4231aac
--- /dev/null
@@ -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 (file)
index 0000000..04bb392
--- /dev/null
@@ -0,0 +1,10 @@
+# SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org>
+# 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 (file)
index 0000000..5334735
--- /dev/null
@@ -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 (file)
index 0000000..73d59ac
--- /dev/null
@@ -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 (file)
index 0000000..677262f
--- /dev/null
@@ -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 (file)
index 0000000..0e259d4
--- /dev/null
@@ -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 (file)
index 0000000..1d80ac3
--- /dev/null
@@ -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.
+
+<one line to give the program's name and an idea of what it does.>
+
+Copyright (C) <yyyy> <name of author>
+
+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.
+
+<signature of Ty Coon>, 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 (file)
index 0000000..5c96471
--- /dev/null
@@ -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 (file)
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/<USER>/Calendar and https://host/SOGo/dav/<USER>/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/<USER>
+  - CalDAV working.
+
+* Zimbra Open-Source edition (version 5.0.18),
+  https://host/principals/users/<USER>
+  - 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/<CALENDAR_ID>/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 (file)
index 0000000..9bfcb92
--- /dev/null
@@ -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 (file)
index 0000000..26588f9
--- /dev/null
@@ -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 (file)
index 0000000..5d29dbc
--- /dev/null
@@ -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: <?xml version="1.0" encoding="utf-8" ?>
+D: <multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
+D:   <response xmlns="DAV:">
+D:    <href xmlns="DAV:">/caldav.php/test1.user/home/</href>
+D:    <propstat xmlns="DAV:">
+D:      <prop xmlns="DAV:">
+D:        <C:supported-calendar-component-set xmlns:C="urn:ietf:params:xml:ns:caldav">
+D:          <C:comp xmlns:C="urn:ietf:params:xml:ns:caldav" name="VEVENT"/>
+D:          <C:comp xmlns:C="urn:ietf:params:xml:ns:caldav" name="VTODO"/>
+D:          <C:comp xmlns:C="urn:ietf:params:xml:ns:caldav" name="VJOURNAL"/>
+D:          <C:comp xmlns:C="urn:ietf:params:xml:ns:caldav" name="VTIMEZONE"/>
+D:          <C:comp xmlns:C="urn:ietf:params:xml:ns:caldav" name="VFREEBUSY"/>
+D:        </C:supported-calendar-component-set>
+D:        <resourcetype xmlns="DAV:">
+D:          <collection xmlns="DAV:"/>
+D:          <C:calendar xmlns:C="urn:ietf:params:xml:ns:caldav"/>
+D:          <C:schedule-calendar xmlns:C="urn:ietf:params:xml:ns:caldav"/>
+D:        </resourcetype>
+D:        <displayname xmlns="DAV:">Test1 User</displayname>
+D:        <current-user-privilege-set xmlns="DAV:">
+D:          <privilege xmlns="DAV:">
+D:            <read xmlns="DAV:"/>
+D:          </privilege>
+D:        </current-user-privilege-set>
+D:        <getctag xmlns="http://calendarserver.org/ns/">12345</getctag>
+D:      </prop>
+D:      <status xmlns="DAV:">HTTP/1.1 200 OK</status>
+D:    </propstat>
+D:   </response>
+D: </multistatus>
+X
diff --git a/autotests/data/dataitemmultifetchjob-caldav.txt b/autotests/data/dataitemmultifetchjob-caldav.txt
new file mode 100644 (file)
index 0000000..e876f57
--- /dev/null
@@ -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: <?xml version="1.0" encoding="utf-8" ?>
+D: <multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
+D:   <response>
+D:     <href>/principals/users/dfaure%40example.com/</href>
+D:     <propstat>
+D:       <prop>
+D:         <C:calendar-home-set>
+D:           <href>/caldav/dfaure%40example.com/</href>
+D:         </C:calendar-home-set>
+D:       </prop>
+D:       <status>HTTP/1.1 200 OK</status>
+D:     </propstat>
+D:   </response>
+D: </multistatus>
+X
diff --git a/autotests/data/dataitemmultifetchjob-carddav-collections.txt b/autotests/data/dataitemmultifetchjob-carddav-collections.txt
new file mode 100644 (file)
index 0000000..e63496d
--- /dev/null
@@ -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: <?xml version="1.0" encoding="utf-8" ?>
+D: <multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:carddav">
+D:   <response xmlns="DAV:">
+D:    <href xmlns="DAV:">/carddav.php/test1.user/home/</href>
+D:    <propstat xmlns="DAV:">
+D:      <prop xmlns="DAV:">
+D:        <resourcetype xmlns="DAV:">
+D:          <collection xmlns="DAV:"/>
+D:          <C:addressbook xmlns:C="urn:ietf:params:xml:ns:carddav"/>
+D:        </resourcetype>
+D:        <displayname xmlns="DAV:">My Address Book</displayname>
+D:        <getctag xmlns="http://calendarserver.org/ns/">3145</getctag>
+D:      </prop>
+D:      <status xmlns="DAV:">HTTP/1.1 200 OK</status>
+D:    </propstat>
+D:   </response>
+D: </multistatus>
+X
diff --git a/autotests/data/dataitemmultifetchjob-carddav.txt b/autotests/data/dataitemmultifetchjob-carddav.txt
new file mode 100644 (file)
index 0000000..6a389b7
--- /dev/null
@@ -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: <?xml version="1.0" encoding="utf-8" ?>
+D: <multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:carddav">
+D:   <response>
+D:     <href>/principals/users/dfaure%40example.com/</href>
+D:     <propstat>
+D:       <prop>
+D:         <C:addressbook-home-set>
+D:           <href>/carddav/dfaure%40example.com/</href>
+D:         </C:addressbook-home-set>
+D:       </prop>
+D:       <status>HTTP/1.1 200 OK</status>
+D:     </propstat>
+D:   </response>
+D: </multistatus>
+X
diff --git a/autotests/data/dataitemmultifetchjob-error.txt b/autotests/data/dataitemmultifetchjob-error.txt
new file mode 100644 (file)
index 0000000..ada1fb0
--- /dev/null
@@ -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 (file)
index 0000000..497d340
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+    SPDX-FileCopyrightText: 2020 David Faure <faure@kde.org>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "davcollectionsmultifetchjobtest.h"
+#include "fakeserver.h"
+
+#include <KDAV/DavCollectionsMultiFetchJob>
+
+#include <QSignalSpy>
+#include <QTest>
+
+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<KDAV::Protocol>();
+}
+
+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<KDAV::Protocol>()), 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<KDAV::Protocol>()), 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 (file)
index 0000000..9a652af
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+    SPDX-FileCopyrightText: 2020 David Faure <faure@kde.org>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#ifndef DAVITEMFETCHJOB_TEST_H
+#define DAVITEMFETCHJOB_TEST_H
+
+#include <QObject>
+
+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 (file)
index 0000000..eb69128
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+    SPDX-FileCopyrightText: 2017 Sandro Knauß <sknauss@kde.org>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "davcollectiontest.h"
+
+#include <KDAV/DavCollection>
+#include <KDAV/DavUrl>
+
+#include <QColor>
+#include <QTest>
+
+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 (file)
index 0000000..de4a87c
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+    SPDX-FileCopyrightText: 2017 Sandro Knauß <sknauss@kde.org>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#ifndef DAVCOLLECTION_TEST_H
+#define DAVCOLLECTION_TEST_H
+
+#include <QObject>
+
+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 (file)
index 0000000..46d0742
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+    SPDX-FileCopyrightText: 2017 Sandro Knauß <sknauss@kde.org>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "davitemfetchjobtest.h"
+#include "fakeserver.h"
+
+#include <KDAV/DavItemFetchJob>
+
+#include <QTest>
+
+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 (file)
index 0000000..e86f016
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+    SPDX-FileCopyrightText: 2017 Sandro Knauß <sknauss@kde.org>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#ifndef DAVITEMFETCHJOB_TEST_H
+#define DAVITEMFETCHJOB_TEST_H
+
+#include <QObject>
+
+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 (file)
index 0000000..41daeb5
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+    SPDX-FileCopyrightText: 2017 Sandro Knauß <sknauss@kde.org>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "davitemslistjobtest.h"
+#include "fakeserver.h"
+
+#include <KDAV/DavError>
+#include <KDAV/DavItemsListJob>
+#include <KDAV/DavUrl>
+#include <KDAV/EtagCache>
+
+#include <QTest>
+
+void DavItemsListJobTest::noMatchingMimetype()
+{
+    std::shared_ptr<KDAV::EtagCache> 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<int>(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 (file)
index 0000000..87fa092
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+    SPDX-FileCopyrightText: 2017 Sandro Knauß <sknauss@kde.org>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#ifndef DAVITEMSLISTJOB_TEST_H
+#define DAVITEMSLISTJOB_TEST_H
+
+#include <QObject>
+
+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 (file)
index 0000000..7a17fb3
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+    SPDX-FileCopyrightText: 2017 Sandro Knauß <sknauss@kde.org>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "davitemtest.h"
+
+#include <KDAV/DavItem>
+#include <KDAV/DavUrl>
+
+#include <QDataStream>
+#include <QTest>
+
+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 (file)
index 0000000..0ea589b
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+    SPDX-FileCopyrightText: 2017 Sandro Knauß <sknauss@kde.org>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#ifndef DAVITEM_TEST_H
+#define DAVITEM_TEST_H
+
+#include <QObject>
+
+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 (file)
index 0000000..008003e
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+    SPDX-FileCopyrightText: 2017 Sandro Knauß <sknauss@kde.org>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "davurltest.h"
+
+#include <KDAV/DavUrl>
+
+#include <QDataStream>
+#include <QTest>
+
+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 (file)
index 0000000..ecc7624
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+    SPDX-FileCopyrightText: 2017 Sandro Knauß <sknauss@kde.org>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#ifndef DAVURL_TEST_H
+#define DAVURL_TEST_H
+
+#include <QObject>
+
+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 (file)
index 0000000..84ce022
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+    SPDX-FileCopyrightText: 2008 Omat Holding B .V. <info@omat.nl>
+    SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB , a KDAB Group company <info@kdab.com>
+    SPDX-FileContributor: Kevin Ottens <kevin@kdab.com>
+    SPDX-FileCopyrightText: 2017 Sandro Kanuß <knauss@kde.org>
+
+    SPDX-License-Identifier: GPL-2.0-or-later
+*/
+
+// Own
+#include "fakeserver.h"
+
+// Qt
+#include <QDebug>
+#include <QFile>
+#include <QTest>
+
+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<QTcpSocket *>(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<QByteArray> &scenario)
+{
+    QMutexLocker locker(&m_mutex);
+
+    m_scenarios.clear();
+    m_scenarios << scenario;
+}
+
+void FakeServer::addScenario(const QList<QByteArray> &scenario)
+{
+    QMutexLocker locker(&m_mutex);
+
+    m_scenarios << scenario;
+}
+
+void FakeServer::addScenarioFromFile(const QString &fileName)
+{
+    QFile file(fileName);
+    file.open(QIODevice::ReadOnly | QIODevice::Text);
+
+    QList<QByteArray> 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<QByteArray> &scenario : std::as_const(m_scenarios)) {
+        if (!scenario.isEmpty()) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+void FakeServer::writeServerPart(QTcpSocket *clientSocket, int scenarioNumber)
+{
+    QList<QByteArray> 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<QByteArray> &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<QByteArray> scenario = *it;
+    QVector<QByteArray> 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 (file)
index 0000000..38cab61
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+    SPDX-FileCopyrightText: 2008 Omat Holding B .V. <info@omat.nl>
+    SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB , a KDAB Group company <info@kdab.com>
+    SPDX-FileContributor: Kevin Ottens <kevin@kdab.com>
+    SPDX-FileCopyrightText: 2017 Sandro Kanuß <knauss@kde.org>
+
+    SPDX-License-Identifier: GPL-2.0-or-later
+*/
+
+#ifndef FAKESERVER_H
+#define FAKESERVER_H
+
+#include <QMutex>
+#include <QTcpServer>
+#include <QTcpSocket>
+#include <QThread>
+
+Q_DECLARE_METATYPE(QList<QByteArray>)
+
+/**
+ * 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<QByteArray> 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<QByteArray> &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<QByteArray> &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<QList<QByteArray>> m_scenarios;
+    QTcpServer *m_tcpServer = nullptr;
+    mutable QMutex m_mutex;
+    QList<QTcpSocket *> m_clientSockets;
+    QThread *m_thread;
+    int m_port;
+};
+
+#endif
diff --git a/metainfo.yaml b/metainfo.yaml
new file mode 100644 (file)
index 0000000..3596e12
--- /dev/null
@@ -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 (file)
index 0000000..56a031a
--- /dev/null
@@ -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 <safa1996alfulaij@gmail.com>, 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 <safa1996alfulaij@gmail.com>\n"
+"Language-Team: Arabic <doc@arabeyes.org>\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 (file)
index 0000000..4469190
--- /dev/null
@@ -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 <xxmn77@gmail.com>, 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 <xxmn77@gmail.com>\n"
+"Language-Team: Azerbaijani <kde-i18n-doc@kde.org>\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 (file)
index 0000000..6a387df
--- /dev/null
@@ -0,0 +1,155 @@
+# Mincho Kondarev <mkondarev@yahoo.de>, 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 <mkondarev@yahoo.de>\n"
+"Language-Team: Bulgarian <kde-i18n-doc@kde.org>\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 (file)
index 0000000..c743c1d
--- /dev/null
@@ -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 <manutortosa@gmail.com>, 2009, 2010.
+# Josep M. Ferrer <txemaq@gmail.com>, 2010, 2011, 2012, 2015, 2017.
+# Antoni Bella Pérez <antonibella5@yahoo.com>, 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 <antonibella5@yahoo.com>\n"
+"Language-Team: Catalan <kde-i18n-ca@kde.org>\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 (file)
index 0000000..3b058a5
--- /dev/null
@@ -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 <manutortosa@gmail.com>, 2009, 2010.
+# Josep M. Ferrer <txemaq@gmail.com>, 2010, 2011, 2012, 2015, 2017.
+# Antoni Bella Pérez <antonibella5@yahoo.com>, 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 <antonibella5@yahoo.com>\n"
+"Language-Team: Catalan <kde-i18n-ca@kde.org>\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 (file)
index 0000000..d8c575e
--- /dev/null
@@ -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 <vit@pelcak.org>, 2010, 2011, 2013, 2016, 2017, 2018.
+# Tomáš Chvátal <tomas.chvatal@gmail.com>, 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 <vit@pelcak.org>\n"
+"Language-Team: Czech <kde-i18n-doc@kde.org>\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 (file)
index 0000000..0b22773
--- /dev/null
@@ -0,0 +1,168 @@
+# Burkhard Lück <lueck@hube-lueck.de>, 2009, 2011, 2013, 2014, 2015, 2017, 2018, 2020, 2021.
+# Frederik Schwarzer <schwarzer@kde.org>, 2010, 2011, 2016, 2020.
+# Panagiotis Papadopoulos <pano_90@gmx.net>, 2010.
+# Peter Rüthemann <peter.ruethemann@gmx.ch>, 2010.
+# Torbjörn Klatt <opensource@torbjoern-klatt.de>, 2011.
+# Rolf Eike Beer <kde@opensource.sf-tec.de>, 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 <lueck@hube-lueck.de>\n"
+"Language-Team: German <kde-i18n-de@kde.org>\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 (file)
index 0000000..987d820
--- /dev/null
@@ -0,0 +1,165 @@
+# Copyright (C) YEAR This file is copyright:
+# This file is distributed under the same license as the kdav package.
+#
+# Stelios <sstavra@gmail.com>, 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 <sstavra@gmail.com>\n"
+"Language-Team: Greek <kde-i18n-el@kde.org>\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 (file)
index 0000000..297e5ca
--- /dev/null
@@ -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 <steve.allewell@gmail.com>, 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 <steve.allewell@gmail.com>\n"
+"Language-Team: British English <kde-l10n-en_gb@kde.org>\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 (file)
index 0000000..8244afd
--- /dev/null
@@ -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 <EMAIL@ADDRESS>, 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 <fjvinal@gmail.com>\n"
+"Language-Team: Spanish <l10n-kde-es@kde.org>\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 (file)
index 0000000..11ec05e
--- /dev/null
@@ -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 <qiilaq69@gmail.com>, 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 <qiilaq69@gmail.com>\n"
+"Language-Team: Estonian <kde-et@lists.linux.ee>\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 (file)
index 0000000..8eda54c
--- /dev/null
@@ -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 <xalba@ni.eus>.
+#
+# Translators:
+# Iñigo Salvador Azurmendi <xalba@ni.eus>, 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 <xalba@ni.eus>\n"
+"Language-Team: Basque <kde-i18n-eu@kde.org>\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 (file)
index 0000000..4c15b3c
--- /dev/null
@@ -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 <translator@legisign.org>, 2011, 2012, 2013, 2015, 2016, 2017.
+# Lasse Liehu <lasse.liehu@gmail.com>, 2012, 2013, 2014, 2015.
+# Jiri Grönroos <jiri.gronroos+kde@iki.fi>, 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 <translator@legisign.org>\n"
+"Language-Team: Finnish <kde-i18n-doc@kde.org>\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 (file)
index 0000000..a92c401
--- /dev/null
@@ -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 <guill.p@gmail.com>, 2009, 2010.
+# Geoffray Levasseur <geoffray.levasseurbrandin@numericable.fr>, 2012, 2013, 2014.
+# xavier <xavier.besnard@neuf.fr>, 2013.
+# Joëlle Cornavin <jcornavin@laposte.net>, 2011.
+# Sebastien Renard <renard@kde.org>, 2013.
+# Vincent Pinon <vpinon@kde.org>, 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 <vpinon@kde.org>\n"
+"Language-Team: French <kde-francophone@kde.org>\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 (file)
index 0000000..f1ee055
--- /dev/null
@@ -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é <xosecalvo@gmail.com>, 2009, 2010, 2013.
+# Adrian Chaves Fernandez <adriyetichaves@gmail.com>, 2013, 2015, 2017.
+# Marce Villarino <mvillarino@kde-espana.org>, 2014.
+# Adrián Chaves (Gallaecio) <adrian@chaves.io>, 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) <adrian@chaves.io>\n"
+"Language-Team: Galician <kde-i18n-doc@kde.org>\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 (file)
index 0000000..429a9b7
--- /dev/null
@@ -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 <lumarzeli30@gmail.com>, 2021.
+# Raghavendra Kamath <raghu@raghukamath.com>, 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 <raghu@raghukamath.com>\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 (file)
index 0000000..e004ad4
--- /dev/null
@@ -0,0 +1,166 @@
+# Copyright (C) YEAR This file is copyright:
+# This file is distributed under the same license as the kdav package.
+#
+# giovanni <g.sora@tiscali.it>, 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 <g.sora@tiscali.it>\n"
+"Language-Team: Interlingua <kde-i18n-it@kde.org>\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 (file)
index 0000000..b5344a4
--- /dev/null
@@ -0,0 +1,158 @@
+# translation of akonadi_davgroupware_resource.po to Italian
+#
+# Vincenzo Reale <smart2128vr@gmail.com>, 2009, 2010.
+# Nicola Ruggero <nicola@nxnt.org>, 2010, 2011.
+# Luigi Toscano <luigi.toscano@tiscali.it>, 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 <luigi.toscano@tiscali.it>\n"
+"Language-Team: Italian <kde-i18n-it@kde.org>\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 (file)
index 0000000..9417f51
--- /dev/null
@@ -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 <kde-jp@kde.org>\n"
+"Language-Team: Japanese <kde-jp@kde.org>\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 (file)
index 0000000..a1bcbcc
--- /dev/null
@@ -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 <EMAIL@ADDRESS>, 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 <temuri.doghonadze@gmail.com>\n"
+"Language-Team: Georgian <kde-i18n-doc@kde.org>\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 (file)
index 0000000..b9c096e
--- /dev/null
@@ -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 <kde@peremen.name>, 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 <kde@peremen.name>\n"
+"Language-Team: Korean <kde-kr@kde.org>\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 (file)
index 0000000..d579a50
--- /dev/null
@@ -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 (file)
index 0000000..8a7e095
--- /dev/null
@@ -0,0 +1,158 @@
+# Translation of libkdav to Norwegian Bokmål
+#
+# Bjørn Steensrud <bjornst@skogkatt.homelinux.org>, 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 <bjornst@skogkatt.homelinux.org>\n"
+"Language-Team: Norwegian Bokmål <l10n-no@lister.huftis.org>\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 (file)
index 0000000..93e9745
--- /dev/null
@@ -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 <freekdekruijf@kde.nl>, 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 <freekdekruijf@kde.nl>\n"
+"Language-Team: Dutch <kde-i18n-nl@kde.org>\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 (file)
index 0000000..9b4f2f4
--- /dev/null
@@ -0,0 +1,163 @@
+# Translation of libkdav to Norwegian Nynorsk
+#
+# Karl Ove Hufthammer <karl@huftis.org>, 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 <karl@huftis.org>\n"
+"Language-Team: Norwegian Nynorsk <l10n-no@lister.huftis.org>\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 (file)
index 0000000..ac1a41d
--- /dev/null
@@ -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 <lukasz.wojnilowicz@gmail.com>, 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 <lukasz.wojnilowicz@gmail.com>\n"
+"Language-Team: Polish <kde-i18n-doc@kde.org>\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 (file)
index 0000000..18452c6
--- /dev/null
@@ -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 <zepires@gmail.com>\n"
+"Language-Team: Portuguese <kde-i18n-pt@kde.org>\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 (file)
index 0000000..8c6689e
--- /dev/null
@@ -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 <alvarenga@kde.org>, 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 <alvarenga@kde.org>\n"
+"Language-Team: Brazilian Portuguese <kde-i18n-pt_br@kde.org>\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 (file)
index 0000000..2c63467
--- /dev/null
@@ -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 <sergiu@cip.md>, 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 <sergiu@cip.md>\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 (file)
index 0000000..fb20c35
--- /dev/null
@@ -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 <aspotashev@gmail.com>, 2017.
+# Alexander Yavorsky <kekcuha@gmail.com>, 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 <kekcuha@gmail.com>\n"
+"Language-Team: Russian <kde-russian@lists.kde.ru>\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 (file)
index 0000000..a500125
--- /dev/null
@@ -0,0 +1,158 @@
+# translation of libkdav.po to Slovak
+# Roman Paholík <wizzardsk@gmail.com>, 2017.
+# Matej Mrenica <matejm98mthw@gmail.com>, 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 <matejm98mthw@gmail.com>\n"
+"Language-Team: Slovak <kde-i18n-doc@kde.org>\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 (file)
index 0000000..eae3bab
--- /dev/null
@@ -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 <matjaz.jeran@amis.net>, 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 <matjaz.jeran@amis.net>\n"
+"Language-Team: Slovenian <lugos-slo@lugos.si>\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 (file)
index 0000000..f42439d
--- /dev/null
@@ -0,0 +1,159 @@
+# Translation of libkdav.po into Serbian.
+# Chusslove Illich <caslav.ilic@gmx.net>, 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 <caslav.ilic@gmx.net>\n"
+"Language-Team: Serbian <kde-i18n-sr@kde.org>\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 (file)
index 0000000..7ee5d14
--- /dev/null
@@ -0,0 +1,159 @@
+# Translation of libkdav.po into Serbian.
+# Chusslove Illich <caslav.ilic@gmx.net>, 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 <caslav.ilic@gmx.net>\n"
+"Language-Team: Serbian <kde-i18n-sr@kde.org>\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 (file)
index 0000000..931dd52
--- /dev/null
@@ -0,0 +1,159 @@
+# Translation of libkdav.po into Serbian.
+# Chusslove Illich <caslav.ilic@gmx.net>, 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 <caslav.ilic@gmx.net>\n"
+"Language-Team: Serbian <kde-i18n-sr@kde.org>\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 (file)
index 0000000..df490d4
--- /dev/null
@@ -0,0 +1,159 @@
+# Translation of libkdav.po into Serbian.
+# Chusslove Illich <caslav.ilic@gmx.net>, 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 <caslav.ilic@gmx.net>\n"
+"Language-Team: Serbian <kde-i18n-sr@kde.org>\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 (file)
index 0000000..ae49d7c
--- /dev/null
@@ -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 <stefan.asserhall@bredband.net>, 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 <stefan.asserhall@bredband.net>\n"
+"Language-Team: Swedish <kde-i18n-doc@kde.org>\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 (file)
index 0000000..1a067f4
--- /dev/null
@@ -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 <emir_sari@icloud.com>, 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 <emir_sari@icloud.com>\n"
+"Language-Team: Turkish <kde-l10n-tr@kde.org>\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 (file)
index 0000000..4b6dd82
--- /dev/null
@@ -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 <yurchor@ukr.net>, 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 <yurchor@ukr.net>\n"
+"Language-Team: Ukrainian <kde-i18n-uk@kde.org>\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 (file)
index 0000000..6b9cb89
--- /dev/null
@@ -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 (file)
index 0000000..3b4a74e
--- /dev/null
@@ -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 <EMAIL@ADDRESS>, 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 <EMAIL@ADDRESS>\n"
+"Language-Team: Chinese <kde-i18n-doc@kde.org>\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 (file)
index 0000000..2f01108
--- /dev/null
@@ -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 "$<INSTALL_INTERFACE:${KDAV_INSTALL_INCLUDEDIR}>")
+
+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 (file)
index 0000000..ee93862
--- /dev/null
@@ -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 (file)
index 0000000..80a460d
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+    SPDX-FileCopyrightText: 2009 Grégory Oestreicher <greg@kamago.net>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "davcollection.h"
+
+#include "davurl.h"
+
+#include <QColor>
+
+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 (file)
index 0000000..2346fd5
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+    SPDX-FileCopyrightText: 2009 Grégory Oestreicher <greg@kamago.net>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#ifndef KDAV_DAVCOLLECTION_H
+#define KDAV_DAVCOLLECTION_H
+
+#include "kdav_export.h"
+
+#include "enums.h"
+
+#include <QSharedDataPointer>
+#include <QString>
+#include <QVector>
+
+class QColor;
+
+class DavCollectionPrivate;
+
+namespace KDAV
+{
+class DavUrl;
+}
+
+namespace KDAV
+{
+/**
+ * @class DavCollection davcollection.h <KDAV/DavCollection>
+ *
+ * @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<DavCollection> 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<DavCollectionPrivate> 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 (file)
index 0000000..a4b62ec
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+    SPDX-FileCopyrightText: 2010 Grégory Oestreicher <greg@kamago.net>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "davcollectiondeletejob.h"
+#include "davjobbase_p.h"
+
+#include "daverror.h"
+
+#include <KIO/DeleteJob>
+#include <KIO/Job>
+
+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<KIO::DeleteJob *>(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 (file)
index 0000000..70f149c
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+    SPDX-FileCopyrightText: 2010 Grégory Oestreicher <greg@kamago.net>
+
+    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 <KDAV/DavCollectionDeleteJob>
+ *
+ * @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 (file)
index 0000000..8be394c
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+    SPDX-FileCopyrightText: 2010 Grégory Oestreicher <greg@kamago.net>
+
+    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 <KIO/DavJob>
+#include <KIO/Job>
+
+using namespace KDAV;
+
+namespace KDAV
+{
+class DavCollectionModifyJobPrivate : public DavJobBasePrivate
+{
+public:
+    void davJobFinished(KJob *job);
+
+    DavUrl mUrl;
+    QDomDocument mQuery;
+
+    QVector<QDomElement> mSetProperties;
+    QVector<QDomElement> 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<KIO::DavJob *>(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 (file)
index 0000000..8ac34f7
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+    SPDX-FileCopyrightText: 2010 Grégory Oestreicher <greg@kamago.net>
+
+    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 <KDAV/DavCollectionModifyJob>
+ *
+ * @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 (file)
index 0000000..f1929e1
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+    SPDX-FileCopyrightText: 2010 Tobias Koenig <tokoe@kde.org>
+
+    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 <KIO/DavJob>
+#include <KIO/Job>
+
+#include <QBuffer>
+#include <QColor>
+
+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<DavPrincipalHomeSetsFetchJob *>(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<KIO::DavJob *>(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:
+             *
+             * <responses>
+             *   <response xmlns="DAV:">
+             *     <href xmlns="DAV:">/caldav.php/test1.user/home/</href>
+             *     <propstat xmlns="DAV:">
+             *       <prop xmlns="DAV:">
+             *         <C:supported-calendar-component-set xmlns:C="urn:ietf:params:xml:ns:caldav">
+             *           <C:comp xmlns:C="urn:ietf:params:xml:ns:caldav" name="VEVENT"/>
+             *           <C:comp xmlns:C="urn:ietf:params:xml:ns:caldav" name="VTODO"/>
+             *           <C:comp xmlns:C="urn:ietf:params:xml:ns:caldav" name="VJOURNAL"/>
+             *           <C:comp xmlns:C="urn:ietf:params:xml:ns:caldav" name="VTIMEZONE"/>
+             *           <C:comp xmlns:C="urn:ietf:params:xml:ns:caldav" name="VFREEBUSY"/>
+             *         </C:supported-calendar-component-set>
+             *         <resourcetype xmlns="DAV:">
+             *           <collection xmlns="DAV:"/>
+             *           <C:calendar xmlns:C="urn:ietf:params:xml:ns:caldav"/>
+             *           <C:schedule-calendar xmlns:C="urn:ietf:params:xml:ns:caldav"/>
+             *         </resourcetype>
+             *         <displayname xmlns="DAV:">Test1 User</displayname>
+             *         <current-user-privilege-set xmlns="DAV:">
+             *           <privilege xmlns="DAV:">
+             *             <read xmlns="DAV:"/>
+             *           </privilege>
+             *         </current-user-privilege-set>
+             *         <getctag xmlns="http://calendarserver.org/ns/">12345</getctag>
+             *       </prop>
+             *       <status xmlns="DAV:">HTTP/1.1 200 OK</status>
+             *     </propstat>
+             *   </response>
+             * </responses>
+             */
+
+            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 (file)
index 0000000..24befb8
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+    SPDX-FileCopyrightText: 2010 Tobias Koenig <tokoe@kde.org>
+
+    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 <KDAV/DavCollectionsFetchJob>
+ *
+ * @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 (file)
index 0000000..68c03ca
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+    SPDX-FileCopyrightText: 2010 Tobias Koenig <tokoe@kde.org>
+
+    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<DavCollectionsFetchJob *>(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 (file)
index 0000000..95ad4a6
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+    SPDX-FileCopyrightText: 2010 Tobias Koenig <tokoe@kde.org>
+
+    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 <KCompositeJob>
+
+#include <memory>
+
+namespace KDAV
+{
+class DavCollectionsMultiFetchJobPrivate;
+
+/**
+ * @class DavCollectionsMultiFetchJob davcollectionsmultifetchjob.h <KDAV/DavCollectionsMultiFetchJob>
+ *
+ * @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<DavCollectionsMultiFetchJobPrivate> d;
+};
+}
+
+#endif
diff --git a/src/common/daverror.cpp b/src/common/daverror.cpp
new file mode 100644 (file)
index 0000000..6a189c0
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+    SPDX-FileCopyrightText: 2016 Sandro Knauß <sknauss@kde.org>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "daverror.h"
+#include <KLocalizedString>
+
+#include <KIO/Global>
+#include <KIO/Job>
+
+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 (file)
index 0000000..ccb88da
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+    SPDX-FileCopyrightText: 2016 Sandro Knauß <sknauss@kde.org>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#ifndef KDAV_DAVERROR_H
+#define KDAV_DAVERROR_H
+
+#include "kdav_export.h"
+
+#include <KJob>
+
+#include <QSharedDataPointer>
+#include <QString>
+
+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 <KDAV/DavError>
+ *
+ * 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<ErrorPrivate> d;
+};
+}
+
+#endif
diff --git a/src/common/davitem.cpp b/src/common/davitem.cpp
new file mode 100644 (file)
index 0000000..a0fc346
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+    SPDX-FileCopyrightText: 2009 Grégory Oestreicher <greg@kamago.net>
+
+    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 (file)
index 0000000..a38171c
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+    SPDX-FileCopyrightText: 2009 Grégory Oestreicher <greg@kamago.net>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#ifndef KDAV_DAVITEM_H
+#define KDAV_DAVITEM_H
+
+#include "kdav_export.h"
+
+#include <QByteArray>
+#include <QDataStream>
+#include <QSharedDataPointer>
+#include <QString>
+#include <QVector>
+
+class DavItemPrivate;
+
+namespace KDAV
+{
+class DavUrl;
+}
+
+namespace KDAV
+{
+/**
+ * @class DavItem davitem.h <KDAV/DavItem>
+ *
+ * @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<DavItem> 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<DavItemPrivate> 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 (file)
index 0000000..7279142
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+    SPDX-FileCopyrightText: 2010 Tobias Koenig <tokoe@kde.org>
+
+    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 <KIO/DavJob>
+#include <KIO/Job>
+
+#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<KIO::StoredTransferJob *>(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<DavItemFetchJob *>(job);
+        mItem.setEtag(fetchJob->item().etag());
+    }
+    emitResult();
+}
diff --git a/src/common/davitemcreatejob.h b/src/common/davitemcreatejob.h
new file mode 100644 (file)
index 0000000..fb38a5c
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+    SPDX-FileCopyrightText: 2010 Tobias Koenig <tokoe@kde.org>
+
+    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 <KDAV/DavItemCreateJob>
+ *
+ * @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 (file)
index 0000000..63d6107
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+    SPDX-FileCopyrightText: 2010 Tobias Koenig <tokoe@kde.org>
+
+    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 <KIO/DeleteJob>
+#include <KIO/Job>
+
+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<KIO::DeleteJob *>(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<DavItemFetchJob *>(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 (file)
index 0000000..e24a1d3
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+    SPDX-FileCopyrightText: 2010 Tobias Koenig <tokoe@kde.org>
+
+    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 <KDAV/DavItemDeleteJob>
+ *
+ * @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 (file)
index 0000000..2954c61
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+    SPDX-FileCopyrightText: 2010 Tobias Koenig <tokoe@kde.org>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "davitemfetchjob.h"
+#include "davjobbase_p.h"
+
+#include "daverror.h"
+#include "davmanager_p.h"
+
+#include <KIO/DavJob>
+#include <KIO/Job>
+
+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<KIO::StoredTransferJob *>(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 (file)
index 0000000..a545149
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+    SPDX-FileCopyrightText: 2010 Tobias Koenig <tokoe@kde.org>
+
+    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 <KDAV/DavItemFetchJob>
+ *
+ * @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 (file)
index 0000000..81df8fb
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+    SPDX-FileCopyrightText: 2010 Tobias Koenig <tokoe@kde.org>
+
+    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 <KIO/Job>
+
+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<KIO::StoredTransferJob *>(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<DavItemFetchJob *>(job);
+        mItem.setEtag(fetchJob->item().etag());
+    } else {
+        mItem.setEtag(QString());
+    }
+    emitResult();
+}
+
+void DavItemModifyJobPrivate::conflictingItemFetched(KJob *job)
+{
+    DavItemFetchJob *fetchJob = qobject_cast<DavItemFetchJob *>(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 (file)
index 0000000..911f25e
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+    SPDX-FileCopyrightText: 2010 Tobias Koenig <tokoe@kde.org>
+
+    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 <KDAV/DavItemModifyJob>
+ *
+ * @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 (file)
index 0000000..93cf9e4
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+    SPDX-FileCopyrightText: 2010 Grégory Oestreicher <greg@kamago.net>
+
+    Based on DavItemsListJob:
+    SPDX-FileCopyrightText: 2010 Tobias Koenig <tokoe@kde.org>
+
+    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 <KIO/DavJob>
+#include <KIO/Job>
+
+using namespace KDAV;
+
+namespace KDAV
+{
+class DavItemsFetchJobPrivate : public DavJobBasePrivate
+{
+public:
+    void davJobFinished(KJob *job);
+
+    DavUrl mCollectionUrl;
+    QStringList mUrls;
+    QMap<QString, DavItem> 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<const DavMultigetProtocol *>(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<KIO::DavJob *>(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<const DavMultigetProtocol *>(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 (file)
index 0000000..f08dd97
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+    SPDX-FileCopyrightText: 2010 Grégory Oestreicher <greg@kamago.net>
+
+    Based on DavItemsListJob:
+    SPDX-FileCopyrightText: 2010 Tobias Koenig <tokoe@kde.org>
+
+    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 <QStringList>
+
+namespace KDAV
+{
+class DavItemsFetchJobPrivate;
+
+/**
+ * @class DavItemsFetchJob davitemsfetchjob.h <KDAV/DavItemsFetchJob>
+ *
+ * @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 (file)
index 0000000..702374f
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+    SPDX-FileCopyrightText: 2010 Tobias Koenig <tokoe@kde.org>
+
+    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 <KIO/DavJob>
+#include <KIO/Job>
+
+#include <set>
+
+using namespace KDAV;
+
+namespace KDAV
+{
+class DavItemsListJobPrivate : public DavJobBasePrivate
+{
+public:
+    void davJobFinished(KJob *job);
+
+    DavUrl mUrl;
+    std::shared_ptr<EtagCache> mEtagCache;
+    QStringList mMimeTypes;
+    QString mRangeStart;
+    QString mRangeEnd;
+    DavItem::List mItems;
+    std::set<QString> 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<EtagCache> &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<KIO::DavJob *>(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:
+         *
+         * <multistatus xmlns="DAV:">
+         *   <response xmlns="DAV:">
+         *     <href xmlns="DAV:">/caldav.php/test1.user/home/KOrganizer-166749289.780.ics</href>
+         *     <propstat xmlns="DAV:">
+         *       <prop xmlns="DAV:">
+         *         <getetag xmlns="DAV:">"b4bbea0278f4f63854c4167a7656024a"</getetag>
+         *       </prop>
+         *       <status xmlns="DAV:">HTTP/1.1 200 OK</status>
+         *     </propstat>
+         *   </response>
+         *   <response xmlns="DAV:">
+         *     <href xmlns="DAV:">/caldav.php/test1.user/home/KOrganizer-399416366.464.ics</href>
+         *     <propstat xmlns="DAV:">
+         *       <prop xmlns="DAV:">
+         *         <getetag xmlns="DAV:">"52eb129018398a7da4f435b2bc4c6cd5"</getetag>
+         *       </prop>
+         *       <status xmlns="DAV:">HTTP/1.1 200 OK</status>
+         *     </propstat>
+         *   </response>
+         * </multistatus>
+         */
+
+        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 (file)
index 0000000..d326f4f
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+    SPDX-FileCopyrightText: 2010 Tobias Koenig <tokoe@kde.org>
+
+    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 <memory>
+
+#include <QStringList>
+
+namespace KDAV
+{
+class EtagCache;
+class DavUrl;
+class DavItemsListJobPrivate;
+
+/**
+ * @class DavItemsListJob davitemslistjob.h <KDAV/DavItemsListJob>
+ *
+ * @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<EtagCache> &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 (file)
index 0000000..ab1c28d
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+    SPDX-FileCopyrightText: 2014 Gregory Oestreicher <greg@kamago.net>
+
+    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<KDAV::ErrorNumber>(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 (file)
index 0000000..1a4d9fc
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+    SPDX-FileCopyrightText: 2014 Gregory Oestreicher <greg@kamago.net>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#ifndef KDAV_DAVJOBBASE_H
+#define KDAV_DAVJOBBASE_H
+
+#include "kdav_export.h"
+
+#include <KJob>
+
+#include <memory>
+
+namespace KDAV
+{
+class DavJobBasePrivate;
+class Error;
+
+/**
+ * @class DavJobBase davjobbase.h <KDAV/DavJobBase>
+ *
+ * @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<DavJobBasePrivate> 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 (file)
index 0000000..bba4427
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+    SPDX-FileCopyrightText: 2014 Gregory Oestreicher <greg@kamago.net>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#ifndef KDAV_DAVJOBBASE_P_H
+#define KDAV_DAVJOBBASE_P_H
+
+#include <QString>
+
+#include <memory>
+
+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 (file)
index 0000000..f28a770
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+    SPDX-FileCopyrightText: 2010 Tobias Koenig <tokoe@kde.org>
+
+    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 <KIO/DavJob>
+
+#include "libkdav_debug.h"
+
+#include <QUrl>
+
+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<int>(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 (file)
index 0000000..4951001
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+    SPDX-FileCopyrightText: 2010 Tobias Koenig <tokoe@kde.org>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#ifndef KDAV_DAVMANAGER_P_H
+#define KDAV_DAVMANAGER_P_H
+
+#include "enums.h"
+
+#include <QString>
+
+#include <memory>
+
+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<DavProtocolBase> mProtocols[3];
+};
+}
+
+#endif
diff --git a/src/common/davmultigetprotocol.cpp b/src/common/davmultigetprotocol.cpp
new file mode 100644 (file)
index 0000000..3323a37
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+    SPDX-FileCopyrightText: 2010 Grégory Oestreicher <greg@kamago.net>
+
+    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 (file)
index 0000000..78d9113
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+    SPDX-FileCopyrightText: 2010 Grégory Oestreicher <greg@kamago.net>
+
+    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 (file)
index 0000000..3530a3b
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+    SPDX-FileCopyrightText: 2010 Grégory Oestreicher <greg@kamago.net>
+
+    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 <KIO/DavJob>
+#include <KIO/Job>
+
+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<KIO::DavJob *>(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) :
+     *
+     * <D:multistatus xmlns:D="DAV:">
+     *  <D:response xmlns:D="DAV:">
+     *   <D:href xmlns:D="DAV:">/dav/</D:href>
+     *   <D:propstat xmlns:D="DAV:">
+     *    <D:status xmlns:D="DAV:">HTTP/1.1 200 OK</D:status>
+     *    <D:prop xmlns:D="DAV:">
+     *     <D:current-user-principal xmlns:D="DAV:">
+     *      <D:href xmlns:D="DAV:">/principals/users/gdacoin/</D:href>
+     *     </D:current-user-principal>
+     *    </D:prop>
+     *   </D:propstat>
+     *   <D:propstat xmlns:D="DAV:">
+     *    <D:status xmlns:D="DAV:">HTTP/1.1 404 Not Found</D:status>
+     *    <D:prop xmlns:D="DAV:">
+     *     <principal-URL xmlns="DAV:"/>
+     *     <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav"/>
+     *    </D:prop>
+     *   </D:propstat>
+     *  </D:response>
+     * </D:multistatus>
+     *
+     * Or like this (if the homeset is defined):
+     *
+     *  <?xml version="1.0" encoding="utf-8" ?>
+     *  <multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
+     *    <response>
+     *      <href>/principals/users/greg%40kamago.net/</href>
+     *      <propstat>
+     *        <prop>
+     *          <C:calendar-home-set>
+     *            <href>/greg%40kamago.net/</href>
+     *          </C:calendar-home-set>
+     *        </prop>
+     *        <status>HTTP/1.1 200 OK</status>
+     *      </propstat>
+     *    </response>
+     *  </multistatus>
+     */
+
+    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 (file)
index 0000000..46de971
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+    SPDX-FileCopyrightText: 2010 Grégory Oestreicher <greg@kamago.net>
+
+    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 <QStringList>
+
+namespace KDAV
+{
+class DavPrincipalHomeSetsFetchJobPrivate;
+
+/**
+ * @class DavPrincipalHomeSetsFetchJob davprincipalhomesetsfetchjob.h <KDAV/DavPrincipalHomeSetsFetchJob>
+ *
+ * @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 (file)
index 0000000..45708bd
--- /dev/null
@@ -0,0 +1,386 @@
+/*
+    SPDX-FileCopyrightText: 2011 Grégory Oestreicher <greg@kamago.net>
+
+    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 <KIO/DavJob>
+#include <KIO/Job>
+
+#include <QUrl>
+
+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<PropertyInfo> mFetchProperties;
+    QVector<DavPrincipalSearchJob::Result> 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:
+     * <?xml version="1.0" encoding="utf-8" ?>
+     * <D:propfind xmlns:D="DAV:">
+     *   <D:prop>
+     *     <D:principal-collection-set/>
+     *   </D:prop>
+     * </D:propfind>
+     */
+    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<KIO::DavJob *>(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:
+     *
+     * <?xml version="1.0" encoding="utf-8" ?>
+     * <D:multistatus xmlns:D="DAV:">
+     *   <D:response>
+     *     <D:href>http://www.example.com/papers/</D:href>
+     *     <D:propstat>
+     *       <D:prop>
+     *         <D:principal-collection-set>
+     *           <D:href>http://www.example.com/acl/users/</D:href>
+     *           <D:href>http://www.example.com/acl/groups/</D:href>
+     *         </D:principal-collection-set>
+     *       </D:prop>
+     *       <D:status>HTTP/1.1 200 OK</D:status>
+     *     </D:propstat>
+     *   </D:response>
+     * </D:multistatus>
+     */
+
+    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<KIO::DavJob *>(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:
+     * <?xml version="1.0" encoding="utf-8" ?>
+     * <D:multistatus xmlns:D="DAV:" xmlns:B="http://BigCorp.com/ns/">
+     *   <D:response>
+     *     <D:href>http://www.example.com/users/jdoe</D:href>
+     *     <D:propstat>
+     *       <D:prop>
+     *         <D:displayname>John Doe</D:displayname>
+     *       </D:prop>
+     *       <D:status>HTTP/1.1 200 OK</D:status>
+     *     </D:propstat>
+     * </D:multistatus>
+     */
+
+    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::Result> 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:
+     *
+     *  <?xml version="1.0" encoding="utf-8" ?>
+     *  <D:principal-property-search xmlns:D="DAV:">
+     *    <D:property-search>
+     *      <D:prop>
+     *        <D:displayname/>
+     *      </D:prop>
+     *      <D:match>FILTER</D:match>
+     *    </D:property-search>
+     *    <D:prop>
+     *      XXX
+     *    </D:prop>
+     *  </D:principal-property-search>
+     */
+
+    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 (file)
index 0000000..59e20a1
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+    SPDX-FileCopyrightText: 2011 Grégory Oestreicher <greg@kamago.net>
+
+    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 <QString>
+
+namespace KDAV
+{
+class DavPrincipalSearchJobPrivate;
+
+/**
+ * @class DavPrincipalSearchJob davprincipalsearchjob.h <KDAV/DavPrincipalSearchJob>
+ *
+ * @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<Result> 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 (file)
index 0000000..d2e868f
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+    SPDX-FileCopyrightText: 2009 Grégory Oestreicher <greg@kamago.net>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "davprotocolbase_p.h"
+
+#include <QVariant>
+
+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 (file)
index 0000000..a0ebb0d
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+    SPDX-FileCopyrightText: 2009 Grégory Oestreicher <greg@kamago.net>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#ifndef KDAV_DAVPROTOCOLBASE_H
+#define KDAV_DAVPROTOCOLBASE_H
+
+#include "kdav_export.h"
+
+#include "davcollection.h"
+
+#include <QDomDocument>
+#include <QMap>
+#include <QVariant>
+#include <memory>
+
+namespace KDAV
+{
+/**
+ * @short Base class for XML query builders
+ */
+class XMLQueryBuilder
+{
+public:
+    typedef std::shared_ptr<XMLQueryBuilder> 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<QString, QVariant> 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 <prop> 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<XMLQueryBuilder::Ptr> 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 (file)
index 0000000..1a76699
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+    SPDX-FileCopyrightText: 2010 Tobias Koenig <tokoe@kde.org>
+
+    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<Protocol>(p.toInt()));
+
+    return stream;
+}
diff --git a/src/common/davurl.h b/src/common/davurl.h
new file mode 100644 (file)
index 0000000..1221397
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+    SPDX-FileCopyrightText: 2010 Tobias Koenig <tokoe@kde.org>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#ifndef KDAV_DAVURL_H
+#define KDAV_DAVURL_H
+
+#include "kdav_export.h"
+
+#include "enums.h"
+
+#include <QSharedDataPointer>
+#include <QUrl>
+#include <QVector>
+
+namespace KDAV
+{
+class DavUrlPrivate;
+/**
+ * @class DavUrl davurl.h <KDAV/DavUrl>
+ *
+ * @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<DavUrl> 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<DavUrlPrivate> 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 (file)
index 0000000..ea16c7e
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+    SPDX-FileCopyrightText: 2010 Tobias Koenig <tokoe@kde.org>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#ifndef KDAV_ENUMS_H
+#define KDAV_ENUMS_H
+
+#include <QFlags>
+
+/**
+ * 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 (file)
index 0000000..10d2784
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+    SPDX-FileCopyrightText: 2010 Grégory Oestreicher <greg@kamago.net>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "etagcache.h"
+
+#include <QMap>
+#include <QSet>
+
+using namespace KDAV;
+
+namespace KDAV
+{
+class EtagCachePrivate
+{
+public:
+    QMap<QString, QString> mCache;
+    QSet<QString> 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<QString, QString> 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 (file)
index 0000000..8c6fb5a
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+    SPDX-FileCopyrightText: 2010 Grégory Oestreicher <greg@kamago.net>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#ifndef KDAV_ETAGCACHE_H
+#define KDAV_ETAGCACHE_H
+
+#include "kdav_export.h"
+
+#include <QObject>
+#include <QStringList>
+
+#include <memory>
+
+namespace KDAV
+{
+class EtagCachePrivate;
+
+/**
+ * @class EtagCache etagcache.h <KDAV/EtagCache>
+ *
+ * @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<EtagCachePrivate> 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<QString, QString> etagCacheMap() const;
+};
+}
+
+#endif
diff --git a/src/common/protocolinfo.cpp b/src/common/protocolinfo.cpp
new file mode 100644 (file)
index 0000000..c31c686
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+    SPDX-FileCopyrightText: 2010 Tobias Koenig <tokoe@kde.org>
+
+    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 (file)
index 0000000..e558af0
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+    SPDX-FileCopyrightText: 2019 Volker Krause <vkrause@kde.org>
+
+    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 (file)
index 0000000..218b773
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+    SPDX-FileCopyrightText: 2010 Tobias Koenig <tokoe@kde.org>
+
+    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 <QString>
+
+#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 (file)
index 0000000..9ec7f9e
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+    SPDX-FileCopyrightText: 2010 Tobias Koenig <tokoe@kde.org>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#ifndef KDAV_DAVUTILS_P_H
+#define KDAV_DAVUTILS_P_H
+
+#include "enums.h"
+
+#include <QDomElement>
+
+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 <privilege/> tags are expected to be first level children of @p element.
+ */
+Q_REQUIRED_RESULT Privileges extractPrivileges(const QDomElement &element);
+
+/**
+ * Parses a single <privilege/> 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 (file)
index 0000000..d1118ea
--- /dev/null
@@ -0,0 +1,408 @@
+/*
+    SPDX-FileCopyrightText: 2009 Grégory Oestreicher <greg@kamago.net>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "caldavprotocol_p.h"
+#include "common/utils_p.h"
+
+#include <QDomDocument>
+#include <QStringList>
+#include <QUrl>
+
+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<XMLQueryBuilder::Ptr> CaldavProtocol::itemsQueries() const
+{
+    QVector<XMLQueryBuilder::Ptr> 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
+     *   <propstat xmlns="DAV:">
+     *     <prop xmlns="DAV:">
+     *       <C:supported-calendar-component-set xmlns:C="urn:ietf:params:xml:ns:caldav">
+     *         <C:comp xmlns:C="urn:ietf:params:xml:ns:caldav" name="VEVENT"/>
+     *         <C:comp xmlns:C="urn:ietf:params:xml:ns:caldav" name="VTODO"/>
+     *         <C:comp xmlns:C="urn:ietf:params:xml:ns:caldav" name="VJOURNAL"/>
+     *         <C:comp xmlns:C="urn:ietf:params:xml:ns:caldav" name="VTIMEZONE"/>
+     *         <C:comp xmlns:C="urn:ietf:params:xml:ns:caldav" name="VFREEBUSY"/>
+     *       </C:supported-calendar-component-set>
+     *       <resourcetype xmlns="DAV:">
+     *         <collection xmlns="DAV:"/>
+     *         <C:calendar xmlns:C="urn:ietf:params:xml:ns:caldav"/>
+     *         <C:schedule-calendar xmlns:C="urn:ietf:params:xml:ns:caldav"/>
+     *       </resourcetype>
+     *       <displayname xmlns="DAV:">Test1 User</displayname>
+     *     </prop>
+     *     <status xmlns="DAV:">HTTP/1.1 200 OK</status>
+     *   </propstat>
+     */
+
+    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 (file)
index 0000000..7b83acb
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+    SPDX-FileCopyrightText: 2009 Grégory Oestreicher <greg@kamago.net>
+
+    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<KDAV::XMLQueryBuilder::Ptr> 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 (file)
index 0000000..d0519f1
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+    SPDX-FileCopyrightText: 2010 Tobias Koenig <tokoe@kde.org>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "carddavprotocol_p.h"
+
+#include <QDomDocument>
+#include <QStringList>
+#include <QUrl>
+
+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<XMLQueryBuilder::Ptr> CarddavProtocol::itemsQueries() const
+{
+    QVector<XMLQueryBuilder::Ptr> 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 (file)
index 0000000..b51da62
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+    SPDX-FileCopyrightText: 2010 Tobias Koenig <tokoe@kde.org>
+
+    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<KDAV::XMLQueryBuilder::Ptr> 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 (file)
index 0000000..5849ebe
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+    SPDX-FileCopyrightText: 2009 Grégory Oestreicher <greg@kamago.net>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "groupdavprotocol_p.h"
+
+#include "common/utils_p.h"
+
+#include <QDomDocument>
+
+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<XMLQueryBuilder::Ptr> GroupdavProtocol::itemsQueries() const
+{
+    QVector<XMLQueryBuilder::Ptr> 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
+     *
+     *  <propstat>
+     *    <status>HTTP/1.1 200 OK</status>
+     *    <prop>
+     *      <displayname>Tasks</displayname>
+     *      <resourcetype>
+     *        <collection/>
+     *        <G:vtodo-collection xmlns:G="http://groupdav.org/"/>
+     *      </resourcetype>
+     *      <getlastmodified>Sat, 30 Jan 2010 17:52:41 -0100</getlastmodified>
+     *    </prop>
+     *  </propstat>
+     */
+
+    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 (file)
index 0000000..dc49e65
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+    SPDX-FileCopyrightText: 2009 Grégory Oestreicher <greg@kamago.net>
+
+    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<KDAV::XMLQueryBuilder::Ptr> 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 (file)
index 0000000..b232eee
--- /dev/null
@@ -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 (file)
index 0000000..bac0135
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+    SPDX-FileCopyrightText: 2016 Sandro Knauß <sknauss@kde.org>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include <KDAV/DavCollectionDeleteJob>
+#include <KDAV/DavCollectionModifyJob>
+#include <KDAV/DavCollectionsFetchJob>
+#include <KDAV/DavItemCreateJob>
+#include <KDAV/DavItemDeleteJob>
+#include <KDAV/DavItemFetchJob>
+#include <KDAV/DavItemModifyJob>
+#include <KDAV/DavItemsFetchJob>
+#include <KDAV/DavItemsListJob>
+#include <KDAV/EtagCache>
+
+#include <QCoreApplication>
+#include <QDebug>
+#include <QStringList>
+
+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<KDAV::EtagCache> 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();
+        }
+    }
+}