Import kdav_18.08.3.orig.tar.xz
authorSandro Knauß <hefee@debian.org>
Mon, 4 Feb 2019 14:58:32 +0000 (14:58 +0000)
committerSandro Knauß <hefee@debian.org>
Mon, 4 Feb 2019 14:58:32 +0000 (14:58 +0000)
[dgit import orig kdav_18.08.3.orig.tar.xz]

102 files changed:
.arcconfig [new file with mode: 0644]
.gitignore [new file with mode: 0644]
CMakeLists.txt [new file with mode: 0644]
COPYING [new file with mode: 0644]
KPimKDAVConfig.cmake.in [new file with mode: 0644]
README [new file with mode: 0644]
autotests/CMakeLists.txt [new file with mode: 0644]
autotests/data/dataitemfetchjob.txt [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]
kdav.categories [new file with mode: 0644]
metainfo.yaml [new file with mode: 0644]
po/ar/libkdav.po [new file with mode: 0644]
po/ast/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/en_GB/libkdav.po [new file with mode: 0644]
po/es/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/it/libkdav.po [new file with mode: 0644]
po/ja/libkdav.po [new file with mode: 0644]
po/ko/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/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/ru/libkdav.po [new file with mode: 0644]
po/sk/libkdav.po [new file with mode: 0644]
po/sr/libkdav.po [new file with mode: 0644]
po/sv/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]
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/davmanager.cpp [new file with mode: 0644]
src/common/davmanager.h [new file with mode: 0644]
src/common/davmultigetprotocol.cpp [new file with mode: 0644]
src/common/davmultigetprotocol.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.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/utils.cpp [new file with mode: 0644]
src/common/utils.h [new file with mode: 0644]
src/protocols/caldavprotocol.cpp [new file with mode: 0644]
src/protocols/caldavprotocol.h [new file with mode: 0644]
src/protocols/carddavprotocol.cpp [new file with mode: 0644]
src/protocols/carddavprotocol.h [new file with mode: 0644]
src/protocols/groupdavprotocol.cpp [new file with mode: 0644]
src/protocols/groupdavprotocol.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/.arcconfig b/.arcconfig
new file mode 100644 (file)
index 0000000..3ff2b47
--- /dev/null
@@ -0,0 +1,3 @@
+{
+  "phabricator.uri": "https://phabricator.kde.org/project/profile/34/"
+}
diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..d1af1f3
--- /dev/null
@@ -0,0 +1,4 @@
+# Ignore the following files
+/build/
+CMakeLists.txt.user*
+*.unc-backup*
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..2380cb8
--- /dev/null
@@ -0,0 +1,82 @@
+cmake_minimum_required(VERSION 3.0)
+set(PIM_VERSION "5.9.3")
+
+project(libkdav VERSION ${PIM_VERSION})
+
+set(LIBKDAV_VERSION ${PIM_VERSION})
+
+set(KF5_VERSION "5.47.0")
+
+find_package(ECM ${KF5_VERSION} CONFIG REQUIRED)
+set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH})
+
+include(CMakeFindDependencyMacro)
+include(ECMSetupVersion)
+include(GenerateExportHeader)
+include(ECMGenerateHeaders)
+include(ECMGeneratePriFile)
+include(FeatureSummary)
+include(KDEInstallDirs)
+include(KDECMakeSettings)
+include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE)
+include(ECMAddTests)
+include(ECMInstallIcons)
+include(ECMQtDeclareLoggingCategory)
+include(ECMCoverageOption)
+
+set(QT_REQUIRED_VERSION "5.9.0")
+
+find_package(Qt5 ${QT_REQUIRED_VERSION} CONFIG REQUIRED Core Gui XmlPatterns Test)
+
+find_package(KF5 ${KF5_VERSION} REQUIRED CoreAddons KIO I18n)
+
+# setup lib
+
+add_definitions(-DQT_NO_CAST_FROM_ASCII)
+add_definitions(-DQT_NO_CAST_TO_ASCII)
+add_definitions(-DQT_NO_URL_CAST_FROM_STRING)
+add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x060000)
+add_definitions(-DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT)
+
+
+ecm_setup_version(${LIBKDAV_VERSION} VARIABLE_PREFIX KDAV
+    VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kpimkdav_version.h"
+    PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KPimKDAVConfigVersion.cmake"
+    SOVERSION 5
+    )
+
+set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KPimKDAV")
+
+configure_package_config_file(
+    "${CMAKE_CURRENT_SOURCE_DIR}/KPimKDAVConfig.cmake.in"
+    "${CMAKE_CURRENT_BINARY_DIR}/KPimKDAVConfig.cmake"
+    INSTALL_DESTINATION  ${CMAKECONFIG_INSTALL_DIR}
+    )
+
+install(FILES
+    "${CMAKE_CURRENT_BINARY_DIR}/KPimKDAVConfig.cmake"
+    "${CMAKE_CURRENT_BINARY_DIR}/KPimKDAVConfigVersion.cmake"
+    DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
+    COMPONENT Devel
+    )
+
+install(EXPORT KPimKDAVTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" FILE KPimKDAVTargets.cmake NAMESPACE KPim::)
+
+install(FILES
+    ${CMAKE_CURRENT_BINARY_DIR}/kpimkdav_version.h
+    DESTINATION ${KDE_INSTALL_INCLUDEDIR}/KPim COMPONENT Devel
+    )
+
+install(FILES kdav.categories DESTINATION ${KDE_INSTALL_CONFDIR})
+
+add_subdirectory(src)
+if(BUILD_TESTING)
+    add_subdirectory(autotests)
+    add_subdirectory(test)
+endif()
+
+feature_summary(WHAT ALL
+                INCLUDE_QUIET_PACKAGES
+                FATAL_ON_MISSING_REQUIRED_PACKAGES
+)
+ki18n_install(po)
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..dcfa4c2
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  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 Library 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.
+
+                   GNU GENERAL PUBLIC LICENSE
+   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 a brief idea of what it does.>
+    Copyright (C) <year>  <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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 Library General
+Public License instead of this License.
diff --git a/KPimKDAVConfig.cmake.in b/KPimKDAVConfig.cmake.in
new file mode 100644 (file)
index 0000000..465c247
--- /dev/null
@@ -0,0 +1,6 @@
+@PACKAGE_INIT@
+
+include(CMakeFindDependencyMacro)
+find_dependency(KF5CoreAddons "@KF5_VERSION@")
+
+include("${CMAKE_CURRENT_LIST_DIR}/KPimKDAVTargets.cmake")
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..6d224ca
--- /dev/null
+++ b/README
@@ -0,0 +1,50 @@
+==== What's this ? ====
+
+This is an DAV protocol implemention 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.
diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..20106c1
--- /dev/null
@@ -0,0 +1,32 @@
+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 KPim::KDAV Qt5::Test Qt5::Core Qt5::Gui
+)
+
+ecm_add_test(davitemtest.cpp
+    TEST_NAME davitem
+    NAME_PREFIX "kdav-"
+    LINK_LIBRARIES KPim::KDAV Qt5::Test Qt5::Core
+)
+
+ecm_add_test(davurltest.cpp
+    TEST_NAME davurl
+    NAME_PREFIX "kdav-"
+    LINK_LIBRARIES KPim::KDAV Qt5::Test Qt5::Core
+)
+
+ecm_add_test(davitemfetchjobtest.cpp fakeserver.cpp
+    TEST_NAME davitemfetchjob
+    NAME_PREFIX "kdav-"
+    LINK_LIBRARIES KPim::KDAV Qt5::Test Qt5::Core Qt5::Network
+)
+
+ecm_add_test(davitemslistjobtest.cpp fakeserver.cpp
+    TEST_NAME davitemslistjob
+    NAME_PREFIX "kdav-"
+    LINK_LIBRARIES KPim::KDAV Qt5::Test Qt5::Core Qt5::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/davcollectiontest.cpp b/autotests/davcollectiontest.cpp
new file mode 100644 (file)
index 0000000..660f292
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+    Copyright (c) 2017 Sandro Knauß <sknauss@kde.org>
+
+    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.
+*/
+
+#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..caf98fb
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+    Copyright (c) 2017 Sandro Knauß <sknauss@kde.org>
+
+    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.
+*/
+
+#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..9e1c6fc
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+    Copyright (c) 2017 Sandro Knauß <sknauss@kde.org>
+
+    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.
+*/
+
+#include "davitemfetchjobtest.h"
+#include "fakeserver.h"
+
+#include <KDAV/DavItemFetchJob>
+
+#include <QTest>
+
+void DavItemFetchJobTest::runSuccessfullTest()
+{
+    FakeServer fakeServer;
+    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();
+    fakeServer.quit();
+
+    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..3b45902
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+    Copyright (c) 2017 Sandro Knauß <sknauss@kde.org>
+
+    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.
+*/
+
+#ifndef DAVITEMFETCHJOB_TEST_H
+#define DAVITEMFETCHJOB_TEST_H
+
+#include <QObject>
+
+class DavItemFetchJobTest : public QObject
+{
+    Q_OBJECT
+
+private Q_SLOTS:
+    void runSuccessfullTest();
+};
+
+#endif
diff --git a/autotests/davitemslistjobtest.cpp b/autotests/davitemslistjobtest.cpp
new file mode 100644 (file)
index 0000000..f7fa281
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+    Copyright (c) 2017 Sandro Knauß <sknauss@kde.org>
+
+    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.
+*/
+
+#include "davitemslistjobtest.h"
+#include "fakeserver.h"
+
+#include <KDAV/DavItemsListJob>
+#include <KDAV/DavUrl>
+#include <KDAV/EtagCache>
+#include <KDAV/DavError>
+
+#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..b4c514f
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+    Copyright (c) 2017 Sandro Knauß <sknauss@kde.org>
+
+    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.
+*/
+
+#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..7fdb518
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+    Copyright (c) 2017 Sandro Knauß <sknauss@kde.org>
+
+    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.
+*/
+
+#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, 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..9c63dcb
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+    Copyright (c) 2017 Sandro Knauß <sknauss@kde.org>
+
+    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.
+*/
+
+#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..4c6dffd
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+    Copyright (c) 2017 Sandro Knauß <sknauss@kde.org>
+
+    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.
+*/
+
+#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, 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..163b7b5
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+    Copyright (c) 2017 Sandro Knauß <sknauss@kde.org>
+
+    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.
+*/
+
+#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..670c9fd
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+   Copyright (C) 2008 Omat Holding B.V. <info@omat.nl>
+
+   Copyright (C) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
+   Author: Kevin Ottens <kevin@kdab.com>
+
+   Copyright (C) 2017 Sandro Kanuß <knauss@kde.org>
+
+   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.
+*/
+
+// Own
+#include "fakeserver.h"
+
+// Qt
+#include <QDebug>
+#include <QTcpServer>
+
+#include <QDebug>
+#include <QFile>
+#include <qtest.h>
+
+FakeServer::FakeServer(QObject *parent) 
+    : QThread(parent)
+    , m_port(5989)
+{
+    moveToThread(this);
+}
+
+FakeServer::~FakeServer()
+{
+    quit();
+    wait();
+}
+
+void FakeServer::startAndWait()
+{
+    start();
+    // this will block until the event queue starts
+#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
+    QMetaObject::invokeMethod(this, &FakeServer::started, Qt::BlockingQueuedConnection);
+#else
+    QMetaObject::invokeMethod(this, "started", Qt::BlockingQueuedConnection);
+#endif
+
+}
+
+void FakeServer::dataAvailable()
+{
+    QMutexLocker locker(&m_mutex);
+
+    QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender());
+    Q_ASSERT(socket != nullptr);
+
+    int scenarioNumber = m_clientSockets.indexOf(socket);
+
+    readClientPart(scenarioNumber);
+    writeServerPart(scenarioNumber);
+}
+
+void FakeServer::newConnection()
+{
+    QMutexLocker locker(&m_mutex);
+
+    m_clientSockets << m_tcpServer->nextPendingConnection();
+    connect(m_clientSockets.last(), &QTcpSocket::readyRead, this, &FakeServer::dataAvailable);
+}
+
+void FakeServer::run()
+{
+    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);
+
+    exec();
+
+    qDeleteAll(m_clientSockets);
+
+    delete m_tcpServer;
+}
+
+void FakeServer::started()
+{
+    // do nothing: this is a dummy slot used by startAndWait()
+}
+
+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(QFile::ReadOnly);
+
+    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);
+
+    foreach (const QList<QByteArray> &scenario, m_scenarios) {
+        if (!scenario.isEmpty()) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+void FakeServer::writeServerPart(int scenarioNumber)
+{
+    QList<QByteArray> scenario = m_scenarios[scenarioNumber];
+    QTcpSocket *clientSocket = m_clientSockets[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(int scenarioNumber)
+{
+    QList<QByteArray> scenario = m_scenarios[scenarioNumber];
+    QTcpSocket *socket = m_clientSockets[scenarioNumber];
+    QByteArray line = socket->readLine();
+    QVector<QByteArray> header;
+
+    while(line != "\r\n") {
+        header << line;
+        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";
+            QVERIFY(false);
+            break;
+        }
+    }
+
+    if (!scenario.isEmpty()) {
+        QVERIFY(scenario.first().startsWith("S: "));
+    }
+
+    m_scenarios[scenarioNumber] = scenario;
+}
+
+int FakeServer::port() const
+{
+    return m_port;
+}
diff --git a/autotests/fakeserver.h b/autotests/fakeserver.h
new file mode 100644 (file)
index 0000000..9235ec6
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+   Copyright (C) 2008 Omat Holding B.V. <info@omat.nl>
+
+   Copyright (C) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
+   Author: Kevin Ottens <kevin@kdab.com>
+
+   Copyright (C) 2017 Sandro Kanuß <knauss@kde.org>
+
+   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.
+*/
+
+#ifndef FAKESERVER_H
+#define FAKESERVER_H
+
+#include <QTcpSocket>
+#include <QTcpServer>
+#include <QThread>
+#include <QMutex>
+
+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 corrent 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 QThread
+{
+    Q_OBJECT
+
+public:
+    FakeServer(QObject *parent = nullptr);
+    ~FakeServer();
+
+    /**
+     * Starts the server and waits for it to be ready
+     *
+     * You should use this instead of start() to avoid race conditions.
+     */
+    void startAndWait();
+
+    /**
+     * Starts the fake server
+     *
+     * You should not call this directly.  Use start() instead.
+     *
+     * @reimp
+     */
+    void run() override;
+
+    /**
+     * 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 started();
+
+private:
+    void writeServerPart(int scenarioNumber);
+    void readClientPart(int scenarioNumber);
+
+    QList< QList<QByteArray> > m_scenarios;
+    QTcpServer *m_tcpServer;
+    mutable QMutex m_mutex;
+    QList<QTcpSocket *> m_clientSockets;
+    int m_port;
+};
+
+#endif
diff --git a/kdav.categories b/kdav.categories
new file mode 100644 (file)
index 0000000..d9cf88e
--- /dev/null
@@ -0,0 +1 @@
+org.kde.pim.kdav KDAV
diff --git a/metainfo.yaml b/metainfo.yaml
new file mode 100644 (file)
index 0000000..46f73c2
--- /dev/null
@@ -0,0 +1,17 @@
+maintainer:
+description: The KDav library 
+type: functional
+platforms:
+    - name: All
+portingAid: false
+deprecated: false
+release: false
+libraries:
+ - qmake: PimKDAV
+   cmake: "KPimKDAV"
+   cmakename: KPimKDAV
+
+public_lib: true
+group: kdepim
+platforms:
+    - name: Linux
diff --git a/po/ar/libkdav.po b/po/ar/libkdav.po
new file mode 100644 (file)
index 0000000..4dc6214
--- /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: http://bugs.kde.org\n"
+"POT-Creation-Date: 2018-04-21 03:40+0200\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:83
+#, kde-format
+msgid "Invalid username/password"
+msgstr "اسم المستخدم/كلمة السّرّ غير صالحة"
+
+#: common/daverror.cpp:85
+#, kde-format
+msgid "Access forbidden"
+msgstr "النّفاذ ممنوع"
+
+#: common/daverror.cpp:87
+#, kde-format
+msgid "Resource not found"
+msgstr "لم يُعثر على المورد"
+
+#: common/daverror.cpp:89
+#, kde-format
+msgid "HTTP error"
+msgstr "خطأ HTTP"
+
+#: common/daverror.cpp:91
+#, kde-format
+msgid ""
+"There was a problem with the request.\n"
+"%1 (%2)."
+msgstr ""
+"حدثت مشكلة بالطّلب.\n"
+"%1 (%2)."
+
+#: common/daverror.cpp:95
+#, kde-format
+msgid "Protocol for the collection does not support MULTIGET"
+msgstr "لا يدعم ميفاق التّجميعات MULTIGET"
+
+#: common/daverror.cpp:98
+#, kde-format
+msgid ""
+"The server encountered an error that prevented it from completing your "
+"request: %1 (%2)"
+msgstr "واجه الخادوم خطأً منعه من إكمال الطّلب: %1 ‏(%2)"
+
+#: common/daverror.cpp:101
+#, 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:105
+#, kde-format
+msgid "Invalid responses from backend"
+msgstr "ردود غير صالحة من السّند"
+
+#: common/daverror.cpp:108
+#, kde-format
+msgid "Error setting focus for XQuery"
+msgstr "خطأ في ضبط التّركيز على XQuery"
+
+#: common/daverror.cpp:111
+#, kde-format
+msgid "Invalid XQuery submitted by DAV implementation"
+msgstr "أرسل تنفيذ DAV استعلام XQuery غير صالح"
+
+#: common/daverror.cpp:114
+#, 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:118
+#, kde-format
+msgid "No properties to change or remove"
+msgstr "لا خصائص لتغييرها أو إزالتها"
+
+#: common/daverror.cpp:121
+#, kde-format
+msgid "There was an error when modifying the properties"
+msgstr "حدث خطأ أثناء تعديل الخصائص"
+
+#: common/daverror.cpp:123
+#, kde-format
+msgid ""
+"\n"
+"The server returned more information:\n"
+"%1"
+msgstr ""
+"\n"
+"أعاد الخادوم معلومات أكثر:\n"
+"%1"
+
+#: common/daverror.cpp:127
+#, 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:131
+#, 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:135
+#, 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:140
+#, kde-format
+msgid "There was a problem with the request."
+msgstr "حدثت مشكلة بالطّلب."
+
+#: common/daverror.cpp:144
+#, kde-format
+msgid ""
+"There was a problem with the request. The requested MIME types are not "
+"supported."
+msgstr "حدثت مشكلة بالطّلب. أنواع MIME المطلوبة غير مدعومة."
diff --git a/po/ast/libkdav.po b/po/ast/libkdav.po
new file mode 100644 (file)
index 0000000..9e1ff68
--- /dev/null
@@ -0,0 +1,142 @@
+# Copyright (C) YEAR This_file_is_part_of_KDE
+# This file is distributed under the same license as the PACKAGE package.
+#
+# enolp <enolp@softastur.org>, 2018.
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"Report-Msgid-Bugs-To: http://bugs.kde.org\n"
+"POT-Creation-Date: 2018-04-21 03:40+0200\n"
+"PO-Revision-Date: 2018-01-17 17:59+0100\n"
+"Last-Translator: enolp <enolp@softastur.org>\n"
+"Language-Team: Asturian <>\n"
+"Language: ast\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:83
+#, kde-format
+msgid "Invalid username/password"
+msgstr ""
+
+#: common/daverror.cpp:85
+#, kde-format
+msgid "Access forbidden"
+msgstr ""
+
+#: common/daverror.cpp:87
+#, kde-format
+msgid "Resource not found"
+msgstr "Nun s'alcontró'l recursu"
+
+#: common/daverror.cpp:89
+#, kde-format
+msgid "HTTP error"
+msgstr ""
+
+#: common/daverror.cpp:91
+#, kde-format
+msgid ""
+"There was a problem with the request.\n"
+"%1 (%2)."
+msgstr ""
+
+#: common/daverror.cpp:95
+#, kde-format
+msgid "Protocol for the collection does not support MULTIGET"
+msgstr ""
+
+#: common/daverror.cpp:98
+#, kde-format
+msgid ""
+"The server encountered an error that prevented it from completing your "
+"request: %1 (%2)"
+msgstr ""
+
+#: common/daverror.cpp:101
+#, 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:105
+#, kde-format
+msgid "Invalid responses from backend"
+msgstr ""
+
+#: common/daverror.cpp:108
+#, kde-format
+msgid "Error setting focus for XQuery"
+msgstr ""
+
+#: common/daverror.cpp:111
+#, kde-format
+msgid "Invalid XQuery submitted by DAV implementation"
+msgstr ""
+
+#: common/daverror.cpp:114
+#, 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:118
+#, kde-format
+msgid "No properties to change or remove"
+msgstr ""
+
+#: common/daverror.cpp:121
+#, kde-format
+msgid "There was an error when modifying the properties"
+msgstr ""
+
+#: common/daverror.cpp:123
+#, kde-format
+msgid ""
+"\n"
+"The server returned more information:\n"
+"%1"
+msgstr ""
+
+#: common/daverror.cpp:127
+#, 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:131
+#, 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:135
+#, 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:140
+#, kde-format
+msgid "There was a problem with the request."
+msgstr ""
+
+#: common/daverror.cpp:144
+#, kde-format
+msgid ""
+"There was a problem with the request. The requested MIME types are not "
+"supported."
+msgstr ""
diff --git a/po/ca/libkdav.po b/po/ca/libkdav.po
new file mode 100644 (file)
index 0000000..e488aef
--- /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 Ma. 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: libkdav\n"
+"Report-Msgid-Bugs-To: http://bugs.kde.org\n"
+"POT-Creation-Date: 2018-04-21 03:40+0200\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:83
+#, kde-format
+msgid "Invalid username/password"
+msgstr "Nom d'usuari o contrasenya no vàlids"
+
+#: common/daverror.cpp:85
+#, kde-format
+msgid "Access forbidden"
+msgstr "Accés prohibit"
+
+#: common/daverror.cpp:87
+#, kde-format
+msgid "Resource not found"
+msgstr "No s'ha trobat el recurs"
+
+#: common/daverror.cpp:89
+#, kde-format
+msgid "HTTP error"
+msgstr "Error d'HTTP"
+
+#: common/daverror.cpp:91
+#, 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:95
+#, 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:98
+#, 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:101
+#, 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:105
+#, kde-format
+msgid "Invalid responses from backend"
+msgstr "Respostes no vàlides del dorsal"
+
+#: common/daverror.cpp:108
+#, kde-format
+msgid "Error setting focus for XQuery"
+msgstr "Error en establir el focus a XQuery"
+
+#: common/daverror.cpp:111
+#, kde-format
+msgid "Invalid XQuery submitted by DAV implementation"
+msgstr "XQuery no vàlida enviada per la implementació DAV"
+
+#: common/daverror.cpp:114
+#, 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:118
+#, kde-format
+msgid "No properties to change or remove"
+msgstr "No hi ha cap propietat a canviar o eliminar"
+
+#: common/daverror.cpp:121
+#, 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:123
+#, 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:127
+#, 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:131
+#, 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:135
+#, 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:140
+#, kde-format
+msgid "There was a problem with the request."
+msgstr "S'ha produït un problema amb la sol·licitud."
+
+#: common/daverror.cpp:144
+#, 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..d6d1441
--- /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 Ma. 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: libkdav\n"
+"Report-Msgid-Bugs-To: http://bugs.kde.org\n"
+"POT-Creation-Date: 2018-04-21 03:40+0200\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:83
+#, kde-format
+msgid "Invalid username/password"
+msgstr "Nom d'usuari o contrasenya no vàlids"
+
+#: common/daverror.cpp:85
+#, kde-format
+msgid "Access forbidden"
+msgstr "Accés prohibit"
+
+#: common/daverror.cpp:87
+#, kde-format
+msgid "Resource not found"
+msgstr "No s'ha trobat el recurs"
+
+#: common/daverror.cpp:89
+#, kde-format
+msgid "HTTP error"
+msgstr "Error d'HTTP"
+
+#: common/daverror.cpp:91
+#, 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:95
+#, 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:98
+#, 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:101
+#, 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:105
+#, kde-format
+msgid "Invalid responses from backend"
+msgstr "Respostes no vàlides del dorsal"
+
+#: common/daverror.cpp:108
+#, kde-format
+msgid "Error setting focus for XQuery"
+msgstr "Error en establir el focus a XQuery"
+
+#: common/daverror.cpp:111
+#, kde-format
+msgid "Invalid XQuery submitted by DAV implementation"
+msgstr "XQuery no vàlida enviada per la implementació DAV"
+
+#: common/daverror.cpp:114
+#, 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:118
+#, kde-format
+msgid "No properties to change or remove"
+msgstr "No hi ha cap propietat a canviar o eliminar"
+
+#: common/daverror.cpp:121
+#, 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:123
+#, 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:127
+#, 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:131
+#, 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:135
+#, 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:140
+#, kde-format
+msgid "There was a problem with the request."
+msgstr "S'ha produït un problema amb la sol·licitud."
+
+#: common/daverror.cpp:144
+#, 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..8c79cd1
--- /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: http://bugs.kde.org\n"
+"POT-Creation-Date: 2018-04-21 03:40+0200\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:83
+#, kde-format
+msgid "Invalid username/password"
+msgstr "Neplatné uživatelské jméno nebo heslo"
+
+#: common/daverror.cpp:85
+#, kde-format
+msgid "Access forbidden"
+msgstr "Přístup zakázán"
+
+#: common/daverror.cpp:87
+#, kde-format
+msgid "Resource not found"
+msgstr "Zdroj nebyl nalezen"
+
+#: common/daverror.cpp:89
+#, kde-format
+msgid "HTTP error"
+msgstr "Chyba HTTP"
+
+#: common/daverror.cpp:91
+#, kde-format
+msgid ""
+"There was a problem with the request.\n"
+"%1 (%2)."
+msgstr ""
+
+#: common/daverror.cpp:95
+#, kde-format
+msgid "Protocol for the collection does not support MULTIGET"
+msgstr ""
+
+#: common/daverror.cpp:98
+#, kde-format
+msgid ""
+"The server encountered an error that prevented it from completing your "
+"request: %1 (%2)"
+msgstr ""
+
+#: common/daverror.cpp:101
+#, 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:105
+#, kde-format
+msgid "Invalid responses from backend"
+msgstr ""
+
+#: common/daverror.cpp:108
+#, kde-format
+msgid "Error setting focus for XQuery"
+msgstr ""
+
+#: common/daverror.cpp:111
+#, kde-format
+msgid "Invalid XQuery submitted by DAV implementation"
+msgstr ""
+
+#: common/daverror.cpp:114
+#, 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:118
+#, kde-format
+msgid "No properties to change or remove"
+msgstr ""
+
+#: common/daverror.cpp:121
+#, kde-format
+msgid "There was an error when modifying the properties"
+msgstr ""
+
+#: common/daverror.cpp:123
+#, kde-format
+msgid ""
+"\n"
+"The server returned more information:\n"
+"%1"
+msgstr ""
+"\n"
+"Server navrátil více informací:\n"
+"%1"
+
+#: common/daverror.cpp:127
+#, 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:131
+#, 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:135
+#, 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:140
+#, kde-format
+msgid "There was a problem with the request."
+msgstr "V požadavku nastal problém."
+
+#: common/daverror.cpp:144
+#, 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..f18eb49
--- /dev/null
@@ -0,0 +1,167 @@
+# Copyright (C) YEAR This_file_is_part_of_KDE
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Burkhard Lück <lueck@hube-lueck.de>, 2017, 2018.
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"Report-Msgid-Bugs-To: http://bugs.kde.org\n"
+"POT-Creation-Date: 2018-04-21 03:40+0200\n"
+"PO-Revision-Date: 2018-02-27 13:42+0100\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"
+"X-Generator: Lokalize 2.0\n"
+
+#: common/daverror.cpp:83
+#, kde-format
+msgid "Invalid username/password"
+msgstr "Ungültiger Benutzername/Passwort"
+
+#: common/daverror.cpp:85
+#, kde-format
+msgid "Access forbidden"
+msgstr "Zugriff unzulässig"
+
+#: common/daverror.cpp:87
+#, kde-format
+msgid "Resource not found"
+msgstr "Die Ressource wurde nicht gefunden"
+
+#: common/daverror.cpp:89
+#, kde-format
+msgid "HTTP error"
+msgstr "HTTP-Fehler"
+
+#: common/daverror.cpp:91
+#, 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:95
+#, 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:98
+#, 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:101
+#, 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:105
+#, kde-format
+msgid "Invalid responses from backend"
+msgstr "Ungültige Antwort des Treibers"
+
+#: common/daverror.cpp:108
+#, kde-format
+msgid "Error setting focus for XQuery"
+msgstr "Fehler beim Bestimmen des Fokus für XQuery"
+
+#: common/daverror.cpp:111
+#, kde-format
+msgid "Invalid XQuery submitted by DAV implementation"
+msgstr "DAV-Implementation hat ungültige XQuery übermittelt"
+
+#: common/daverror.cpp:114
+#, 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:118
+#, 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:121
+#, kde-format
+msgid "There was an error when modifying the properties"
+msgstr "Problem beim Anpassen der Eigenschaften"
+
+#: common/daverror.cpp:123
+#, 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:127
+#, 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:131
+#, 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:135
+#, 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:140
+#, kde-format
+msgid "There was a problem with the request."
+msgstr "Bei der Abfrage ist ein Problem aufgetreten"
+
+#: common/daverror.cpp:144
+#, 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 angeforderten MIME-Typen "
+"werden nicht unterstützt."
diff --git a/po/en_GB/libkdav.po b/po/en_GB/libkdav.po
new file mode 100644 (file)
index 0000000..deecf58
--- /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: http://bugs.kde.org\n"
+"POT-Creation-Date: 2018-04-21 03:40+0200\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-i18n-doc@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:83
+#, kde-format
+msgid "Invalid username/password"
+msgstr "Invalid username/password"
+
+#: common/daverror.cpp:85
+#, kde-format
+msgid "Access forbidden"
+msgstr "Access forbidden"
+
+#: common/daverror.cpp:87
+#, kde-format
+msgid "Resource not found"
+msgstr "Resource not found"
+
+#: common/daverror.cpp:89
+#, kde-format
+msgid "HTTP error"
+msgstr "HTTP error"
+
+#: common/daverror.cpp:91
+#, 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:95
+#, kde-format
+msgid "Protocol for the collection does not support MULTIGET"
+msgstr "Protocol for the collection does not support MULTIGET"
+
+#: common/daverror.cpp:98
+#, 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:101
+#, 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:105
+#, kde-format
+msgid "Invalid responses from backend"
+msgstr "Invalid responses from backend"
+
+#: common/daverror.cpp:108
+#, kde-format
+msgid "Error setting focus for XQuery"
+msgstr "Error setting focus for XQuery"
+
+#: common/daverror.cpp:111
+#, kde-format
+msgid "Invalid XQuery submitted by DAV implementation"
+msgstr "Invalid XQuery submitted by DAV implementation"
+
+#: common/daverror.cpp:114
+#, 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:118
+#, kde-format
+msgid "No properties to change or remove"
+msgstr "No properties to change or remove"
+
+#: common/daverror.cpp:121
+#, kde-format
+msgid "There was an error when modifying the properties"
+msgstr "There was an error when modifying the properties"
+
+#: common/daverror.cpp:123
+#, kde-format
+msgid ""
+"\n"
+"The server returned more information:\n"
+"%1"
+msgstr ""
+"\n"
+"The server returned more information:\n"
+"%1"
+
+#: common/daverror.cpp:127
+#, 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:131
+#, 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:135
+#, 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:140
+#, kde-format
+msgid "There was a problem with the request."
+msgstr "There was a problem with the request."
+
+#: common/daverror.cpp:144
+#, 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..bc9f7e0
--- /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: http://bugs.kde.org\n"
+"POT-Creation-Date: 2018-04-21 03:40+0200\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:83
+#, kde-format
+msgid "Invalid username/password"
+msgstr "Usuario/contraseña inválidos"
+
+#: common/daverror.cpp:85
+#, kde-format
+msgid "Access forbidden"
+msgstr "Acceso prohíbido"
+
+#: common/daverror.cpp:87
+#, kde-format
+msgid "Resource not found"
+msgstr "Recurso no encontrado"
+
+#: common/daverror.cpp:89
+#, kde-format
+msgid "HTTP error"
+msgstr "Error HTTP"
+
+#: common/daverror.cpp:91
+#, 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:95
+#, kde-format
+msgid "Protocol for the collection does not support MULTIGET"
+msgstr "El protocolo para la colección no implementa MULTIGET"
+
+#: common/daverror.cpp:98
+#, 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:101
+#, 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:105
+#, kde-format
+msgid "Invalid responses from backend"
+msgstr "Respuesta inválida desde el motor"
+
+#: common/daverror.cpp:108
+#, kde-format
+msgid "Error setting focus for XQuery"
+msgstr "Error al establecer el foco para XQuery"
+
+#: common/daverror.cpp:111
+#, kde-format
+msgid "Invalid XQuery submitted by DAV implementation"
+msgstr "XQuery inválido enviado por la implementación de DAV"
+
+#: common/daverror.cpp:114
+#, 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:118
+#, kde-format
+msgid "No properties to change or remove"
+msgstr "Ninguna propiedad que cambiar o eliminar"
+
+#: common/daverror.cpp:121
+#, kde-format
+msgid "There was an error when modifying the properties"
+msgstr "Ha habido un error al modificar las propiedades"
+
+#: common/daverror.cpp:123
+#, 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:127
+#, 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:131
+#, 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:135
+#, 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:140
+#, kde-format
+msgid "There was a problem with the request."
+msgstr "Ha habido un problema con la petición."
+
+#: common/daverror.cpp:144
+#, 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/fi/libkdav.po b/po/fi/libkdav.po
new file mode 100644 (file)
index 0000000..b80fed1
--- /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: http://bugs.kde.org\n"
+"POT-Creation-Date: 2018-04-21 03:40+0200\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:83
+#, kde-format
+msgid "Invalid username/password"
+msgstr "Virheellinen käyttäjätunnus tai salasana"
+
+#: common/daverror.cpp:85
+#, kde-format
+msgid "Access forbidden"
+msgstr "Saanti estetty"
+
+#: common/daverror.cpp:87
+#, kde-format
+msgid "Resource not found"
+msgstr "Resurssia ei löydy"
+
+#: common/daverror.cpp:89
+#, kde-format
+msgid "HTTP error"
+msgstr "HTTP-virhe"
+
+#: common/daverror.cpp:91
+#, kde-format
+msgid ""
+"There was a problem with the request.\n"
+"%1 (%2)."
+msgstr ""
+"Pyynnössä oli ongelmia.\n"
+"%1 (%2)."
+
+#: common/daverror.cpp:95
+#, kde-format
+msgid "Protocol for the collection does not support MULTIGET"
+msgstr "Kokoelman yhteyskäytäntö ei tue MULTIGETiä"
+
+#: common/daverror.cpp:98
+#, 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:101
+#, 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:105
+#, kde-format
+msgid "Invalid responses from backend"
+msgstr "Taustaosa vastaa virheellisesti"
+
+#: common/daverror.cpp:108
+#, kde-format
+msgid "Error setting focus for XQuery"
+msgstr "Virhe asetettaessa XQueryn kohdistusta"
+
+#: common/daverror.cpp:111
+#, kde-format
+msgid "Invalid XQuery submitted by DAV implementation"
+msgstr "DAV-toteutus lähetti virheellisen XQueryn"
+
+#: common/daverror.cpp:114
+#, 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:118
+#, kde-format
+msgid "No properties to change or remove"
+msgstr "Ei muutettavia tai poistettavia ominaisuuksia"
+
+#: common/daverror.cpp:121
+#, kde-format
+msgid "There was an error when modifying the properties"
+msgstr "Ominaisuuksia muutettaessa sattui virhe"
+
+#: common/daverror.cpp:123
+#, kde-format
+msgid ""
+"\n"
+"The server returned more information:\n"
+"%1"
+msgstr ""
+"\n"
+"Palvelin palautti lisätietoa:\n"
+"%1"
+
+#: common/daverror.cpp:127
+#, 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:131
+#, 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:135
+#, 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:140
+#, kde-format
+msgid "There was a problem with the request."
+msgstr "Pyynnössä oli ongelmia."
+
+#: common/daverror.cpp:144
+#, 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..a92c05f
--- /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: http://bugs.kde.org\n"
+"POT-Creation-Date: 2018-04-21 03:40+0200\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:83
+#, kde-format
+msgid "Invalid username/password"
+msgstr "Nom d'utilisateur ou mot de passe non valable"
+
+#: common/daverror.cpp:85
+#, kde-format
+msgid "Access forbidden"
+msgstr "Accès refusé"
+
+#: common/daverror.cpp:87
+#, kde-format
+msgid "Resource not found"
+msgstr "Impossible de trouver la ressource"
+
+#: common/daverror.cpp:89
+#, kde-format
+msgid "HTTP error"
+msgstr "Erreur « HTTP »"
+
+#: common/daverror.cpp:91
+#, 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:95
+#, 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:98
+#, 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:101
+#, 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:105
+#, kde-format
+msgid "Invalid responses from backend"
+msgstr "Réponses non valables provenant du moteur"
+
+#: common/daverror.cpp:108
+#, kde-format
+msgid "Error setting focus for XQuery"
+msgstr "Problème lors de la définition du focus pour « XQuery »"
+
+#: common/daverror.cpp:111
+#, kde-format
+msgid "Invalid XQuery submitted by DAV implementation"
+msgstr "« XQuery » non valable soumise par l'implémentation de DAV"
+
+#: common/daverror.cpp:114
+#, 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:118
+#, kde-format
+msgid "No properties to change or remove"
+msgstr "Aucune propriété à modifier ou supprimer"
+
+#: common/daverror.cpp:121
+#, 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:123
+#, 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:127
+#, 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:131
+#, 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:135
+#, 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:140
+#, 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:144
+#, 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..7b5f130
--- /dev/null
@@ -0,0 +1,162 @@
+# Copyright (C) YEAR This_file_is_part_of_KDE
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Adrian Chaves <adrian@chaves.io>, 2018.
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"Report-Msgid-Bugs-To: http://bugs.kde.org\n"
+"POT-Creation-Date: 2018-04-21 03:40+0200\n"
+"PO-Revision-Date: 2018-04-22 13:29+0100\n"
+"Last-Translator: Adrian Chaves <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"
+"X-Generator: Lokalize 2.0\n"
+
+#: common/daverror.cpp:83
+#, kde-format
+msgid "Invalid username/password"
+msgstr "O nome de usuario ou o contrasinal son incorrectos"
+
+#: common/daverror.cpp:85
+#, kde-format
+msgid "Access forbidden"
+msgstr "Denegouse o acceso"
+
+#: common/daverror.cpp:87
+#, kde-format
+msgid "Resource not found"
+msgstr "Non se atopou o recurso."
+
+#: common/daverror.cpp:89
+#, kde-format
+msgid "HTTP error"
+msgstr "Erro de HTTP"
+
+#: common/daverror.cpp:91
+#, 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:95
+#, kde-format
+msgid "Protocol for the collection does not support MULTIGET"
+msgstr "O protocolo da colección non admite MULTIGET"
+
+#: common/daverror.cpp:98
+#, 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:101
+#, 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:105
+#, kde-format
+msgid "Invalid responses from backend"
+msgstr "A infraestrutura remitiu respostas incorrectas"
+
+#: common/daverror.cpp:108
+#, kde-format
+msgid "Error setting focus for XQuery"
+msgstr "Produciuse un erro ao configurar o foco de XQuery"
+
+#: common/daverror.cpp:111
+#, kde-format
+msgid "Invalid XQuery submitted by DAV implementation"
+msgstr "A realización de DAV enviou unha XQuery incorrecta"
+
+#: common/daverror.cpp:114
+#, 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:118
+#, kde-format
+msgid "No properties to change or remove"
+msgstr "Non hai propiedades que cambiar ou retirar"
+
+#: common/daverror.cpp:121
+#, kde-format
+msgid "There was an error when modifying the properties"
+msgstr "Produciuse un erro ao modificar as propiedades."
+
+#: common/daverror.cpp:123
+#, 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:127
+#, 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:131
+#, 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:135
+#, 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:140
+#, kde-format
+msgid "There was a problem with the request."
+msgstr "Houbo un problema coa solicitude."
+
+#: common/daverror.cpp:144
+#, 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/it/libkdav.po b/po/it/libkdav.po
new file mode 100644 (file)
index 0000000..346a52e
--- /dev/null
@@ -0,0 +1,158 @@
+# translation of akonadi_davgroupware_resource.po to Italian
+#
+# Vincenzo Reale <smart2128@baslug.org>, 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: http://bugs.kde.org\n"
+"POT-Creation-Date: 2018-04-21 03:40+0200\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:83
+#, kde-format
+msgid "Invalid username/password"
+msgstr "Username o password non validi"
+
+#: common/daverror.cpp:85
+#, kde-format
+msgid "Access forbidden"
+msgstr "Accesso vietato"
+
+#: common/daverror.cpp:87
+#, kde-format
+msgid "Resource not found"
+msgstr "Risorsa non trovata"
+
+#: common/daverror.cpp:89
+#, kde-format
+msgid "HTTP error"
+msgstr "Errore HTTP"
+
+#: common/daverror.cpp:91
+#, kde-format
+msgid ""
+"There was a problem with the request.\n"
+"%1 (%2)."
+msgstr ""
+"Problema con la richiesta.\n"
+"%1 (%2)."
+
+#: common/daverror.cpp:95
+#, kde-format
+msgid "Protocol for the collection does not support MULTIGET"
+msgstr "Il protocollo della collezione non supporta MULTIGET"
+
+#: common/daverror.cpp:98
+#, 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:101
+#, 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:105
+#, kde-format
+msgid "Invalid responses from backend"
+msgstr "Risposta non valida dal backend"
+
+#: common/daverror.cpp:108
+#, kde-format
+msgid "Error setting focus for XQuery"
+msgstr "Errore impostando il fuoco su XQuery"
+
+#: common/daverror.cpp:111
+#, kde-format
+msgid "Invalid XQuery submitted by DAV implementation"
+msgstr "XQuery non valida inviata dall'implementazione DAV"
+
+#: common/daverror.cpp:114
+#, 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:118
+#, kde-format
+msgid "No properties to change or remove"
+msgstr "Nessuna proprietà da cambiare o rimuovere"
+
+#: common/daverror.cpp:121
+#, kde-format
+msgid "There was an error when modifying the properties"
+msgstr "Errore nella modifica delle proprietà"
+
+#: common/daverror.cpp:123
+#, kde-format
+msgid ""
+"\n"
+"The server returned more information:\n"
+"%1"
+msgstr ""
+"\n"
+"Il server ha fornito ulteriori informazioni:\n"
+"%1"
+
+#: common/daverror.cpp:127
+#, 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:131
+#, 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:135
+#, 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:140
+#, kde-format
+msgid "There was a problem with the request."
+msgstr "Problema con la richiesta."
+
+#: common/daverror.cpp:144
+#, 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..3e71dbd
--- /dev/null
@@ -0,0 +1,139 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: akonadi_davcalendar_resource\n"
+"Report-Msgid-Bugs-To: http://bugs.kde.org\n"
+"POT-Creation-Date: 2018-04-21 03:40+0200\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:83
+#, kde-format
+msgid "Invalid username/password"
+msgstr ""
+
+#: common/daverror.cpp:85
+#, kde-format
+msgid "Access forbidden"
+msgstr ""
+
+#: common/daverror.cpp:87
+#, kde-format
+msgid "Resource not found"
+msgstr ""
+
+#: common/daverror.cpp:89
+#, kde-format
+msgid "HTTP error"
+msgstr ""
+
+#: common/daverror.cpp:91
+#, kde-format
+msgid ""
+"There was a problem with the request.\n"
+"%1 (%2)."
+msgstr ""
+
+#: common/daverror.cpp:95
+#, kde-format
+msgid "Protocol for the collection does not support MULTIGET"
+msgstr ""
+
+#: common/daverror.cpp:98
+#, kde-format
+msgid ""
+"The server encountered an error that prevented it from completing your "
+"request: %1 (%2)"
+msgstr ""
+
+#: common/daverror.cpp:101
+#, 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:105
+#, kde-format
+msgid "Invalid responses from backend"
+msgstr ""
+
+#: common/daverror.cpp:108
+#, kde-format
+msgid "Error setting focus for XQuery"
+msgstr ""
+
+#: common/daverror.cpp:111
+#, kde-format
+msgid "Invalid XQuery submitted by DAV implementation"
+msgstr ""
+
+#: common/daverror.cpp:114
+#, 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:118
+#, kde-format
+msgid "No properties to change or remove"
+msgstr ""
+
+#: common/daverror.cpp:121
+#, kde-format
+msgid "There was an error when modifying the properties"
+msgstr ""
+
+#: common/daverror.cpp:123
+#, kde-format
+msgid ""
+"\n"
+"The server returned more information:\n"
+"%1"
+msgstr ""
+
+#: common/daverror.cpp:127
+#, 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:131
+#, 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:135
+#, 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:140
+#, kde-format
+msgid "There was a problem with the request."
+msgstr ""
+
+#: common/daverror.cpp:144
+#, kde-format
+msgid ""
+"There was a problem with the request. The requested MIME types are not "
+"supported."
+msgstr ""
diff --git a/po/ko/libkdav.po b/po/ko/libkdav.po
new file mode 100644 (file)
index 0000000..4c166fe
--- /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: http://bugs.kde.org\n"
+"POT-Creation-Date: 2018-04-21 03:40+0200\n"
+"PO-Revision-Date: 2018-08-15 12:26+0100\n"
+"Last-Translator: Shinjo Park <kde@peremen.name>\n"
+"Language-Team: Korean <kde-i18n-doc@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:83
+#, kde-format
+msgid "Invalid username/password"
+msgstr "잘못된 사용자 이름 및 암호"
+
+#: common/daverror.cpp:85
+#, kde-format
+msgid "Access forbidden"
+msgstr "접근 거부됨"
+
+#: common/daverror.cpp:87
+#, kde-format
+msgid "Resource not found"
+msgstr "자원을 찾을 수 없음"
+
+#: common/daverror.cpp:89
+#, kde-format
+msgid "HTTP error"
+msgstr "HTTP 오류"
+
+#: common/daverror.cpp:91
+#, kde-format
+msgid ""
+"There was a problem with the request.\n"
+"%1 (%2)."
+msgstr ""
+"요청에 문제가 있습니다.\n"
+"%1 (%2)."
+
+#: common/daverror.cpp:95
+#, kde-format
+msgid "Protocol for the collection does not support MULTIGET"
+msgstr "모음집에 대한 프로토콜이 MULTIGET을 지원하지 않음"
+
+#: common/daverror.cpp:98
+#, kde-format
+msgid ""
+"The server encountered an error that prevented it from completing your "
+"request: %1 (%2)"
+msgstr "서버에서 요청을 처리할 수 없는 오류가 발생했습니다: %1(%2)"
+
+#: common/daverror.cpp:101
+#, 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:105
+#, kde-format
+msgid "Invalid responses from backend"
+msgstr "백엔드에서 잘못된 응답이 돌아옴"
+
+#: common/daverror.cpp:108
+#, kde-format
+msgid "Error setting focus for XQuery"
+msgstr "XQuery 초점 설정 오류"
+
+#: common/daverror.cpp:111
+#, kde-format
+msgid "Invalid XQuery submitted by DAV implementation"
+msgstr "DAV 구현에서 잘못된 XQuery를 보냄"
+
+#: common/daverror.cpp:114
+#, 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:118
+#, kde-format
+msgid "No properties to change or remove"
+msgstr "변경하거나 삭제할 속성 없음"
+
+#: common/daverror.cpp:121
+#, kde-format
+msgid "There was an error when modifying the properties"
+msgstr "속성을 수정하는 중 오류가 발생함"
+
+#: common/daverror.cpp:123
+#, kde-format
+msgid ""
+"\n"
+"The server returned more information:\n"
+"%1"
+msgstr ""
+"\n"
+"서버에서 부가 정보를 돌려 줌:\n"
+"%1"
+
+#: common/daverror.cpp:127
+#, 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:131
+#, 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:135
+#, 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:140
+#, kde-format
+msgid "There was a problem with the request."
+msgstr "요청에 문제가 있습니다."
+
+#: common/daverror.cpp:144
+#, kde-format
+msgid ""
+"There was a problem with the request. The requested MIME types are not "
+"supported."
+msgstr "요청에 문제가 있습니다. 지정한 MIME 형식을 지원하지 않습니다."
diff --git a/po/nb/libkdav.po b/po/nb/libkdav.po
new file mode 100644 (file)
index 0000000..e094cb3
--- /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: http://bugs.kde.org\n"
+"POT-Creation-Date: 2018-04-21 03:40+0200\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 <i18n-nb@lister.ping.uio.no>\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:83
+#, kde-format
+msgid "Invalid username/password"
+msgstr "Ugyldig brukernavn/passord"
+
+#: common/daverror.cpp:85
+#, kde-format
+msgid "Access forbidden"
+msgstr "Adgang forbudt"
+
+#: common/daverror.cpp:87
+#, kde-format
+msgid "Resource not found"
+msgstr "Fant ikke ressurs"
+
+#: common/daverror.cpp:89
+#, kde-format
+msgid "HTTP error"
+msgstr "HTTP-feil"
+
+#: common/daverror.cpp:91
+#, 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:95
+#, kde-format
+msgid "Protocol for the collection does not support MULTIGET"
+msgstr "Protokollen for samlingen støtter ikke MULTIGET"
+
+#: common/daverror.cpp:98
+#, kde-format
+msgid ""
+"The server encountered an error that prevented it from completing your "
+"request: %1 (%2)"
+msgstr ""
+
+#: common/daverror.cpp:101
+#, 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:105
+#, kde-format
+msgid "Invalid responses from backend"
+msgstr "Ugyldige svar fra bakgrunnsmotor"
+
+#: common/daverror.cpp:108
+#, kde-format
+msgid "Error setting focus for XQuery"
+msgstr "Feil ved fokussetting for XQuery"
+
+#: common/daverror.cpp:111
+#, kde-format
+msgid "Invalid XQuery submitted by DAV implementation"
+msgstr "Ugyldig XQuery sendt inn av DAV-implementasjon"
+
+#: common/daverror.cpp:114
+#, 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:118
+#, kde-format
+msgid "No properties to change or remove"
+msgstr "Ingen egenskaper som skal endres eller fjernes"
+
+#: common/daverror.cpp:121
+#, kde-format
+msgid "There was an error when modifying the properties"
+msgstr "Det oppsto en feil ved endring av egenskapene"
+
+#: common/daverror.cpp:123
+#, kde-format
+msgid ""
+"\n"
+"The server returned more information:\n"
+"%1"
+msgstr ""
+
+#: common/daverror.cpp:127
+#, 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:131
+#, 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:135
+#, 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:140
+#, kde-format
+msgid "There was a problem with the request."
+msgstr ""
+
+#: common/daverror.cpp:144
+#, 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..6f1ac8e
--- /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: http://bugs.kde.org\n"
+"POT-Creation-Date: 2018-04-21 03:40+0200\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:83
+#, kde-format
+msgid "Invalid username/password"
+msgstr "Ongeldige gebruikersnaam/wachtwoord"
+
+#: common/daverror.cpp:85
+#, kde-format
+msgid "Access forbidden"
+msgstr "Toegang verboden"
+
+#: common/daverror.cpp:87
+#, kde-format
+msgid "Resource not found"
+msgstr "Hulpbron niet gevonden"
+
+#: common/daverror.cpp:89
+#, kde-format
+msgid "HTTP error"
+msgstr "HTTP-fout"
+
+#: common/daverror.cpp:91
+#, 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:95
+#, kde-format
+msgid "Protocol for the collection does not support MULTIGET"
+msgstr "Protocol voor de verzameling ondersteunt geen MULTIGET"
+
+#: common/daverror.cpp:98
+#, 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:101
+#, 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:105
+#, kde-format
+msgid "Invalid responses from backend"
+msgstr "Ongeldige antwoorden van backend"
+
+#: common/daverror.cpp:108
+#, kde-format
+msgid "Error setting focus for XQuery"
+msgstr "Fout bij het instellen van de focus voor XQuery"
+
+#: common/daverror.cpp:111
+#, kde-format
+msgid "Invalid XQuery submitted by DAV implementation"
+msgstr "Ongeldige Xquery ingediend door DAV-implementatie"
+
+#: common/daverror.cpp:114
+#, 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:118
+#, kde-format
+msgid "No properties to change or remove"
+msgstr "Er zijn geen eigenschappen te wijzigen of te verwijderen"
+
+#: common/daverror.cpp:121
+#, 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:123
+#, kde-format
+msgid ""
+"\n"
+"The server returned more information:\n"
+"%1"
+msgstr ""
+"\n"
+"De server gaf meer informatie terug:\n"
+"%1"
+
+#: common/daverror.cpp:127
+#, 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:131
+#, 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:135
+#, 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:140
+#, kde-format
+msgid "There was a problem with the request."
+msgstr "Er was een probleem met het verzoek."
+
+#: common/daverror.cpp:144
+#, 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/pl/libkdav.po b/po/pl/libkdav.po
new file mode 100644 (file)
index 0000000..db441da
--- /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: http://bugs.kde.org\n"
+"POT-Creation-Date: 2018-04-21 03:40+0200\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:83
+#, kde-format
+msgid "Invalid username/password"
+msgstr "Nieprawidłowa nazwa użytkownika/hasło"
+
+#: common/daverror.cpp:85
+#, kde-format
+msgid "Access forbidden"
+msgstr "Dostęp wzbroniony"
+
+#: common/daverror.cpp:87
+#, kde-format
+msgid "Resource not found"
+msgstr "Nie znaleziono zasobu"
+
+#: common/daverror.cpp:89
+#, kde-format
+msgid "HTTP error"
+msgstr "Błąd HTTP"
+
+#: common/daverror.cpp:91
+#, 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:95
+#, kde-format
+msgid "Protocol for the collection does not support MULTIGET"
+msgstr "Protokół dla zbioru nie obsługuje MULTIGET"
+
+#: common/daverror.cpp:98
+#, 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:101
+#, 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:105
+#, kde-format
+msgid "Invalid responses from backend"
+msgstr "Nieprawidłowa odpowiedź z modułu obsługi"
+
+#: common/daverror.cpp:108
+#, kde-format
+msgid "Error setting focus for XQuery"
+msgstr "Błąd ustawiania ostrości dla XQuery"
+
+#: common/daverror.cpp:111
+#, kde-format
+msgid "Invalid XQuery submitted by DAV implementation"
+msgstr "Nieprawidłowe XQuery wykonane przez DAV"
+
+#: common/daverror.cpp:114
+#, 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:118
+#, kde-format
+msgid "No properties to change or remove"
+msgstr "Nie ma właściwości, aby zmienić lub usunąć"
+
+#: common/daverror.cpp:121
+#, 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:123
+#, kde-format
+msgid ""
+"\n"
+"The server returned more information:\n"
+"%1"
+msgstr ""
+"\n"
+"Serwer zwrócił więcej informacji:\n"
+"%1"
+
+#: common/daverror.cpp:127
+#, 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:131
+#, 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:135
+#, 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:140
+#, kde-format
+msgid "There was a problem with the request."
+msgstr "Wystąpił problem z żądaniem."
+
+#: common/daverror.cpp:144
+#, 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..12eed95
--- /dev/null
@@ -0,0 +1,156 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: libkdav\n"
+"Report-Msgid-Bugs-To: http://bugs.kde.org\n"
+"POT-Creation-Date: 2018-04-21 03:40+0200\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: \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:83
+#, kde-format
+msgid "Invalid username/password"
+msgstr "Utilizador/senha inválidos"
+
+#: common/daverror.cpp:85
+#, kde-format
+msgid "Access forbidden"
+msgstr "Acesso proibido"
+
+#: common/daverror.cpp:87
+#, kde-format
+msgid "Resource not found"
+msgstr "Recurso não encontrado"
+
+#: common/daverror.cpp:89
+#, kde-format
+msgid "HTTP error"
+msgstr "Erro de HTTP"
+
+#: common/daverror.cpp:91
+#, 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:95
+#, 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:98
+#, 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:101
+#, 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:105
+#, kde-format
+msgid "Invalid responses from backend"
+msgstr "Foi obtida uma resposta inválida da infra-estrutura"
+
+#: common/daverror.cpp:108
+#, kde-format
+msgid "Error setting focus for XQuery"
+msgstr "Ocorreu um erro na atribuição do XQuery"
+
+#: common/daverror.cpp:111
+#, 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:114
+#, 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:118
+#, kde-format
+msgid "No properties to change or remove"
+msgstr "Não existem propriedades para alterar ou remover"
+
+#: common/daverror.cpp:121
+#, kde-format
+msgid "There was an error when modifying the properties"
+msgstr "Ocorreu um erro ao modificar as propriedades"
+
+#: common/daverror.cpp:123
+#, kde-format
+msgid ""
+"\n"
+"The server returned more information:\n"
+"%1"
+msgstr ""
+"\n"
+"O servidor devolveu mais informações:\n"
+"%1"
+
+#: common/daverror.cpp:127
+#, 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:131
+#, 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:135
+#, 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:140
+#, kde-format
+msgid "There was a problem with the request."
+msgstr "Ocorreu um problema com o pedido."
+
+#: common/daverror.cpp:144
+#, 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..6a25684
--- /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: http://bugs.kde.org\n"
+"POT-Creation-Date: 2018-04-21 03:40+0200\n"
+"PO-Revision-Date: 2018-07-24 23:51-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:83
+#, kde-format
+msgid "Invalid username/password"
+msgstr "Usuário/senha inválidos"
+
+#: common/daverror.cpp:85
+#, kde-format
+msgid "Access forbidden"
+msgstr "Acesso proibido"
+
+#: common/daverror.cpp:87
+#, kde-format
+msgid "Resource not found"
+msgstr "Recurso não encontrado"
+
+#: common/daverror.cpp:89
+#, kde-format
+msgid "HTTP error"
+msgstr "Erro de HTTP"
+
+#: common/daverror.cpp:91
+#, 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:95
+#, 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:98
+#, 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:101
+#, 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:105
+#, kde-format
+msgid "Invalid responses from backend"
+msgstr "Foi obtida uma resposta inválida da infraestrutura"
+
+#: common/daverror.cpp:108
+#, kde-format
+msgid "Error setting focus for XQuery"
+msgstr "Ocorreu um erro na configuração do XQuery"
+
+#: common/daverror.cpp:111
+#, 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:114
+#, 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:118
+#, kde-format
+msgid "No properties to change or remove"
+msgstr "Nenhuma propriedade para alterar ou remover"
+
+#: common/daverror.cpp:121
+#, kde-format
+msgid "There was an error when modifying the properties"
+msgstr "Ocorreu um erro ao modificar as propriedades"
+
+#: common/daverror.cpp:123
+#, kde-format
+msgid ""
+"\n"
+"The server returned more information:\n"
+"%1"
+msgstr ""
+"\n"
+"O servidor retornou mais informações:\n"
+"%1"
+
+#: common/daverror.cpp:127
+#, 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:131
+#, 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:135
+#, 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:140
+#, kde-format
+msgid "There was a problem with the request."
+msgstr "Ocorreu um problema com a solicitação."
+
+#: common/daverror.cpp:144
+#, 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/ru/libkdav.po b/po/ru/libkdav.po
new file mode 100644 (file)
index 0000000..7cec0c6
--- /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: http://bugs.kde.org\n"
+"POT-Creation-Date: 2018-04-21 03:40+0200\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:83
+#, kde-format
+msgid "Invalid username/password"
+msgstr "Неправильное имя пользователя или пароль"
+
+#: common/daverror.cpp:85
+#, kde-format
+msgid "Access forbidden"
+msgstr "Доступ запрещён"
+
+#: common/daverror.cpp:87
+#, kde-format
+msgid "Resource not found"
+msgstr "Ресурс не найден"
+
+#: common/daverror.cpp:89
+#, kde-format
+msgid "HTTP error"
+msgstr "Ошибка HTTP"
+
+#: common/daverror.cpp:91
+#, kde-format
+msgid ""
+"There was a problem with the request.\n"
+"%1 (%2)."
+msgstr ""
+"При выполнении запроса произошла ошибка.\n"
+"%1 (%2)."
+
+#: common/daverror.cpp:95
+#, kde-format
+msgid "Protocol for the collection does not support MULTIGET"
+msgstr "Протокол для этой коллекции не поддерживает MULTIGET."
+
+#: common/daverror.cpp:98
+#, kde-format
+msgid ""
+"The server encountered an error that prevented it from completing your "
+"request: %1 (%2)"
+msgstr ""
+"На сервере произошла ошибка, из-за чего он не смог завершить выполнение "
+"запроса: %1 (%2)"
+
+#: common/daverror.cpp:101
+#, 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:105
+#, kde-format
+msgid "Invalid responses from backend"
+msgstr "Неверный ответ сервера"
+
+#: common/daverror.cpp:108
+#, kde-format
+msgid "Error setting focus for XQuery"
+msgstr "Ошибка установки фокуса для XQuery"
+
+#: common/daverror.cpp:111
+#, kde-format
+msgid "Invalid XQuery submitted by DAV implementation"
+msgstr "Неверный XQuery, представленный реализацией DAV"
+
+#: common/daverror.cpp:114
+#, 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:118
+#, kde-format
+msgid "No properties to change or remove"
+msgstr "Нет свойств для изменения или удаления"
+
+#: common/daverror.cpp:121
+#, kde-format
+msgid "There was an error when modifying the properties"
+msgstr "При изменении свойств произошла ошибка"
+
+#: common/daverror.cpp:123
+#, kde-format
+msgid ""
+"\n"
+"The server returned more information:\n"
+"%1"
+msgstr ""
+"\n"
+"Сервер вернул расширенные сведения:\n"
+"%1"
+
+#: common/daverror.cpp:127
+#, 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:131
+#, 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:135
+#, 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:140
+#, kde-format
+msgid "There was a problem with the request."
+msgstr "При выполнении запроса произошла ошибка."
+
+#: common/daverror.cpp:144
+#, 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..d3fc91b
--- /dev/null
@@ -0,0 +1,159 @@
+# translation of libkdav.po to Slovak
+# Roman Paholík <wizzardsk@gmail.com>, 2017.
+msgid ""
+msgstr ""
+"Project-Id-Version: libkdav\n"
+"Report-Msgid-Bugs-To: http://bugs.kde.org\n"
+"POT-Creation-Date: 2018-04-21 03:40+0200\n"
+"PO-Revision-Date: 2017-12-03 21:41+0100\n"
+"Last-Translator: Roman Paholik <wizzardsk@gmail.com>\n"
+"Language-Team: Slovak <kde-sk@linux.sk>\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 2.0\n"
+"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
+
+#: common/daverror.cpp:83
+#, kde-format
+msgid "Invalid username/password"
+msgstr "Neplatné užívateľské meno/heslo"
+
+#: common/daverror.cpp:85
+#, kde-format
+msgid "Access forbidden"
+msgstr "Prístup zamietnutý"
+
+#: common/daverror.cpp:87
+#, kde-format
+msgid "Resource not found"
+msgstr "Zdroj nenájdený"
+
+#: common/daverror.cpp:89
+#, kde-format
+msgid "HTTP error"
+msgstr "HTTP chyba"
+
+#: common/daverror.cpp:91
+#, 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:95
+#, kde-format
+msgid "Protocol for the collection does not support MULTIGET"
+msgstr "Protokol pre kolekciu nepodporuje MULTIGET"
+
+#: common/daverror.cpp:98
+#, 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:101
+#, 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:105
+#, kde-format
+msgid "Invalid responses from backend"
+msgstr "Neplatná odpoveď z backendu"
+
+#: common/daverror.cpp:108
+#, kde-format
+msgid "Error setting focus for XQuery"
+msgstr "Chyba nastavenia zamerania na XQuery"
+
+#: common/daverror.cpp:111
+#, kde-format
+msgid "Invalid XQuery submitted by DAV implementation"
+msgstr "Neplatná XQuery poslaná implementáciou DAV"
+
+#: common/daverror.cpp:114
+#, 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:118
+#, kde-format
+msgid "No properties to change or remove"
+msgstr "Žiadne vlastnosti na zmenu alebo odstránenie"
+
+#: common/daverror.cpp:121
+#, kde-format
+msgid "There was an error when modifying the properties"
+msgstr "Nastala chyba počas zmeny vlastností"
+
+#: common/daverror.cpp:123
+#, kde-format
+msgid ""
+"\n"
+"The server returned more information:\n"
+"%1"
+msgstr ""
+"\n"
+"Server vrátil viac informácií:\n"
+"%1"
+
+#: common/daverror.cpp:127
+#, 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:131
+#, 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:135
+#, 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:140
+#, kde-format
+msgid "There was a problem with the request."
+msgstr "Bol problém s požiadavkou."
+
+#: common/daverror.cpp:144
+#, fuzzy, kde-format
+#| msgid ""
+#| "There was a problem with the request. The requested mimetypes are not "
+#| "supported."
+msgid ""
+"There was a problem with the request. The requested MIME types are not "
+"supported."
+msgstr "Nastal problém s požiadavkou. Požadované mime typy nie sú podporované."
diff --git a/po/sr/libkdav.po b/po/sr/libkdav.po
new file mode 100644 (file)
index 0000000..10eb3c9
--- /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: http://bugs.kde.org\n"
+"POT-Creation-Date: 2018-04-21 03:40+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:83
+#, kde-format
+msgid "Invalid username/password"
+msgstr "Лоше корисничко име или лозинка"
+
+#: common/daverror.cpp:85
+#, kde-format
+msgid "Access forbidden"
+msgstr "Приступ забрањен"
+
+#: common/daverror.cpp:87
+#, kde-format
+msgid "Resource not found"
+msgstr "Ресурс није нађен"
+
+#: common/daverror.cpp:89
+#, kde-format
+msgid "HTTP error"
+msgstr "ХТТП грешка"
+
+#: common/daverror.cpp:91
+#, kde-format
+msgid ""
+"There was a problem with the request.\n"
+"%1 (%2)."
+msgstr ""
+"Дошло је до проблема са захтевом.\n"
+"%1 (%2)."
+
+#: common/daverror.cpp:95
+#, kde-format
+msgid "Protocol for the collection does not support MULTIGET"
+msgstr "Протокол за збирке не подржава MULTIGET."
+
+#: common/daverror.cpp:98
+#, kde-format
+msgid ""
+"The server encountered an error that prevented it from completing your "
+"request: %1 (%2)"
+msgstr ""
+"Сервер је наишао на грешку која га је спречила да доврши ваш захтев: %1 (%2)"
+
+#: common/daverror.cpp:101
+#, 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:105
+#, kde-format
+msgid "Invalid responses from backend"
+msgstr "Неисправни одговори из позадине."
+
+#: common/daverror.cpp:108
+#, kde-format
+msgid "Error setting focus for XQuery"
+msgstr "Грешка у постављању фокуса за икс‑упит."
+
+#: common/daverror.cpp:111
+#, kde-format
+msgid "Invalid XQuery submitted by DAV implementation"
+msgstr "Изведба ДАВ‑а предала је лош икс‑упит."
+
+#: common/daverror.cpp:114
+#, 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:118
+#, kde-format
+msgid "No properties to change or remove"
+msgstr "Нема својстава за мењање или уклањање."
+
+#: common/daverror.cpp:121
+#, kde-format
+msgid "There was an error when modifying the properties"
+msgstr "Грешка при мењању својстава."
+
+#: common/daverror.cpp:123
+#, kde-format
+msgid ""
+"\n"
+"The server returned more information:\n"
+"%1"
+msgstr ""
+"\n"
+"Сервер је вратио још података:\n"
+"%1"
+
+#: common/daverror.cpp:127
+#, 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:131
+#, 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:135
+#, 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:140
+#, kde-format
+msgid "There was a problem with the request."
+msgstr "Дошло је до проблема са захтевом."
+
+#: common/daverror.cpp:144
+#, kde-format
+msgid ""
+"There was a problem with the request. The requested MIME types are not "
+"supported."
+msgstr "Дошло је до проблема са захтевом. Тражени МИМЕ типови нису подржани."
diff --git a/po/sv/libkdav.po b/po/sv/libkdav.po
new file mode 100644 (file)
index 0000000..14a5a1b
--- /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: http://bugs.kde.org\n"
+"POT-Creation-Date: 2018-04-21 03:40+0200\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:83
+#, kde-format
+msgid "Invalid username/password"
+msgstr "Ogiltigt användarnamn eller lösenord"
+
+#: common/daverror.cpp:85
+#, kde-format
+msgid "Access forbidden"
+msgstr "Åtkomst nekas"
+
+#: common/daverror.cpp:87
+#, kde-format
+msgid "Resource not found"
+msgstr "Resurs hittades inte"
+
+#: common/daverror.cpp:89
+#, kde-format
+msgid "HTTP error"
+msgstr "HTTP-fel"
+
+#: common/daverror.cpp:91
+#, 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:95
+#, kde-format
+msgid "Protocol for the collection does not support MULTIGET"
+msgstr "Protokoll för samlingen stöder inte MULTIGET"
+
+#: common/daverror.cpp:98
+#, 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:101
+#, 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:105
+#, kde-format
+msgid "Invalid responses from backend"
+msgstr "Felaktigt svar från gränssnitt"
+
+#: common/daverror.cpp:108
+#, kde-format
+msgid "Error setting focus for XQuery"
+msgstr "Fel när fokus skulle ställas in för XQuery"
+
+#: common/daverror.cpp:111
+#, kde-format
+msgid "Invalid XQuery submitted by DAV implementation"
+msgstr "Felaktig XQuery skickades av DAV-implementering"
+
+#: common/daverror.cpp:114
+#, 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:118
+#, kde-format
+msgid "No properties to change or remove"
+msgstr "Inga egenskaper att ändra eller ta bort"
+
+#: common/daverror.cpp:121
+#, kde-format
+msgid "There was an error when modifying the properties"
+msgstr "Ett fel uppstod när egenskaperna skulle ändras"
+
+#: common/daverror.cpp:123
+#, kde-format
+msgid ""
+"\n"
+"The server returned more information:\n"
+"%1"
+msgstr ""
+"\n"
+"Servern returnerade mer information:\n"
+"%1"
+
+#: common/daverror.cpp:127
+#, 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:131
+#, 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:135
+#, 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:140
+#, kde-format
+msgid "There was a problem with the request."
+msgstr "Ett problem uppstod med begäran."
+
+#: common/daverror.cpp:144
+#, 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/uk/libkdav.po b/po/uk/libkdav.po
new file mode 100644 (file)
index 0000000..9337607
--- /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: http://bugs.kde.org\n"
+"POT-Creation-Date: 2018-04-21 03:40+0200\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:83
+#, kde-format
+msgid "Invalid username/password"
+msgstr "Некоректне ім’я користувача чи пароль"
+
+#: common/daverror.cpp:85
+#, kde-format
+msgid "Access forbidden"
+msgstr "Доступ заборонено"
+
+#: common/daverror.cpp:87
+#, kde-format
+msgid "Resource not found"
+msgstr "Ресурс не знайдено"
+
+#: common/daverror.cpp:89
+#, kde-format
+msgid "HTTP error"
+msgstr "Помилка HTTP"
+
+#: common/daverror.cpp:91
+#, kde-format
+msgid ""
+"There was a problem with the request.\n"
+"%1 (%2)."
+msgstr ""
+"Під час виконання запиту виникла проблема.\n"
+"%1 (%2)."
+
+#: common/daverror.cpp:95
+#, kde-format
+msgid "Protocol for the collection does not support MULTIGET"
+msgstr "У протоколі для роботи з цією збіркою не передбачено команди MULTIGET"
+
+#: common/daverror.cpp:98
+#, kde-format
+msgid ""
+"The server encountered an error that prevented it from completing your "
+"request: %1 (%2)"
+msgstr ""
+"На сервері сталася помилка, через яку він не зміг завершити виконання вашого "
+"запиту: %1 (%2)"
+
+#: common/daverror.cpp:101
+#, 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:105
+#, kde-format
+msgid "Invalid responses from backend"
+msgstr "Отримано некоректні відповіді сервера"
+
+#: common/daverror.cpp:108
+#, kde-format
+msgid "Error setting focus for XQuery"
+msgstr "Помилка під час спроби встановлення фокусу для XQuery"
+
+#: common/daverror.cpp:111
+#, kde-format
+msgid "Invalid XQuery submitted by DAV implementation"
+msgstr "Реалізацією DAV було надіслано некоректні дані XQuery"
+
+#: common/daverror.cpp:114
+#, 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:118
+#, kde-format
+msgid "No properties to change or remove"
+msgstr "Немає властивостей для зміни або вилучення"
+
+#: common/daverror.cpp:121
+#, kde-format
+msgid "There was an error when modifying the properties"
+msgstr "Під час спроби зміни властивостей сталася помилка"
+
+#: common/daverror.cpp:123
+#, kde-format
+msgid ""
+"\n"
+"The server returned more information:\n"
+"%1"
+msgstr ""
+"\n"
+"Сервером було повернуто додаткову інформацію:\n"
+"%1"
+
+#: common/daverror.cpp:127
+#, 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:131
+#, 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:135
+#, 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:140
+#, kde-format
+msgid "There was a problem with the request."
+msgstr "Під час виконання запиту виникла проблема."
+
+#: common/daverror.cpp:144
+#, 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..8ba9a4b
--- /dev/null
@@ -0,0 +1,159 @@
+# 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: kdeorg\n"
+"Report-Msgid-Bugs-To: http://bugs.kde.org\n"
+"POT-Creation-Date: 2018-04-21 03:40+0200\n"
+"PO-Revision-Date: 2018-11-01 23:18\n"
+"Last-Translator: guoyunhe <i@guoyunhe.me>\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-Generator: crowdin.com\n"
+"X-Crowdin-Project: kdeorg\n"
+"X-Crowdin-Language: zh-CN\n"
+"X-Crowdin-File: /kf5-stable/messages/pim/libkdav.pot\n"
+
+#: common/daverror.cpp:83
+#, kde-format
+msgid "Invalid username/password"
+msgstr "无效的用户名或密码"
+
+#: common/daverror.cpp:85
+#, kde-format
+msgid "Access forbidden"
+msgstr "禁止访问"
+
+#: common/daverror.cpp:87
+#, kde-format
+msgid "Resource not found"
+msgstr "找不到资源"
+
+#: common/daverror.cpp:89
+#, kde-format
+msgid "HTTP error"
+msgstr "HTTP 错误"
+
+#: common/daverror.cpp:91
+#, kde-format
+msgid ""
+"There was a problem with the request.\n"
+"%1 (%2)."
+msgstr "请求出错。\\n%1 (%2)。"
+
+#: common/daverror.cpp:95
+#, kde-format
+msgid "Protocol for the collection does not support MULTIGET"
+msgstr "集合的协议不支持 MULTIGET"
+
+#: common/daverror.cpp:98
+#, kde-format
+msgid ""
+"The server encountered an error that prevented it from completing your "
+"request: %1 (%2)"
+msgstr "服务器出现错误,无法完成您的请求:%1 (%2)"
+
+#: common/daverror.cpp:101
+#, 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:105
+#, kde-format
+msgid "Invalid responses from backend"
+msgstr "无效的后端应答"
+
+#: common/daverror.cpp:108
+#, kde-format
+msgid "Error setting focus for XQuery"
+msgstr "设置 XQuery 焦点时发生错误"
+
+#: common/daverror.cpp:111
+#, kde-format
+msgid "Invalid XQuery submitted by DAV implementation"
+msgstr "DAV 实现提交了无效的 XQuery"
+
+#: common/daverror.cpp:114
+#, 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:118
+#, kde-format
+msgid "No properties to change or remove"
+msgstr "没有要更改或删除的属性"
+
+#: common/daverror.cpp:121
+#, kde-format
+msgid "There was an error when modifying the properties"
+msgstr "修改属性时出错"
+
+#: common/daverror.cpp:123
+#, kde-format
+msgid ""
+"\n"
+"The server returned more information:\n"
+"%1"
+msgstr ""
+"\n"
+"服务器返回更多信息:\n"
+"%1"
+
+#: common/daverror.cpp:127
+#, 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:131
+#, 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:135
+#, 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:140
+#, kde-format
+msgid "There was a problem with the request."
+msgstr "请求出错。"
+
+#: common/daverror.cpp:144
+#, 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..8ad0760
--- /dev/null
@@ -0,0 +1,132 @@
+add_definitions(-DTRANSLATION_DOMAIN=\"libkdav\")
+include_directories(
+   common/
+   protocols/
+)
+
+########### next target ###############
+
+set(libkdav_SRCS
+ common/davjobbase.cpp
+ common/davcollection.cpp
+ common/davcollectiondeletejob.cpp
+ common/davcollectionsfetchjob.cpp
+ common/davcollectionmodifyjob.cpp
+ common/davcollectionsmultifetchjob.cpp
+ common/davprotocolbase.cpp
+ common/daverror.cpp
+ common/davitem.cpp
+ common/davitemcreatejob.cpp
+ common/davitemdeletejob.cpp
+ common/davitemfetchjob.cpp
+ common/davitemmodifyjob.cpp
+ common/davitemsfetchjob.cpp
+ common/davitemslistjob.cpp
+ common/davmanager.cpp
+ common/davmultigetprotocol.cpp
+ common/davprincipalhomesetsfetchjob.cpp
+ common/davprincipalsearchjob.cpp
+ common/davurl.cpp
+ common/utils.cpp
+ common/etagcache.cpp
+
+ protocols/groupdavprotocol.cpp
+
+ #KContacts
+ protocols/carddavprotocol.cpp
+
+ #KCalCore
+ protocols/caldavprotocol.cpp
+)
+
+
+ecm_generate_headers(KDAV_Camelcase_HEADERS
+    HEADER_NAMES
+    DavJobBase
+    DavCollection
+    DavCollectionDeleteJob
+    DavCollectionsFetchJob
+    DavCollectionModifyJob
+    DavCollectionsMultiFetchJob
+    DavError
+    DavItem
+    DavItemCreateJob
+    DavItemDeleteJob
+    DavItemFetchJob
+    DavItemModifyJob
+    DavItemsFetchJob
+    DavItemsListJob
+    DavManager
+    DavProtocolBase
+    DavPrincipalHomesetsFetchJob
+    DavPrincipalSearchJob
+    DavUrl
+    Utils
+    Enums
+    EtagCache
+    REQUIRED_HEADERS KDAV_HEADERS
+    PREFIX KDAV
+    RELATIVE common
+    )
+
+install(FILES
+    ${KDAV_Camelcase_HEADERS}
+    DESTINATION ${KDE_INSTALL_INCLUDEDIR}/KPim/KDAV
+    COMPONENT Devel
+    )
+
+install(FILES
+    ${KDAV_HEADERS}
+    ${CMAKE_CURRENT_BINARY_DIR}/kpimkdav_export.h
+    ${CMAKE_CURRENT_BINARY_DIR}/libkdav_debug.h
+
+    DESTINATION ${KDE_INSTALL_INCLUDEDIR}/KPim/kdav
+    COMPONENT Devel
+    )
+
+ecm_generate_pri_file(BASE_NAME kdav
+    LIB_NAME KPimKDAV
+    FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR}/KDAV
+    )
+
+install(FILES
+    ${PRI_FILENAME}
+    DESTINATION ${ECM_MKSPECS_INSTALL_DIR}
+    )
+
+ecm_qt_declare_logging_category(libkdav_SRCS HEADER libkdav_debug.h IDENTIFIER KDAV_LOG CATEGORY_NAME org.kde.pim.kdav)
+
+add_library(KPimKDAV
+   ${libkdav_SRCS}
+   )
+
+generate_export_header(KPimKDAV BASE_NAME kpimkdav)
+
+add_library(KPim::KDAV ALIAS KPimKDAV)
+
+target_link_libraries(KPimKDAV
+PUBLIC
+    KF5::CoreAddons
+PRIVATE
+    Qt5::Xml
+    Qt5::Gui
+    Qt5::XmlPatterns
+    KF5::KIOCore
+    KF5::I18n
+    )
+
+set_target_properties(KPimKDAV PROPERTIES
+    VERSION ${KDAV_VERSION_STRING}
+    SOVERSION ${KDAV_SOVERSION}
+    EXPORT_NAME KDAV
+    )
+
+install(TARGETS
+    KPimKDAV
+    EXPORT KPimKDAVTargets
+    ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}
+    ${LIBRARY_NAMELINK}
+    )
+
+target_include_directories(KPimKDAV INTERFACE "$<INSTALL_INTERFACE:${KDE_INSTALL_INCLUDEDIR}/KPim/KDAV/;${KDE_INSTALL_INCLUDEDIR}/KPim/kdav;${KDE_INSTALL_INCLUDEDIR}/KPim>")
+
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..e0476ff
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+    Copyright (c) 2009 Grégory Oestreicher <greg@kamago.net>
+
+    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.
+*/
+
+#include "davcollection.h"
+
+#include "davurl.h"
+
+#include <QColor>
+
+using namespace KDAV;
+
+class DavCollectionPrivate
+{
+public:
+    DavCollectionPrivate(DavCollection *qPtr) : q(qPtr)
+    {
+    }
+
+    void fillFrom(const DavCollectionPrivate &other);
+
+    DavCollection *q;
+    QString mCTag;
+    DavUrl mUrl;
+    QString mDisplayName;
+    QColor mColor;
+    DavCollection::ContentTypes mContentTypes;
+    Privileges mPrivileges;
+};
+
+void DavCollectionPrivate::fillFrom(const DavCollectionPrivate &other)
+{
+    mCTag = other.mCTag;
+    mUrl = other.mUrl;
+    mDisplayName = other.mDisplayName;
+    mColor = other.mColor;
+    mContentTypes = other.mContentTypes;
+    mPrivileges = other.mPrivileges;
+}
+
+DavCollection::DavCollection()
+    : d(std::unique_ptr<DavCollectionPrivate>(new DavCollectionPrivate(this)))
+{
+}
+
+DavCollection::DavCollection(const DavUrl &url, const QString &displayName, ContentTypes contentTypes)
+    : d(std::unique_ptr<DavCollectionPrivate>(new DavCollectionPrivate(this)))
+{
+    d->mUrl = url;
+    d->mDisplayName = displayName;
+    d->mContentTypes = contentTypes;
+    d->mPrivileges = KDAV::All;
+}
+
+DavCollection::DavCollection(const DavCollection &other)
+    : d(std::unique_ptr<DavCollectionPrivate>(new DavCollectionPrivate(this)))
+{
+    d->fillFrom(*other.d.get());
+}
+
+DavCollection &DavCollection::operator=(const DavCollection &other)
+{
+    d->fillFrom(*other.d.get());
+    return *this;
+}
+
+DavCollection::~DavCollection()
+{
+}
+
+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..5e16ec0
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+    Copyright (c) 2009 Grégory Oestreicher <greg@kamago.net>
+
+    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.
+*/
+
+#ifndef KDAV_DAVCOLLECTION_H
+#define KDAV_DAVCOLLECTION_H
+
+#include "kpimkdav_export.h"
+
+#include "enums.h"
+
+#include <memory>
+
+#include <QVector>
+#include <QString>
+
+class QColor;
+
+class DavCollectionPrivate;
+
+namespace KDAV {
+class DavUrl;
+}
+
+namespace KDAV {
+/**
+ * @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 KPIMKDAV_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 &operator=(const DavCollection &other);
+
+    ~DavCollection();
+
+    /**
+     * Sets this collection CTag.
+     */
+    void setCTag(const QString &ctag);
+
+    /**
+     * Returns this collection CTag. The returned value will be empty
+     * if no CTag was found.
+     */
+    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:
+    std::unique_ptr<DavCollectionPrivate> d;
+};
+}
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(KDAV::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..f3f3ef0
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+    Copyright (c) 2010 Grégory Oestreicher <greg@kamago.net>
+
+    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.
+*/
+
+#include "davcollectiondeletejob.h"
+
+#include "daverror.h"
+
+#include <KIO/DeleteJob>
+#include <KIO/Job>
+
+using namespace KDAV;
+
+DavCollectionDeleteJob::DavCollectionDeleteJob(const DavUrl &url, QObject *parent)
+    : DavJobBase(parent)
+    , mUrl(url)
+{
+}
+
+void DavCollectionDeleteJob::start()
+{
+    KIO::DeleteJob *job = KIO::del(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, &DavCollectionDeleteJob::davJobFinished);
+}
+
+void DavCollectionDeleteJob::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..828fdc8
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+    Copyright (c) 2010 Grégory Oestreicher <greg@kamago.net>
+
+    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.
+*/
+
+#ifndef KDAV_DAVCOLLECTIONDELETEJOB_H
+#define KDAV_DAVCOLLECTIONDELETEJOB_H
+
+#include "kpimkdav_export.h"
+
+#include "davjobbase.h"
+#include "davurl.h"
+
+#include <KJob>
+
+namespace KDAV {
+/**
+ * @short A job that deletes a DAV collection.
+ *
+ * This job is used to delete a DAV collection at a certain URL.
+ */
+class KPIMKDAV_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_SLOTS:
+    void davJobFinished(KJob *);
+
+private:
+    DavUrl mUrl;
+};
+}
+
+#endif
diff --git a/src/common/davcollectionmodifyjob.cpp b/src/common/davcollectionmodifyjob.cpp
new file mode 100644 (file)
index 0000000..c8c04e9
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+    Copyright (c) 2010 Grégory Oestreicher <greg@kamago.net>
+
+    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.
+*/
+
+#include "davcollectionmodifyjob.h"
+#include "davmanager.h"
+
+#include "daverror.h"
+#include "utils.h"
+
+#include <KIO/DavJob>
+#include <KIO/Job>
+
+using namespace KDAV;
+
+DavCollectionModifyJob::DavCollectionModifyJob(const DavUrl &url, QObject *parent)
+    : DavJobBase(parent)
+    , mUrl(url)
+{
+}
+
+void DavCollectionModifyJob::setProperty(const QString &prop, const QString &value, const QString &ns)
+{
+    QDomElement propElement;
+
+    if (ns.isEmpty()) {
+        propElement = mQuery.createElement(prop);
+    } else {
+        propElement = mQuery.createElementNS(ns, prop);
+    }
+
+    const QDomText textElement = mQuery.createTextNode(value);
+    propElement.appendChild(textElement);
+
+    mSetProperties << propElement;
+}
+
+void DavCollectionModifyJob::removeProperty(const QString &prop, const QString &ns)
+{
+    QDomElement propElement;
+
+    if (ns.isEmpty()) {
+        propElement = mQuery.createElement(prop);
+    } else {
+        propElement = mQuery.createElementNS(ns, prop);
+    }
+
+    mRemoveProperties << propElement;
+}
+
+void DavCollectionModifyJob::start()
+{
+    if (mSetProperties.isEmpty() && mRemoveProperties.isEmpty()) {
+        setError(ERR_COLLECTIONMODIFY_NO_PROPERITES);
+        setErrorTextFromDavError();
+        emitResult();
+        return;
+    }
+
+    QDomDocument mQuery;
+    QDomElement propertyUpdateElement = mQuery.createElementNS(QStringLiteral("DAV:"), QStringLiteral("propertyupdate"));
+    mQuery.appendChild(propertyUpdateElement);
+
+    if (!mSetProperties.isEmpty()) {
+        QDomElement setElement = mQuery.createElementNS(QStringLiteral("DAV:"), QStringLiteral("set"));
+        propertyUpdateElement.appendChild(setElement);
+
+        QDomElement propElement = mQuery.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop"));
+        setElement.appendChild(propElement);
+
+        foreach (const QDomElement &element, mSetProperties) {
+            propElement.appendChild(element);
+        }
+    }
+
+    if (!mRemoveProperties.isEmpty()) {
+        QDomElement removeElement = mQuery.createElementNS(QStringLiteral("DAV:"), QStringLiteral("remove"));
+        propertyUpdateElement.appendChild(removeElement);
+
+        QDomElement propElement = mQuery.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop"));
+        removeElement.appendChild(propElement);
+
+        foreach (const QDomElement &element, mSetProperties) {
+            propElement.appendChild(element);
+        }
+    }
+
+    KIO::DavJob *job = DavManager::self()->createPropPatchJob(mUrl.url(), mQuery);
+    job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true"));
+    connect(job, &KIO::DavJob::result, this, &DavCollectionModifyJob::davJobFinished);
+}
+
+void DavCollectionModifyJob::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;
+    }
+
+    const QDomDocument response = davJob->response();
+    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..5517de0
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+    Copyright (c) 2010 Grégory Oestreicher <greg@kamago.net>
+
+    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.
+*/
+
+#ifndef KDAV_DAVCOLLECTIONMODIFYJOB_H
+#define KDAV_DAVCOLLECTIONMODIFYJOB_H
+
+#include "kpimkdav_export.h"
+
+#include "davjobbase.h"
+#include "davurl.h"
+
+#include <QDomDocument>
+
+#include <KJob>
+
+namespace KDAV {
+/**
+ * @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 KPIMKDAV_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:
+    void davJobFinished(KJob *job);
+    DavUrl mUrl;
+    QDomDocument mQuery;
+
+    QVector<QDomElement> mSetProperties;
+    QVector<QDomElement> mRemoveProperties;
+};
+}
+
+#endif
diff --git a/src/common/davcollectionsfetchjob.cpp b/src/common/davcollectionsfetchjob.cpp
new file mode 100644 (file)
index 0000000..2f61cf3
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+    Copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
+
+    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.
+*/
+
+#include "davcollectionsfetchjob.h"
+
+#include "davmanager.h"
+#include "davprincipalhomesetsfetchjob.h"
+#include "davprotocolbase.h"
+#include "utils.h"
+#include "daverror.h"
+
+#include "libkdav_debug.h"
+#include <KIO/DavJob>
+#include <KIO/Job>
+
+#include <QColor>
+#include <QBuffer>
+#include <QtXmlPatterns/QXmlQuery>
+
+using namespace KDAV;
+
+DavCollectionsFetchJob::DavCollectionsFetchJob(const DavUrl &url, QObject *parent)
+    : DavJobBase(parent)
+    , mUrl(url)
+    , mSubJobCount(0)
+{
+}
+
+void DavCollectionsFetchJob::start()
+{
+    if (DavManager::self()->davProtocol(mUrl.protocol())->supportsPrincipals()) {
+        DavPrincipalHomeSetsFetchJob *job = new DavPrincipalHomeSetsFetchJob(mUrl);
+        connect(job, &DavPrincipalHomeSetsFetchJob::result, this, &DavCollectionsFetchJob::principalFetchFinished);
+        job->start();
+    } else {
+        doCollectionsFetch(mUrl.url());
+    }
+}
+
+DavCollection::List DavCollectionsFetchJob::collections() const
+{
+    return mCollections;
+}
+
+DavUrl DavCollectionsFetchJob::davUrl() const
+{
+    return mUrl;
+}
+
+void DavCollectionsFetchJob::doCollectionsFetch(const QUrl &url)
+{
+    ++mSubJobCount;
+
+    const QDomDocument collectionQuery = DavManager::self()->davProtocol(mUrl.protocol())->collectionsQuery()->buildQuery();
+
+    KIO::DavJob *job = DavManager::self()->createPropFindJob(url, collectionQuery);
+    connect(job, &KIO::DavJob::result, this, &DavCollectionsFetchJob::collectionsFetchFinished);
+    job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true"));
+}
+
+void DavCollectionsFetchJob::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 DavCollectionsFetchJob::collectionsFetchFinished(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)) {
+        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
+        QDomElement rootElement = davJob->response().documentElement();
+        if (rootElement.tagName().compare(QLatin1String("multistatus"), Qt::CaseInsensitive) != 0) {
+            setError(ERR_COLLECTIONFETCH);
+            setErrorTextFromDavError();
+            subjobFinished();
+            return;
+        }
+
+        QByteArray resp(davJob->response().toByteArray());
+        QBuffer buffer(&resp);
+        buffer.open(QIODevice::ReadOnly);
+
+        QXmlQuery xquery;
+        if (!xquery.setFocus(&buffer)) {
+            setError(ERR_COLLECTIONFETCH_XQUERY_SETFOCUS);
+            setErrorTextFromDavError();
+            subjobFinished();
+            return;
+        }
+
+        xquery.setQuery(DavManager::self()->davProtocol(mUrl.protocol())->collectionsXQuery());
+        if (!xquery.isValid()) {
+            setError(ERR_COLLECTIONFETCH_XQUERY_INVALID);
+            setErrorTextFromDavError();
+            subjobFinished();
+            return;
+        }
+
+        QString responsesStr;
+        xquery.evaluateTo(&responsesStr);
+        responsesStr.prepend(QLatin1String("<responses>"));
+        responsesStr.append(QLatin1String("</responses>"));
+
+        QDomDocument document;
+        if (!document.setContent(responsesStr, true)) {
+            setError(ERR_COLLECTIONFETCH);
+            setErrorTextFromDavError();
+            subjobFinished();
+            return;
+        }
+
+        if (!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 : qAsConst(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"));
+                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::self()->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 collectionDiscovered(mUrl.protocol(), url.toDisplayString(), jobUrl);
+
+                responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response"));
+            }
+        }
+    }
+
+    subjobFinished();
+}
+
+void DavCollectionsFetchJob::subjobFinished()
+{
+    if (--mSubJobCount == 0) {
+        emitResult();
+    }
+}
diff --git a/src/common/davcollectionsfetchjob.h b/src/common/davcollectionsfetchjob.h
new file mode 100644 (file)
index 0000000..ff5ff40
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+    Copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
+
+    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.
+*/
+
+#ifndef KDAV_DAVCOLLECTIONSFETCHJOB_H
+#define KDAV_DAVCOLLECTIONSFETCHJOB_H
+
+#include "kpimkdav_export.h"
+
+#include "davcollection.h"
+#include "davjobbase.h"
+#include "davurl.h"
+
+#include <KJob>
+
+namespace KDAV {
+/**
+ * @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 KPIMKDAV_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(int protocol, const QString &collectionUrl, const QString &configuredUrl);
+
+private:
+    void principalFetchFinished(KJob *);
+    void collectionsFetchFinished(KJob *);
+    void doCollectionsFetch(const QUrl &url);
+    void subjobFinished();
+
+    DavUrl mUrl;
+    DavCollection::List mCollections;
+    uint mSubJobCount;
+};
+}
+
+#endif
diff --git a/src/common/davcollectionsmultifetchjob.cpp b/src/common/davcollectionsmultifetchjob.cpp
new file mode 100644 (file)
index 0000000..7bbec55
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+    Copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
+
+    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.
+*/
+
+#include "davcollectionsmultifetchjob.h"
+
+#include "davcollectionsfetchjob.h"
+
+using namespace KDAV;
+
+DavCollectionsMultiFetchJob::DavCollectionsMultiFetchJob(const DavUrl::List &urls, QObject *parent)
+    : KJob(parent)
+    , mUrls(urls)
+    , mSubJobCount(urls.size())
+{
+}
+
+void DavCollectionsMultiFetchJob::start()
+{
+    if (mUrls.isEmpty()) {
+        emitResult();
+    }
+
+    foreach (const DavUrl &url, mUrls) {
+        DavCollectionsFetchJob *job = new DavCollectionsFetchJob(url, this);
+        connect(job, &DavCollectionsFetchJob::result, this, &DavCollectionsMultiFetchJob::davJobFinished);
+        connect(job, &DavCollectionsFetchJob::collectionDiscovered, this, &DavCollectionsMultiFetchJob::collectionDiscovered);
+        job->start();
+    }
+}
+
+DavCollection::List DavCollectionsMultiFetchJob::collections() const
+{
+    return mCollections;
+}
+
+void DavCollectionsMultiFetchJob::davJobFinished(KJob *job)
+{
+    DavCollectionsFetchJob *fetchJob = qobject_cast<DavCollectionsFetchJob *>(job);
+
+    if (job->error()) {
+        setError(job->error());
+        setErrorText(job->errorText());
+    } else {
+        mCollections << fetchJob->collections();
+    }
+
+    if (--mSubJobCount == 0) {
+        emitResult();
+    }
+}
diff --git a/src/common/davcollectionsmultifetchjob.h b/src/common/davcollectionsmultifetchjob.h
new file mode 100644 (file)
index 0000000..62ea025
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+    Copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
+
+    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.
+*/
+
+#ifndef KDAV_DAVCOLLECTIONSMULTIFETCHJOB_H
+#define KDAV_DAVCOLLECTIONSMULTIFETCHJOB_H
+
+#include "kpimkdav_export.h"
+
+#include "davcollection.h"
+#include "davurl.h"
+
+#include <KJob>
+
+namespace KDAV {
+/**
+ * @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 KPIMKDAV_EXPORT DavCollectionsMultiFetchJob : public KJob
+{
+    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);
+
+    /**
+     * 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(int protocol, const QString &collectionUrl, const QString &configuredUrl);
+
+private:
+    void davJobFinished(KJob *);
+    DavUrl::List mUrls;
+    DavCollection::List mCollections;
+    uint mSubJobCount;
+};
+}
+
+#endif
diff --git a/src/common/daverror.cpp b/src/common/daverror.cpp
new file mode 100644 (file)
index 0000000..f0bc514
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+    Copyright (c) 2016 Sandro Knauß <sknauss@kde.org>
+
+    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.
+*/
+
+#include "daverror.h"
+#include <KLocalizedString>
+
+#include <KIO/Global>
+#include <KIO/Job>
+
+using namespace KDAV;
+
+Error::Error()
+    : mErrorNumber(NO_ERR)
+    , mResponseCode(0)
+    , mJobErrorCode(0)
+{
+}
+
+Error::Error(ErrorNumber errNo, int responseCode, const QString &errorText, int jobErrorCode)
+    : mErrorNumber(errNo)
+    , mResponseCode(responseCode)
+    , mErrorText(errorText)
+    , mJobErrorCode(jobErrorCode)
+{
+}
+
+ErrorNumber Error::errorNumber() const
+{
+    return mErrorNumber;
+}
+
+QString Error::internalErrorText() const
+{
+    return mErrorText;
+}
+
+int Error::jobErrorCode() const
+{
+    return mJobErrorCode;
+}
+
+int Error::responseCode() const
+{
+    return mResponseCode;
+}
+
+QString KDAV::Error::translatedJobError() const
+{
+    QString err;
+    if (mJobErrorCode > 0 && mJobErrorCode != KIO::ERR_SLAVE_DEFINED) {
+        err = KIO::buildErrorString(mJobErrorCode, mErrorText);
+    } else {
+        err = mErrorText;
+    }
+    return err;
+}
+
+QString Error::errorText() const
+{
+    QString result;
+
+    QString err = translatedJobError();
+
+    switch (mErrorNumber) {
+    case ERR_PROBLEM_WITH_REQUEST:
+        // User-side error
+        if (mResponseCode == 401) {
+            err = i18n("Invalid username/password");
+        } else if (mResponseCode == 403) {
+            err = i18n("Access forbidden");
+        } else if (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, 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, 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, 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, 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 (!mErrorText.isEmpty()) {
+            result.append(i18n("\nThe server returned more information:\n%1", 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, 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, 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, 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..e286ffe
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+    Copyright (c) 2016 Sandro Knauß <sknauss@kde.org>
+
+    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.
+*/
+
+#ifndef KDAV_DAVERROR_H
+#define KDAV_DAVERROR_H
+
+#include "kpimkdav_export.h"
+
+#include <KJob>
+
+#include <QString>
+
+namespace KDAV {
+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 KPIMKDAV_EXPORT Error
+{
+public:
+    explicit Error();
+    explicit Error(ErrorNumber errNo, int responseCode, const QString &errorText, int jobErrorCode);
+
+    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:
+    ErrorNumber mErrorNumber;
+    int mResponseCode;
+    QString mErrorText;
+    int mJobErrorCode;
+};
+}
+
+#endif
diff --git a/src/common/davitem.cpp b/src/common/davitem.cpp
new file mode 100644 (file)
index 0000000..82236d2
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+    Copyright (c) 2009 Grégory Oestreicher <greg@kamago.net>
+
+    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.
+*/
+
+#include "davitem.h"
+
+#include "davurl.h"
+
+using namespace KDAV;
+
+class DavItemPrivate
+{
+public:
+    DavItemPrivate(DavItem *qPtr) : q(qPtr)
+    {
+    }
+
+    void fillFrom(const DavItemPrivate &other);
+
+    DavItem *q;
+
+    DavUrl mUrl;
+    QString mContentType;
+    QByteArray mData;
+    QString mEtag;
+};
+
+void DavItemPrivate::fillFrom(const DavItemPrivate &other)
+{
+    mUrl = other.mUrl;
+    mContentType = other.mContentType;
+    mData = other.mData;
+    mEtag = other.mEtag;
+}
+
+DavItem::DavItem()
+    : d(std::unique_ptr<DavItemPrivate>(new DavItemPrivate(this)))
+{
+}
+
+DavItem::DavItem(const DavUrl &url, const QString &contentType, const QByteArray &data, const QString &etag)
+    : d(std::unique_ptr<DavItemPrivate>(new DavItemPrivate(this)))
+{
+    d->mUrl = url;
+    d->mContentType = contentType;
+    d->mData = data;
+    d->mEtag = etag;
+}
+
+DavItem::DavItem(const DavItem &other)
+    : d(std::unique_ptr<DavItemPrivate>(new DavItemPrivate(this)))
+{
+    d->fillFrom(*other.d.get());
+}
+
+DavItem &DavItem::operator=(const DavItem &other)
+{
+    d->fillFrom(*other.d.get());
+    return *this;
+}
+
+DavItem::~DavItem()
+{
+}
+
+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, 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..9b3c05f
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+    Copyright (c) 2009 Grégory Oestreicher <greg@kamago.net>
+
+    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.
+*/
+
+#ifndef KDAV_DAVITEM_H
+#define KDAV_DAVITEM_H
+
+#include "kpimkdav_export.h"
+
+#include <memory>
+
+#include <QByteArray>
+#include <QDataStream>
+#include <QString>
+#include <QVector>
+
+class DavItemPrivate;
+
+namespace KDAV {
+class DavUrl;
+}
+
+namespace KDAV {
+/**
+ * @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 KPIMKDAV_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 &operator=(const DavItem &other);
+
+    ~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.
+     */
+    void setEtag(const QString &etag);
+
+    /**
+     * Returns the etag of the item.
+     */
+    Q_REQUIRED_RESULT QString etag() const;
+
+private:
+    std::unique_ptr<DavItemPrivate> d;
+};
+
+KPIMKDAV_EXPORT QDataStream &operator<<(QDataStream &out, const DavItem &item);
+KPIMKDAV_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..98495a6
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+    Copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
+
+    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.
+*/
+
+#include "davitemcreatejob.h"
+
+#include "davitemfetchjob.h"
+#include "davmanager.h"
+#include "daverror.h"
+
+#include <KIO/DavJob>
+#include <KIO/Job>
+
+#include "libkdav_debug.h"
+
+using namespace KDAV;
+
+DavItemCreateJob::DavItemCreateJob(const DavItem &item, QObject *parent)
+    : DavJobBase(parent)
+    , mItem(item)
+    , mRedirectCount(0)
+{
+}
+
+void DavItemCreateJob::start()
+{
+    QString headers = QStringLiteral("Content-Type: ");
+    headers += mItem.contentType();
+    headers += QLatin1String("\r\n");
+    headers += QLatin1String("If-None-Match: *");
+
+    KIO::StoredTransferJob *job = KIO::storedPut(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, &DavItemCreateJob::davJobFinished);
+}
+
+DavItem DavItemCreateJob::item() const
+{
+    return mItem;
+}
+
+QUrl DavItemCreateJob::itemUrl() const
+{
+    return mItem.url().url();
+}
+
+void DavItemCreateJob::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();
+    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;
+    foreach (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(UserDefinedError + responseCode);
+            emitResult();
+        } else {
+            QUrl _itemUrl(url);
+            _itemUrl.setUserInfo(itemUrl().userInfo());
+            mItem.setUrl(DavUrl(_itemUrl, mItem.url().protocol()));
+
+            ++mRedirectCount;
+            start();
+        }
+
+        return;
+    }
+
+    url.setUserInfo(itemUrl().userInfo());
+    mItem.setUrl(DavUrl(url, mItem.url().protocol()));
+
+    DavItemFetchJob *fetchJob = new DavItemFetchJob(mItem);
+    connect(fetchJob, &DavItemFetchJob::result, this, &DavItemCreateJob::itemRefreshed);
+    fetchJob->start();
+}
+
+void DavItemCreateJob::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..95afb97
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+    Copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
+
+    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.
+*/
+
+#ifndef KDAV_DAVITEMCREATEJOB_H
+#define KDAV_DAVITEMCREATEJOB_H
+
+#include "kpimkdav_export.h"
+
+#include "davitem.h"
+#include "davjobbase.h"
+#include "davurl.h"
+
+namespace KDAV {
+/**
+ * @short A job to create a DAV item on the DAV server.
+ */
+class KPIMKDAV_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.
+     */
+    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:
+    void davJobFinished(KJob *);
+    void itemRefreshed(KJob *);
+    DavItem mItem;
+    int mRedirectCount;
+};
+}
+
+#endif
diff --git a/src/common/davitemdeletejob.cpp b/src/common/davitemdeletejob.cpp
new file mode 100644 (file)
index 0000000..795def8
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+    Copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
+
+    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.
+*/
+
+#include "davitemdeletejob.h"
+
+#include "davitemfetchjob.h"
+#include "davmanager.h"
+#include "daverror.h"
+
+#include <KIO/DeleteJob>
+#include <KIO/Job>
+
+using namespace KDAV;
+
+DavItemDeleteJob::DavItemDeleteJob(const DavItem &item, QObject *parent)
+    : DavJobBase(parent)
+    , mItem(item)
+    , mFreshResponseCode(-1)
+{
+}
+
+void DavItemDeleteJob::start()
+{
+    KIO::DeleteJob *job = KIO::del(mItem.url().url(), KIO::HideProgressInfo | KIO::DefaultFlags);
+    job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true"));
+    job->addMetaData(QStringLiteral("customHTTPHeader"), QStringLiteral("If-Match: ") + mItem.etag());
+    job->addMetaData(QStringLiteral("cookies"), QStringLiteral("none"));
+    job->addMetaData(QStringLiteral("no-auth-prompt"), QStringLiteral("true"));
+
+    connect(job, &KIO::DeleteJob::result, this, &DavItemDeleteJob::davJobFinished);
+}
+
+DavItem DavItemDeleteJob::freshItem() const
+{
+    return mFreshItem;
+}
+
+int DavItemDeleteJob::freshResponseCode() const
+{
+    return mFreshResponseCode;
+}
+
+void DavItemDeleteJob::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 (hasConflict()) {
+            DavItemFetchJob *fetchJob = new DavItemFetchJob(mItem);
+            connect(fetchJob, &DavItemFetchJob::result, this, &DavItemDeleteJob::conflictingItemFetched);
+            fetchJob->start();
+            return;
+        }
+    }
+
+    emitResult();
+}
+
+void DavItemDeleteJob::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..0e8f1bb
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+    Copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
+
+    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.
+*/
+
+#ifndef KDAV_DAVITEMDELETEJOB_H
+#define KDAV_DAVITEMDELETEJOB_H
+
+#include "kpimkdav_export.h"
+
+#include "davitem.h"
+#include "davjobbase.h"
+#include "davurl.h"
+
+namespace KDAV {
+/**
+ * @short A job to delete a DAV item on the DAV server.
+ */
+class KPIMKDAV_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.
+     */
+    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:
+    void davJobFinished(KJob *);
+    void conflictingItemFetched(KJob *);
+    DavItem mItem;
+    DavItem mFreshItem;
+    int mFreshResponseCode;
+};
+}
+
+#endif
diff --git a/src/common/davitemfetchjob.cpp b/src/common/davitemfetchjob.cpp
new file mode 100644 (file)
index 0000000..4a35bf0
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+    Copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
+
+    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.
+*/
+
+#include "davitemfetchjob.h"
+
+#include "davmanager.h"
+#include "daverror.h"
+
+#include <KIO/DavJob>
+#include <KIO/Job>
+
+using namespace KDAV;
+
+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(parent)
+    , mItem(item)
+{
+}
+
+void DavItemFetchJob::start()
+{
+    KIO::StoredTransferJob *job = KIO::storedGet(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, &DavItemFetchJob::davJobFinished);
+}
+
+DavItem DavItemFetchJob::item() const
+{
+    return mItem;
+}
+
+void DavItemFetchJob::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..5d7e980
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+    Copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
+
+    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.
+*/
+
+#ifndef KDAV_DAVITEMFETCHJOB_H
+#define KDAV_DAVITEMFETCHJOB_H
+
+#include "kpimkdav_export.h"
+
+#include "davitem.h"
+#include "davjobbase.h"
+#include "davurl.h"
+
+namespace KDAV {
+/**
+ * @short A job that fetches a DAV item from the DAV server.
+ */
+class KPIMKDAV_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.
+     */
+    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:
+    void davJobFinished(KJob *);
+    DavUrl mUrl;
+    DavItem mItem;
+};
+}
+
+#endif
diff --git a/src/common/davitemmodifyjob.cpp b/src/common/davitemmodifyjob.cpp
new file mode 100644 (file)
index 0000000..e9cf4ea
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+    Copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
+
+    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.
+*/
+
+#include "davitemmodifyjob.h"
+
+#include "davitemfetchjob.h"
+#include "davmanager.h"
+#include "daverror.h"
+
+#include <KIO/Job>
+
+using namespace KDAV;
+
+DavItemModifyJob::DavItemModifyJob(const DavItem &item, QObject *parent)
+    : DavJobBase(parent)
+    , mItem(item)
+    , mFreshResponseCode(0)
+{
+}
+
+void DavItemModifyJob::start()
+{
+    QString headers = QStringLiteral("Content-Type: ");
+    headers += mItem.contentType();
+    headers += QLatin1String("\r\n");
+    headers += QLatin1String("If-Match: ") + mItem.etag();
+
+    KIO::StoredTransferJob *job = KIO::storedPut(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, &DavItemModifyJob::davJobFinished);
+}
+
+DavItem DavItemModifyJob::item() const
+{
+    return mItem;
+}
+
+DavItem DavItemModifyJob::freshItem() const
+{
+    return mFreshItem;
+}
+
+int DavItemModifyJob::freshResponseCode() const
+{
+    return mFreshResponseCode;
+}
+
+QUrl DavItemModifyJob::itemUrl() const
+{
+    return mItem.url().url();
+}
+
+void DavItemModifyJob::davJobFinished(KJob *job)
+{
+    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 (hasConflict()) {
+            DavItemFetchJob *fetchJob = new DavItemFetchJob(mItem);
+            connect(fetchJob, &DavItemFetchJob::result, this, &DavItemModifyJob::conflictingItemFetched);
+            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(itemUrl().userInfo());
+    mItem.setUrl(DavUrl(url, mItem.url().protocol()));
+
+    DavItemFetchJob *fetchJob = new DavItemFetchJob(mItem);
+    connect(fetchJob, &DavItemFetchJob::result, this, &DavItemModifyJob::itemRefreshed);
+    fetchJob->start();
+}
+
+void DavItemModifyJob::itemRefreshed(KJob *job)
+{
+    if (!job->error()) {
+        DavItemFetchJob *fetchJob = qobject_cast<DavItemFetchJob *>(job);
+        mItem.setEtag(fetchJob->item().etag());
+    } else {
+        mItem.setEtag(QString());
+    }
+    emitResult();
+}
+
+void DavItemModifyJob::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..38e3c0b
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+    Copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
+
+    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.
+*/
+
+#ifndef KDAV_DAVITEMMODIFYJOB_H
+#define KDAV_DAVITEMMODIFYJOB_H
+
+#include "kpimkdav_export.h"
+
+#include "davitem.h"
+#include "davjobbase.h"
+#include "davurl.h"
+
+namespace KDAV {
+/**
+ * @short A job that modifies a DAV item on the DAV server.
+ */
+class KPIMKDAV_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.
+     */
+    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:
+    void davJobFinished(KJob *);
+    void itemRefreshed(KJob *);
+    void conflictingItemFetched(KJob *);
+    DavItem mItem;
+    DavItem mFreshItem;
+    int mFreshResponseCode;
+};
+}
+
+#endif
diff --git a/src/common/davitemsfetchjob.cpp b/src/common/davitemsfetchjob.cpp
new file mode 100644 (file)
index 0000000..59f7617
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+    Copyright (c) 2010 Grégory Oestreicher <greg@kamago.net>
+    Based on DavItemsListJob which is copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
+
+    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.
+*/
+
+#include "davitemsfetchjob.h"
+
+#include "davmanager.h"
+#include "davmultigetprotocol.h"
+#include "utils.h"
+#include "daverror.h"
+
+#include <KIO/DavJob>
+#include <KIO/Job>
+
+using namespace KDAV;
+
+DavItemsFetchJob::DavItemsFetchJob(const DavUrl &collectionUrl, const QStringList &urls, QObject *parent)
+    : DavJobBase(parent)
+    , mCollectionUrl(collectionUrl)
+    , mUrls(urls)
+{
+}
+
+void DavItemsFetchJob::start()
+{
+    const DavMultigetProtocol *protocol
+        = dynamic_cast<const DavMultigetProtocol *>(DavManager::self()->davProtocol(mCollectionUrl.protocol()));
+    if (!protocol) {
+        setError(ERR_NO_MULTIGET);
+        setErrorTextFromDavError();
+        emitResult();
+        return;
+    }
+
+    const QDomDocument report = protocol->itemsReportQuery(mUrls)->buildQuery();
+    KIO::DavJob *job = DavManager::self()->createReportJob(mCollectionUrl.url(), report, QStringLiteral("0"));
+    job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true"));
+    connect(job, &KIO::DavJob::result, this, &DavItemsFetchJob::davJobFinished);
+}
+
+DavItem::List DavItemsFetchJob::items() const
+{
+    DavItem::List values;
+    values.reserve(mItems.size());
+    Q_FOREACH (const auto &value, mItems) {
+        values << value;
+    }
+    return values;
+}
+
+DavItem DavItemsFetchJob::item(const QString &url) const
+{
+    return mItems.value(url);
+}
+
+void DavItemsFetchJob::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::self()->davProtocol(mCollectionUrl.protocol()));
+
+    const QDomDocument document = davJob->response();
+    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..25d3117
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+    Copyright (c) 2010 Grégory Oestreicher <greg@kamago.net>
+    Based on DavItemsListJob which is copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
+
+    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.
+*/
+
+#ifndef KDAV_DAVITEMSFETCHJOB_H
+#define KDAV_DAVITEMSFETCHJOB_H
+
+#include "kpimkdav_export.h"
+
+#include "davitem.h"
+#include "davjobbase.h"
+#include "davurl.h"
+
+#include <QMap>
+#include <QStringList>
+
+namespace KDAV {
+/**
+ * @short A job that fetches a list of items from a DAV server using a multiget query.
+ */
+class KPIMKDAV_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:
+    void davJobFinished(KJob *);
+    DavUrl mCollectionUrl;
+    QStringList mUrls;
+    QMap<QString, DavItem> mItems;
+};
+}
+
+#endif
diff --git a/src/common/davitemslistjob.cpp b/src/common/davitemslistjob.cpp
new file mode 100644 (file)
index 0000000..41f3153
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+    Copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
+
+    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.
+*/
+
+#include "davitemslistjob.h"
+
+#include "daverror.h"
+#include "davmanager.h"
+#include "davprotocolbase.h"
+#include "davurl.h"
+#include "utils.h"
+#include "etagcache.h"
+
+#include <KIO/DavJob>
+#include <KIO/Job>
+
+using namespace KDAV;
+
+class DavItemsListJobPrivate
+{
+public:
+    DavItemsListJobPrivate(const DavUrl &url, const std::shared_ptr<EtagCache> &cache);
+
+    DavUrl mUrl;
+    std::shared_ptr<EtagCache> mEtagCache;
+    QStringList mMimeTypes;
+    QString mRangeStart;
+    QString mRangeEnd;
+    DavItem::List mItems;
+    QSet<QString> mSeenUrls; // to prevent events duplication with some servers
+    DavItem::List mChangedItems;
+    QStringList mDeletedItems;
+    uint mSubJobCount;
+};
+
+DavItemsListJobPrivate::DavItemsListJobPrivate(const DavUrl &url, const std::shared_ptr<EtagCache> &cache)
+    : mUrl(url)
+    , mEtagCache(cache)
+    , mSubJobCount(0)
+{
+}
+
+DavItemsListJob::DavItemsListJob(const DavUrl &url, const std::shared_ptr<EtagCache> &cache, QObject *parent)
+    : DavJobBase(parent)
+    , d(std::unique_ptr<DavItemsListJobPrivate>(new DavItemsListJobPrivate(url, cache)))
+{
+}
+
+DavItemsListJob::~DavItemsListJob()
+{
+}
+
+void DavItemsListJob::setContentMimeTypes(const QStringList &types)
+{
+    d->mMimeTypes = types;
+}
+
+void DavItemsListJob::setTimeRange(const QString &start, const QString &end)
+{
+    d->mRangeStart = start;
+    d->mRangeEnd = end;
+}
+
+void DavItemsListJob::start()
+{
+    const DavProtocolBase *protocol = DavManager::self()->davProtocol(d->mUrl.protocol());
+    Q_ASSERT(protocol);
+    QVectorIterator<XMLQueryBuilder::Ptr> it(protocol->itemsQueries());
+
+    while (it.hasNext()) {
+        XMLQueryBuilder::Ptr builder = it.next();
+        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);
+                job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true"));
+                job->setProperty("davType", QStringLiteral("report"));
+                job->setProperty("itemsMimeType", mimeType);
+                connect(job, &KIO::DavJob::result, this, &DavItemsListJob::davJobFinished);
+            } else {
+                KIO::DavJob *job = DavManager::self()->createPropFindJob(d->mUrl.url(), props);
+                job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true"));
+                job->setProperty("davType", QStringLiteral("propFind"));
+                job->setProperty("itemsMimeType", mimeType);
+                connect(job, &KIO::DavJob::result, this, &DavItemsListJob::davJobFinished);
+            }
+        }
+    }
+
+    if (d->mSubJobCount == 0) {
+        setError(ERR_ITEMLIST_NOMIMETYPE);
+        setErrorTextFromDavError();
+        emitResult();
+    }
+}
+
+DavItem::List DavItemsListJob::items() const
+{
+    return d->mItems;
+}
+
+DavItem::List DavItemsListJob::changedItems() const
+{
+    return d->mChangedItems;
+}
+
+QStringList DavItemsListJob::deletedItems() const
+{
+    return d->mDeletedItems;
+}
+
+void DavItemsListJob::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();
+        const QDomDocument document = davJob->response();
+        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 (!responseElement.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);
+            }
+
+            QString itemUrl = url.toDisplayString();
+            if (d->mSeenUrls.contains(itemUrl)) {
+                responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response"));
+                continue;
+            }
+
+            d->mSeenUrls << itemUrl;
+            auto _url = url;
+            _url.setUserInfo(d->mUrl.url().userInfo());
+            item.setUrl(DavUrl(_url, d->mUrl.protocol()));
+
+            // extract etag
+            const QDomElement getetagElement = Utils::firstChildElementNS(propElement, QStringLiteral("DAV:"), QStringLiteral("getetag"));
+
+            item.setEtag(getetagElement.text());
+
+            d->mItems << item;
+
+            if (d->mEtagCache->etagChanged(itemUrl, item.etag())) {
+                d->mChangedItems << item;
+            }
+
+            responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response"));
+        }
+    }
+
+    QSet<QString> removed = d->mEtagCache->urls().toSet();
+    removed.subtract(d->mSeenUrls);
+    d->mDeletedItems = removed.toList();
+
+    if (--d->mSubJobCount == 0) {
+        emitResult();
+    }
+}
diff --git a/src/common/davitemslistjob.h b/src/common/davitemslistjob.h
new file mode 100644 (file)
index 0000000..7b89e82
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+    Copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
+
+    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.
+*/
+
+#ifndef KDAV_DAVITEMSLISTJOB_H
+#define KDAV_DAVITEMSLISTJOB_H
+
+#include "kpimkdav_export.h"
+
+#include "davitem.h"
+#include "davjobbase.h"
+
+#include <memory>
+
+#include <QStringList>
+
+class DavItemsListJobPrivate;
+
+namespace KDAV {
+class EtagCache;
+class DavUrl;
+
+/**
+ * @short A job that lists all DAV items inside a DAV collection.
+ */
+class KPIMKDAV_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:
+    void davJobFinished(KJob *);
+    std::unique_ptr<DavItemsListJobPrivate> d;
+};
+}
+
+#endif
diff --git a/src/common/davjobbase.cpp b/src/common/davjobbase.cpp
new file mode 100644 (file)
index 0000000..e93ec64
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+    Copyright (c) 2014 Gregory Oestreicher <greg@kamago.net>
+
+    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.
+*/
+
+#include "davjobbase.h"
+
+#include "daverror.h"
+
+using namespace KDAV;
+
+class DavJobBasePrivate
+{
+public:
+    DavJobBasePrivate();
+
+    int mLatestResponseCode = 0;
+    int mJobErrorCode = 0;
+    QString mInternalErrorText;
+};
+
+DavJobBasePrivate::DavJobBasePrivate()
+{
+}
+
+DavJobBase::DavJobBase(QObject *parent)
+    : KJob(parent)
+    , d(std::unique_ptr<DavJobBasePrivate>(new DavJobBasePrivate()))
+{
+}
+
+DavJobBase::~DavJobBase()
+{
+}
+
+int DavJobBase::latestResponseCode() const
+{
+    return d->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 DavJobBase::setLatestResponseCode(int code)
+{
+    d->mLatestResponseCode = code;
+}
+
+Error DavJobBase::davError() const
+{
+    return Error(static_cast<KDAV::ErrorNumber>(error()), d->mLatestResponseCode, d->mInternalErrorText, d->mJobErrorCode);
+}
+
+void DavJobBase::setJobErrorText(const QString &errorText)
+{
+    d->mInternalErrorText = errorText;
+}
+
+void DavJobBase::setJobError(int jobErrorCode)
+{
+    d->mJobErrorCode = jobErrorCode;
+}
+
+void DavJobBase::setErrorTextFromDavError()
+{
+    setErrorText(davError().errorText());
+}
+
+void DavJobBase::setDavError(const Error &error)
+{
+    setError(error.errorNumber());
+    setLatestResponseCode(error.responseCode());
+    setJobErrorText(error.internalErrorText());
+    setJobError(error.jobErrorCode());
+}
diff --git a/src/common/davjobbase.h b/src/common/davjobbase.h
new file mode 100644 (file)
index 0000000..2fd8e16
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+    Copyright (c) 2014 Gregory Oestreicher <greg@kamago.net>
+
+    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.
+*/
+
+#ifndef KDAV_DAVJOBBASE_H
+#define KDAV_DAVJOBBASE_H
+
+#include <memory>
+
+#include "kpimkdav_export.h"
+
+#include <KJob>
+
+class DavJobBasePrivate;
+
+namespace KDAV {
+class Error;
+
+/**
+ * @short base class for the jobs used by the resource.
+ */
+class KPIMKDAV_EXPORT DavJobBase : public KJob
+{
+    Q_OBJECT
+
+public:
+    explicit DavJobBase(QObject *parent = nullptr);
+    ~DavJobBase();
+
+    /**
+     * 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:
+    /**
+     * 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);
+private:
+    std::unique_ptr<DavJobBasePrivate> d;
+};
+}
+
+#endif
diff --git a/src/common/davmanager.cpp b/src/common/davmanager.cpp
new file mode 100644 (file)
index 0000000..11cc145
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+    Copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
+
+    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.
+*/
+
+#include "davmanager.h"
+
+#include "protocols/caldavprotocol.h"
+#include "protocols/carddavprotocol.h"
+#include "protocols/groupdavprotocol.h"
+
+#include <KIO/DavJob>
+
+#include "libkdav_debug.h"
+
+#include <QUrl>
+#include <QDomDocument>
+
+using namespace KDAV;
+
+DavManager *DavManager::mSelf = nullptr;
+
+DavManager::DavManager()
+{
+}
+
+DavManager::~DavManager()
+{
+    QMapIterator<Protocol, DavProtocolBase *> it(mProtocols);
+    while (it.hasNext()) {
+        it.next();
+        delete it.value();
+    }
+}
+
+DavManager *DavManager::self()
+{
+    if (!mSelf) {
+        mSelf = new DavManager();
+    }
+
+    return mSelf;
+}
+
+KIO::DavJob *DavManager::createPropFindJob(const QUrl &url, const QDomDocument &document, const QString &depth) const
+{
+    KIO::DavJob *job = KIO::davPropFind(url, document, depth, KIO::HideProgressInfo | KIO::DefaultFlags);
+
+    // workaround needed, Depth: header doesn't seem to be correctly added
+    const QString header = QLatin1String("Content-Type: text/xml\r\nDepth: ") + depth;
+    job->addMetaData(QStringLiteral("customHTTPHeader"), header);
+    job->addMetaData(QStringLiteral("cookies"), QStringLiteral("none"));
+    job->addMetaData(QStringLiteral("no-auth-prompt"), QStringLiteral("true"));
+    job->setProperty("extraDavDepth", QVariant::fromValue(depth));
+
+    return job;
+}
+
+KIO::DavJob *DavManager::createReportJob(const QUrl &url, const QDomDocument &document, const QString &depth) const
+{
+    KIO::DavJob *job = KIO::davReport(url, document.toString(), depth, KIO::HideProgressInfo | KIO::DefaultFlags);
+
+    // workaround needed, Depth: header doesn't seem to be correctly added
+    const QString header = QLatin1String("Content-Type: text/xml\r\nDepth: ") + depth;
+    job->addMetaData(QStringLiteral("customHTTPHeader"), header);
+    job->addMetaData(QStringLiteral("cookies"), QStringLiteral("none"));
+    job->addMetaData(QStringLiteral("no-auth-prompt"), QStringLiteral("true"));
+    job->setProperty("extraDavDepth", QVariant::fromValue(depth));
+
+    return job;
+}
+
+KIO::DavJob *DavManager::createPropPatchJob(const QUrl &url, const QDomDocument &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)
+{
+    if (createProtocol(protocol)) {
+        return mProtocols[ protocol ];
+    } else {
+        return nullptr;
+    }
+}
+
+bool DavManager::createProtocol(Protocol protocol)
+{
+    if (mProtocols.contains(protocol)) {
+        return true;
+    }
+
+    switch (protocol) {
+    case KDAV::CalDav:
+        mProtocols.insert(KDAV::CalDav, new CaldavProtocol());
+        return true;
+    case KDAV::CardDav:
+        mProtocols.insert(KDAV::CardDav, new CarddavProtocol());
+        return true;
+    case KDAV::GroupDav:
+        mProtocols.insert(KDAV::GroupDav, new GroupdavProtocol());
+        return true;
+    }
+    qCCritical(KDAV_LOG) << "Unknown protocol: " << static_cast<int>(protocol);
+    return false;
+}
diff --git a/src/common/davmanager.h b/src/common/davmanager.h
new file mode 100644 (file)
index 0000000..b42f263
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+    Copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
+
+    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.
+*/
+
+#ifndef KDAV_DAVMANAGER_H
+#define KDAV_DAVMANAGER_H
+
+#include "kpimkdav_export.h"
+
+#include "enums.h"
+
+#include <QMap>
+#include <QString>
+
+namespace KIO {
+class DavJob;
+}
+
+class QUrl;
+
+class QDomDocument;
+
+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 KPIMKDAV_EXPORT 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 QDomDocument &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 QDomDocument &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 QDomDocument &document) const;
+
+    /**
+     * Returns the DAV protocol dialect object for the given DAV @p protocol.
+     */
+    const DavProtocolBase *davProtocol(Protocol protocol);
+
+private:
+    /**
+     * Creates a new DAV manager.
+     */
+    DavManager();
+
+    /**
+     * Creates a new protocol.
+     */
+    bool createProtocol(Protocol protocol);
+
+    typedef QMap<Protocol, DavProtocolBase *> protocolsMap;
+    protocolsMap mProtocols;
+    static DavManager *mSelf;
+};
+}
+
+#endif
diff --git a/src/common/davmultigetprotocol.cpp b/src/common/davmultigetprotocol.cpp
new file mode 100644 (file)
index 0000000..0704b5d
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+    Copyright (c) 2010 Grégory Oestreicher <greg@kamago.net>
+
+    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.
+*/
+
+#include "davmultigetprotocol.h"
+
+using namespace KDAV;
+
+DavMultigetProtocol::~DavMultigetProtocol()
+{
+}
diff --git a/src/common/davmultigetprotocol.h b/src/common/davmultigetprotocol.h
new file mode 100644 (file)
index 0000000..240b4f8
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+    Copyright (c) 2010 Grégory Oestreicher <greg@kamago.net>
+
+    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.
+*/
+
+#ifndef KDAV_DAVMULTIGETPROTOCOL_H
+#define KDAV_DAVMULTIGETPROTOCOL_H
+
+#include "kpimkdav_export.h"
+
+#include "davprotocolbase.h"
+
+namespace KDAV {
+/**
+ * @short Base class for protocols that implement multiget capabilities
+ */
+class KPIMKDAV_EXPORT DavMultigetProtocol : public DavProtocolBase
+{
+public:
+    /**
+     * Destroys the DAV protocol
+     */
+    virtual ~DavMultigetProtocol();
+
+    /**
+     * 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..95e6377
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+    Copyright (c) 2010 Grégory Oestreicher <greg@kamago.net>
+
+    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.
+*/
+
+#include "davprincipalhomesetsfetchjob.h"
+
+#include "davmanager.h"
+#include "davprotocolbase.h"
+#include "daverror.h"
+#include "utils.h"
+
+#include <KIO/DavJob>
+#include <KIO/Job>
+
+using namespace KDAV;
+
+DavPrincipalHomeSetsFetchJob::DavPrincipalHomeSetsFetchJob(const DavUrl &url, QObject *parent)
+    : DavJobBase(parent)
+    , mUrl(url)
+{
+}
+
+void DavPrincipalHomeSetsFetchJob::start()
+{
+    fetchHomeSets(false);
+}
+
+void DavPrincipalHomeSetsFetchJob::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 = DavManager::self()->davProtocol(mUrl.protocol())->principalHomeSet();
+    const QString homeSetNS = DavManager::self()->davProtocol(mUrl.protocol())->principalHomeSetNS();
+    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, QStringLiteral("0"));
+    job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true"));
+    connect(job, &KIO::DavJob::result, this, &DavPrincipalHomeSetsFetchJob::davJobFinished);
+}
+
+QStringList DavPrincipalHomeSetsFetchJob::homeSets() const
+{
+    return mHomeSets;
+}
+
+void DavPrincipalHomeSetsFetchJob::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_SLAVE_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 = DavManager::self()->davProtocol(mUrl.protocol())->principalHomeSet();
+    const QString homeSetNS = DavManager::self()->davProtocol(mUrl.protocol())->principalHomeSetNS();
+    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.
+
+    const QDomDocument document = davJob->response();
+    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..6e95177
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+    Copyright (c) 2010 Grégory Oestreicher <greg@kamago.net>
+
+    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.
+*/
+
+#ifndef KDAV_DAVPRINCIPALHOMESETSFETCHJOB_H
+#define KDAV_DAVPRINCIPALHOMESETSFETCHJOB_H
+
+#include "kpimkdav_export.h"
+
+#include "davjobbase.h"
+#include "davurl.h"
+
+#include <KJob>
+
+#include <QStringList>
+
+namespace KDAV {
+/**
+ * @short A job that fetches home sets for a principal.
+ */
+class KPIMKDAV_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:
+    void davJobFinished(KJob *);
+    /**
+     * 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;
+};
+}
+
+#endif
diff --git a/src/common/davprincipalsearchjob.cpp b/src/common/davprincipalsearchjob.cpp
new file mode 100644 (file)
index 0000000..97d4e8b
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+    Copyright (c) 2011 Grégory Oestreicher <greg@kamago.net>
+
+    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.
+*/
+
+#include "davprincipalsearchjob.h"
+
+#include "davmanager.h"
+#include "utils.h"
+#include "daverror.h"
+
+#include <KIO/Job>
+#include <KIO/DavJob>
+
+#include <QUrl>
+
+using namespace KDAV;
+
+DavPrincipalSearchJob::DavPrincipalSearchJob(const DavUrl &url, DavPrincipalSearchJob::FilterType type, const QString &filter, QObject *parent)
+    : DavJobBase(parent)
+    , mUrl(url)
+    , mType(type)
+    , mFilter(filter)
+    , mPrincipalPropertySearchSubJobCount(0)
+    , mPrincipalPropertySearchSubJobSuccessful(false)
+{
+}
+
+void DavPrincipalSearchJob::fetchProperty(const QString &name, const QString &ns)
+{
+    QString propNamespace = ns;
+    if (propNamespace.isEmpty()) {
+        propNamespace = QStringLiteral("DAV:");
+    }
+
+    mFetchProperties << QPair<QString, QString>(propNamespace, name);
+}
+
+DavUrl DavPrincipalSearchJob::davUrl() const
+{
+    return mUrl;
+}
+
+void DavPrincipalSearchJob::start()
+{
+    /*
+     * 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(mUrl.url(), query);
+    job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true"));
+    connect(job, &KIO::DavJob::result, this, &DavPrincipalSearchJob::principalCollectionSetSearchFinished);
+    job->start();
+}
+
+void DavPrincipalSearchJob::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 = davJob->response();
+    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);
+        reportJob->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true"));
+        connect(reportJob, &KIO::DavJob::result, this, &DavPrincipalSearchJob::principalPropertySearchFinished);
+        ++mPrincipalPropertySearchSubJobCount;
+        reportJob->start();
+    }
+}
+
+void DavPrincipalSearchJob::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>
+    */
+
+    const QDomDocument document = davJob->response();
+    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
+    typedef QPair<QString, QString> PropertyPair;
+    foreach (const PropertyPair &fetchProperty, mFetchProperties) {
+        QDomNodeList fetchNodes = propElement.elementsByTagNameNS(fetchProperty.first, fetchProperty.second);
+        for (int i = 0; i < fetchNodes.size(); ++i) {
+            QDomElement fetchElement = fetchNodes.at(i).toElement();
+            Result result;
+            result.propertyNamespace = fetchProperty.first;
+            result.property = fetchProperty.second;
+            result.value = fetchElement.text();
+            mResults << result;
+        }
+    }
+
+    if (mPrincipalPropertySearchSubJobCount == 0) {
+        emitResult();
+    }
+}
+
+QVector< DavPrincipalSearchJob::Result > DavPrincipalSearchJob::results() const
+{
+    return mResults;
+}
+
+void DavPrincipalSearchJob::buildReportQuery(QDomDocument &query)
+{
+    /*
+     * 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 == DisplayName) {
+        QDomElement displayName = query.createElementNS(QStringLiteral("DAV:"), QStringLiteral("displayname"));
+        prop.appendChild(displayName);
+    } else if (mType == 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);
+
+    typedef QPair<QString, QString> PropertyPair;
+    foreach (const PropertyPair &fetchProperty, mFetchProperties) {
+        QDomElement elem = query.createElementNS(fetchProperty.first, fetchProperty.second);
+        prop.appendChild(elem);
+    }
+}
diff --git a/src/common/davprincipalsearchjob.h b/src/common/davprincipalsearchjob.h
new file mode 100644 (file)
index 0000000..2688fc2
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+    Copyright (c) 2011 Grégory Oestreicher <greg@kamago.net>
+
+    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.
+*/
+
+#ifndef KDAV_DAVPRINCIPALSEARCHJOB_H
+#define KDAV_DAVPRINCIPALSEARCHJOB_H
+
+#include "kpimkdav_export.h"
+
+#include "davjobbase.h"
+#include "davurl.h"
+
+#include <QList>
+#include <QPair>
+#include <QString>
+
+#include <KJob>
+
+class QDomDocument;
+
+namespace KDAV {
+/**
+ * @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 KPIMKDAV_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:
+    void principalCollectionSetSearchFinished(KJob *job);
+    void principalPropertySearchFinished(KJob *job);
+    void buildReportQuery(QDomDocument &query);
+
+private:
+    DavUrl mUrl;
+    FilterType mType;
+    QString mFilter;
+    int mPrincipalPropertySearchSubJobCount;
+    bool mPrincipalPropertySearchSubJobSuccessful;
+    QList< QPair<QString, QString> > mFetchProperties;
+    QVector<Result> mResults;
+};
+}
+
+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..fdee204
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+    Copyright (c) 2009 Grégory Oestreicher <greg@kamago.net>
+
+    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.
+*/
+
+#include "davprotocolbase.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.h b/src/common/davprotocolbase.h
new file mode 100644 (file)
index 0000000..a0dc77f
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+    Copyright (c) 2009 Grégory Oestreicher <greg@kamago.net>
+
+    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.
+*/
+
+#ifndef KDAV_DAVPROTOCOLBASE_H
+#define KDAV_DAVPROTOCOLBASE_H
+
+#include "kpimkdav_export.h"
+
+#include "davcollection.h"
+
+#include <QMap>
+#include <QDomDocument>
+#include <QSharedPointer>
+#include <QVariant>
+
+namespace KDAV {
+/**
+ * @short Base class for XML query builders
+ */
+class KPIMKDAV_EXPORT XMLQueryBuilder
+{
+public:
+    typedef QSharedPointer<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 KPIMKDAV_EXPORT 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 ResourceBase::retrieveItems() already and
+     * there is no need to call 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 the XQuery string that filters out the relevant XML elements
+     * from the result returned by the query that is provided by collectionQuery().
+     */
+    virtual QString collectionsXQuery() 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..3d7eee4
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+    Copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
+
+    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.
+*/
+
+#include "davurl.h"
+
+#include "enums.h"
+
+using namespace KDAV;
+
+DavUrl::DavUrl()
+    : mProtocol(KDAV::CalDav)
+{
+}
+
+DavUrl::DavUrl(const QUrl &url, Protocol protocol)
+    : mUrl(url)
+    , mProtocol(protocol)
+{
+}
+
+void DavUrl::setUrl(const QUrl &url)
+{
+    mUrl = url;
+}
+
+QUrl DavUrl::url() const
+{
+    return mUrl;
+}
+
+void DavUrl::setProtocol(Protocol protocol)
+{
+    mProtocol = protocol;
+}
+
+Protocol DavUrl::protocol() const
+{
+    return mProtocol;
+}
+
+QString DavUrl::toDisplayString() const
+{
+    auto url = 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..4971fb2
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+    Copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
+
+    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.
+*/
+
+#ifndef KDAV_DAVURL_H
+#define KDAV_DAVURL_H
+
+#include "kpimkdav_export.h"
+
+#include "enums.h"
+
+#include <QUrl>
+#include <QVector>
+
+namespace KDAV {
+/**
+ * @short A helper class to combine url and protocol of a DAV url.
+ */
+class KPIMKDAV_EXPORT DavUrl
+{
+public:
+    /**
+     * Defines a list of DAV url objects.
+     */
+    typedef QVector<DavUrl> List;
+
+    /**
+     * Creates an empty DAV url.
+     */
+    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 userfriendly way without login informations.
+     */
+    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:
+    QUrl mUrl;
+    Protocol mProtocol;
+};
+
+KPIMKDAV_EXPORT QDataStream &operator<<(QDataStream &out, const DavUrl &url);
+KPIMKDAV_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..2344c40
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+    Copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
+
+    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.
+*/
+
+#ifndef KDAV_ENUMS_H
+#define KDAV_ENUMS_H
+
+#include <QFlags>
+
+namespace KDAV {
+/**
+ * Describes the DAV protocol dialect.
+ */
+enum Protocol {
+    CalDav = 0,   ///< The CalDav protocol as defined in http://caldav.calconnect.org
+    CardDav,      ///< The CardDav protocol as defined in http://carddav.calconnect.org
+    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..f88f218
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+    Copyright (c) 2010 Grégory Oestreicher <greg@kamago.net>
+
+    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.
+*/
+
+#include "etagcache.h"
+
+using namespace KDAV;
+
+EtagCache::EtagCache(QObject *parent)
+    : QObject(parent)
+{
+}
+
+void EtagCache::setEtag(const QString &remoteId, const QString &etag)
+{
+    setEtagInternal(remoteId, etag);
+
+    if (mChangedRemoteIds.contains(remoteId)) {
+        mChangedRemoteIds.remove(remoteId);
+    }
+}
+
+void EtagCache::setEtagInternal(const QString &remoteId, const QString &etag)
+{
+    mCache[ remoteId ] = etag;
+}
+
+bool EtagCache::contains(const QString &remoteId) const
+{
+    return mCache.contains(remoteId);
+}
+
+bool EtagCache::etagChanged(const QString &remoteId, const QString &refEtag) const
+{
+    if (!contains(remoteId)) {
+        return true;
+    }
+    return mCache.value(remoteId) != refEtag;
+}
+
+void EtagCache::markAsChanged(const QString &remoteId)
+{
+    mChangedRemoteIds.insert(remoteId);
+}
+
+bool EtagCache::isOutOfDate(const QString &remoteId) const
+{
+    return mChangedRemoteIds.contains(remoteId);
+}
+
+void EtagCache::removeEtag(const QString &remoteId)
+{
+    mChangedRemoteIds.remove(remoteId);
+    mCache.remove(remoteId);
+}
+
+QStringList EtagCache::urls() const
+{
+    return mCache.keys();
+}
+
+QStringList EtagCache::changedRemoteIds() const
+{
+    return mChangedRemoteIds.toList();
+}
diff --git a/src/common/etagcache.h b/src/common/etagcache.h
new file mode 100644 (file)
index 0000000..7e9a26c
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+    Copyright (c) 2010 Grégory Oestreicher <greg@kamago.net>
+
+    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.
+*/
+
+#ifndef KDAV_ETAGCACHE_H
+#define KDAV_ETAGCACHE_H
+
+#include "kpimkdav_export.h"
+
+#include <QMap>
+#include <QObject>
+#include <QSet>
+#include <QStringList>
+
+namespace KDAV {
+/**
+ * @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 ResourceBase::retrieveItems()
+ */
+class KPIMKDAV_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);
+
+    /**
+     * 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:
+    QMap<QString, QString> mCache;
+    QSet<QString> mChangedRemoteIds;
+};
+}
+
+#endif
diff --git a/src/common/utils.cpp b/src/common/utils.cpp
new file mode 100644 (file)
index 0000000..5daa284
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+    Copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
+
+    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.
+*/
+
+#include "utils.h"
+
+#include "enums.h"
+
+#include "davitem.h"
+#include "davmanager.h"
+#include "davprotocolbase.h"
+
+#include <QDateTime>
+#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;
+}
+
+QLatin1String Utils::protocolName(Protocol protocol)
+{
+    QLatin1String protocolName("");
+
+    switch (protocol) {
+    case KDAV::CalDav:
+        protocolName = QLatin1String("CalDav");
+        break;
+    case KDAV::CardDav:
+        protocolName = QLatin1String("CardDav");
+        break;
+    case KDAV::GroupDav:
+        protocolName = QLatin1String("GroupDav");
+        break;
+    }
+
+    return protocolName;
+}
+
+Protocol Utils::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 Utils::createUniqueId()
+{
+    const qint64 time = QDateTime::currentMSecsSinceEpoch() / 1000;
+    const int r = qrand() % 1000;
+    const QString id = QLatin1Char('R') + QString::number(r);
+    const QString uid = QString::number(time) + QLatin1Char('.') + id;
+    return uid;
+}
+
+QString Utils::contactsMimeType(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/utils.h b/src/common/utils.h
new file mode 100644 (file)
index 0000000..2adf266
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+    Copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
+
+    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.
+*/
+
+#ifndef KDAV_DAVUTILS_H
+#define KDAV_DAVUTILS_H
+
+#include "kpimkdav_export.h"
+
+#include "enums.h"
+
+#include <QDomElement>
+
+namespace KDAV {
+/**
+ * @short A namespace that contains helper methods for DAV functionality.
+ */
+namespace Utils {
+/**
+ * Returns the untranslated name of the given DAV @p protocol dialect.
+ */
+Q_REQUIRED_RESULT QLatin1String KPIMKDAV_EXPORT protocolName(Protocol protocol);
+
+/**
+ * Returns the protocol matching the given name. This is the opposite of
+ * Utils::protocolName().
+ */
+Protocol KPIMKDAV_EXPORT protocolByName(const QString &name);
+
+/**
+ * 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 KPIMKDAV_EXPORT 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 KPIMKDAV_EXPORT 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 KPIMKDAV_EXPORT extractPrivileges(const QDomElement &element);
+
+/**
+ * Parses a single <privilege/> tag and returns the final Privileges.
+ */
+Q_REQUIRED_RESULT Privileges KPIMKDAV_EXPORT parsePrivilege(const QDomElement &element);
+
+/**
+ * Creates a unique identifier that can be used as a file name to upload the dav item
+ */
+Q_REQUIRED_RESULT QString KPIMKDAV_EXPORT createUniqueId();
+
+/**
+ * Returns the mimetype that shall be used for contact DAV resources using @p protocol.
+ */
+Q_REQUIRED_RESULT QString KPIMKDAV_EXPORT contactsMimeType(Protocol protocol);
+}
+}
+
+#endif
diff --git a/src/protocols/caldavprotocol.cpp b/src/protocols/caldavprotocol.cpp
new file mode 100644 (file)
index 0000000..0c0c222
--- /dev/null
@@ -0,0 +1,422 @@
+/*
+    Copyright (c) 2009 Grégory Oestreicher <greg@kamago.net>
+
+    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.
+*/
+
+#include "caldavprotocol.h"
+#include "common/utils.h"
+
+#include <QStringList>
+#include <QUrl>
+#include <QDomDocument>
+
+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.toString());
+            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());
+}
+
+QString CaldavProtocol::collectionsXQuery() const
+{
+    //const QString query( "//*[local-name()='calendar' and namespace-uri()='urn:ietf:params:xml:ns:caldav']/ancestor::*[local-name()='prop' and namespace-uri()='DAV:']/*[local-name()='supported-calendar-component-set' and namespace-uri()='urn:ietf:params:xml:ns:caldav']/*[local-name()='comp' and namespace-uri()='urn:ietf:params:xml:ns:caldav' and (@name='VTODO' or @name='VEVENT')]/ancestor::*[local-name()='response' and namespace-uri()='DAV:']" );
+    const QString query(QStringLiteral(
+                            "//*[local-name()='calendar' and namespace-uri()='urn:ietf:params:xml:ns:caldav']/ancestor::*[local-name()='prop' and namespace-uri()='DAV:']/ancestor::*[local-name()='response' and namespace-uri()='DAV:']"));
+
+    return query;
+}
+
+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.h b/src/protocols/caldavprotocol.h
new file mode 100644 (file)
index 0000000..7fda826
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+    Copyright (c) 2009 Grégory Oestreicher <greg@kamago.net>
+
+    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.
+*/
+
+#ifndef KDAV_CALDAVPROTOCOL_H
+#define KDAV_CALDAVPROTOCOL_H
+
+#include "common/davmultigetprotocol.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 QString collectionsXQuery() 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..9449ace
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+    Copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
+
+    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.
+*/
+
+#include "carddavprotocol.h"
+
+#include <QStringList>
+#include <QUrl>
+#include <QDomDocument>
+
+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());
+}
+
+QString CarddavProtocol::collectionsXQuery() const
+{
+    const QString query(QStringLiteral("//*[local-name()='addressbook' and namespace-uri()='urn:ietf:params:xml:ns:carddav']/ancestor::*[local-name()='response' and namespace-uri()='DAV:']"));
+
+    return query;
+}
+
+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.h b/src/protocols/carddavprotocol.h
new file mode 100644 (file)
index 0000000..1eaf98a
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+    Copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
+
+    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.
+*/
+
+#ifndef KDAV_CARDDAVPROTOCOL_H
+#define KDAV_CARDDAVPROTOCOL_H
+
+#include "common/davmultigetprotocol.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 QString collectionsXQuery() 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..5294398
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+    Copyright (c) 2009 Grégory Oestreicher <greg@kamago.net>
+
+    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.
+*/
+
+#include "groupdavprotocol.h"
+
+#include "common/utils.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());
+}
+
+QString GroupdavProtocol::collectionsXQuery() const
+{
+    const QString query(QStringLiteral(
+                            "//*[(local-name()='vevent-collection' or local-name()='vtodo-collection' or local-name()='vcard-collection') and namespace-uri()='http://groupdav.org/']/ancestor::*[local-name()='response' and namespace-uri()='DAV:']"));
+
+    return query;
+}
+
+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.h b/src/protocols/groupdavprotocol.h
new file mode 100644 (file)
index 0000000..e89ad9f
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+    Copyright (c) 2009 Grégory Oestreicher <greg@kamago.net>
+
+    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.
+*/
+
+#ifndef GROUPDAVPROTOCOL_H
+#define GROUPDAVPROTOCOL_H
+
+#include "common/davprotocolbase.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 QString collectionsXQuery() 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..d91c4f7
--- /dev/null
@@ -0,0 +1,15 @@
+kde_enable_exceptions()
+set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR})
+
+set(testserver_SRCS
+  testserver.cpp
+)
+
+add_executable(testserver ${testserver_SRCS})
+
+target_link_libraries(testserver
+    Qt5::Core
+    KPim::KDAV
+    Qt5::Xml
+    )
+
diff --git a/test/testserver.cpp b/test/testserver.cpp
new file mode 100644 (file)
index 0000000..8043665
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+  Copyright (c) 2016 Sandro Knauß <sknauss@kde.org>
+
+  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.
+*/
+
+#include <KDAV/Utils>
+#include <KDAV/DavCollectionDeleteJob>
+#include <KDAV/DavCollectionModifyJob>
+#include <KDAV/DavCollectionsFetchJob>
+#include <KDAV/DavItemFetchJob>
+#include <KDAV/DavItemCreateJob>
+#include <KDAV/DavItemsFetchJob>
+#include <KDAV/DavItemModifyJob>
+#include <KDAV/DavItemDeleteJob>
+#include <KDAV/DavItemsListJob>
+#include <KDAV/EtagCache>
+#include <KDAV/Utils>
+
+#include <QDebug>
+#include <QStringList>
+#include <QCoreApplication>
+
+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();
+
+    foreach(const auto collection, job->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();
+            foreach(const auto item, itemListJob->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() != QStringLiteral("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();
+        }
+    }
+}