--- /dev/null
+{
+ "phabricator.uri": "https://phabricator.kde.org/project/profile/34/"
+}
--- /dev/null
+# Ignore the following files
+/build/
+CMakeLists.txt.user*
+*.unc-backup*
--- /dev/null
+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)
--- /dev/null
+ 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.
--- /dev/null
+@PACKAGE_INIT@
+
+include(CMakeFindDependencyMacro)
+find_dependency(KF5CoreAddons "@KF5_VERSION@")
+
+include("${CMAKE_CURRENT_LIST_DIR}/KPimKDAVTargets.cmake")
--- /dev/null
+==== 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.
--- /dev/null
+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
+)
--- /dev/null
+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
--- /dev/null
+/*
+ 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)
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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)
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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)
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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)
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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)
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+org.kde.pim.kdav KDAV
--- /dev/null
+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
--- /dev/null
+# 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 المطلوبة غير مدعومة."
--- /dev/null
+# 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 ""
--- /dev/null
+# 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."
--- /dev/null
+# 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."
--- /dev/null
+# 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 ""
--- /dev/null
+# 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."
--- /dev/null
+# 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."
--- /dev/null
+# 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."
--- /dev/null
+# 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."
--- /dev/null
+# 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."
--- /dev/null
+# 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."
--- /dev/null
+# 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."
--- /dev/null
+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 ""
--- /dev/null
+# 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 형식을 지원하지 않습니다."
--- /dev/null
+# 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 ""
--- /dev/null
+# 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."
--- /dev/null
+# 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."
--- /dev/null
+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."
--- /dev/null
+# 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."
--- /dev/null
+# 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 не "
+"поддерживаются."
--- /dev/null
+# 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é."
--- /dev/null
+# 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 "Дошло је до проблема са захтевом. Тражени МИМЕ типови нису подржани."
--- /dev/null
+# 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."
--- /dev/null
+# 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 не передбачено."
--- /dev/null
+# 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 "请求出错。服务器上的项目未创建。"
--- /dev/null
+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>")
+
--- /dev/null
+#! /bin/sh
+$XGETTEXT `find . -name "*.cpp" -o -name "*.h" | grep -v '/tests/'` -o $podir/libkdav.pot
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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();
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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();
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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();
+ }
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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();
+ }
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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();
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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();
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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();
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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();
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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();
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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();
+ }
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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());
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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()
+{
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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);
+ }
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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);
+ }
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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();
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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();
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+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
+ )
+
--- /dev/null
+/*
+ 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();
+ }
+ }
+}