summaryrefslogtreecommitdiffstats
path: root/tderesources/kolab
diff options
context:
space:
mode:
Diffstat (limited to 'tderesources/kolab')
-rw-r--r--tderesources/kolab/CMakeLists.txt18
-rw-r--r--tderesources/kolab/Makefile.am8
-rw-r--r--tderesources/kolab/kabc/CMakeLists.txt54
-rw-r--r--tderesources/kolab/kabc/Makefile.am27
-rw-r--r--tderesources/kolab/kabc/contact.cpp1326
-rw-r--r--tderesources/kolab/kabc/contact.h286
-rw-r--r--tderesources/kolab/kabc/kolab.desktop52
-rw-r--r--tderesources/kolab/kabc/resourcekolab.cpp694
-rw-r--r--tderesources/kolab/kabc/resourcekolab.h179
-rw-r--r--tderesources/kolab/kabc/resourcekolab_plugin.cpp52
-rw-r--r--tderesources/kolab/kcal/CMakeLists.txt57
-rw-r--r--tderesources/kolab/kcal/Makefile.am27
-rw-r--r--tderesources/kolab/kcal/event.cpp223
-rw-r--r--tderesources/kolab/kcal/event.h102
-rw-r--r--tderesources/kolab/kcal/incidence.cpp1039
-rw-r--r--tderesources/kolab/kcal/incidence.h175
-rw-r--r--tderesources/kolab/kcal/journal.cpp184
-rw-r--r--tderesources/kolab/kcal/journal.h103
-rw-r--r--tderesources/kolab/kcal/kolab.desktop52
-rw-r--r--tderesources/kolab/kcal/resourcekolab.cpp1342
-rw-r--r--tderesources/kolab/kcal/resourcekolab.h284
-rw-r--r--tderesources/kolab/kcal/resourcekolab_plugin.cpp49
-rw-r--r--tderesources/kolab/kcal/task.cpp461
-rw-r--r--tderesources/kolab/kcal/task.h143
-rw-r--r--tderesources/kolab/knotes/CMakeLists.txt55
-rw-r--r--tderesources/kolab/knotes/Makefile.am29
-rw-r--r--tderesources/kolab/knotes/kolabresource.desktop52
-rw-r--r--tderesources/kolab/knotes/note.cpp229
-rw-r--r--tderesources/kolab/knotes/note.h111
-rw-r--r--tderesources/kolab/knotes/resourcekolab.cpp463
-rw-r--r--tderesources/kolab/knotes/resourcekolab.h133
-rw-r--r--tderesources/kolab/knotes/resourcekolab_plugin.cpp50
-rw-r--r--tderesources/kolab/kolab-resource.upd12
-rw-r--r--tderesources/kolab/shared/CMakeLists.txt30
-rw-r--r--tderesources/kolab/shared/Makefile.am17
-rw-r--r--tderesources/kolab/shared/kmailconnection.cpp339
-rw-r--r--tderesources/kolab/shared/kmailconnection.h129
-rw-r--r--tderesources/kolab/shared/kolabbase.cpp487
-rw-r--r--tderesources/kolab/shared/kolabbase.h177
-rw-r--r--tderesources/kolab/shared/resourcekolabbase.cpp287
-rw-r--r--tderesources/kolab/shared/resourcekolabbase.h205
-rw-r--r--tderesources/kolab/shared/subresource.cpp133
-rw-r--r--tderesources/kolab/shared/subresource.h117
-rw-r--r--tderesources/kolab/uninstall.desktop2
-rw-r--r--tderesources/kolab/upgrade-resourcetype.pl24
45 files changed, 10018 insertions, 0 deletions
diff --git a/tderesources/kolab/CMakeLists.txt b/tderesources/kolab/CMakeLists.txt
new file mode 100644
index 000000000..01acd3972
--- /dev/null
+++ b/tderesources/kolab/CMakeLists.txt
@@ -0,0 +1,18 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( shared )
+add_subdirectory( kabc )
+add_subdirectory( knotes )
+add_subdirectory( kcal )
+
+install( FILES kolab-resource.upd DESTINATION ${DATA_INSTALL_DIR}/kconf_update )
+install( PROGRAMS upgrade-resourcetype.pl DESTINATION ${DATA_INSTALL_DIR}/kconf_update )
diff --git a/tderesources/kolab/Makefile.am b/tderesources/kolab/Makefile.am
new file mode 100644
index 000000000..0f144e05c
--- /dev/null
+++ b/tderesources/kolab/Makefile.am
@@ -0,0 +1,8 @@
+SUBDIRS = shared kabc knotes kcal
+
+updatedir = $(kde_datadir)/kconf_update
+update_DATA = kolab-resource.upd
+update_SCRIPTS = upgrade-resourcetype.pl
+
+messages: rc.cpp
+ $(XGETTEXT) */*.cpp -o $(podir)/kres_kolab.pot
diff --git a/tderesources/kolab/kabc/CMakeLists.txt b/tderesources/kolab/kabc/CMakeLists.txt
new file mode 100644
index 000000000..e4e3e00c8
--- /dev/null
+++ b/tderesources/kolab/kabc/CMakeLists.txt
@@ -0,0 +1,54 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/../shared
+ ${CMAKE_SOURCE_DIR}
+ ${CMAKE_SOURCE_DIR}/libtdepim
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install(
+ FILES kolab.desktop
+ DESTINATION ${SERVICES_INSTALL_DIR}/tderesources/kabc )
+
+install(
+ FILES ${CMAKE_CURRENT_SOURCE_DIR}/../uninstall.desktop
+ DESTINATION ${SERVICES_INSTALL_DIR}/tderesources/kabc
+ RENAME imap.desktop )
+
+
+##### kabc_kolab (module) #######################
+
+tde_add_kpart( kabc_kolab AUTOMOC
+ SOURCES resourcekolab_plugin.cpp
+ LINK kabckolab-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
+
+
+##### kabckolab (shared) ########################
+
+tde_add_library( kabckolab SHARED AUTOMOC
+ SOURCES resourcekolab.cpp contact.cpp
+ VERSION 0.0.0
+ LINK resourcekolabshared-static kgroupwarebase-shared
+ DESTINATION ${LIB_INSTALL_DIR}
+)
diff --git a/tderesources/kolab/kabc/Makefile.am b/tderesources/kolab/kabc/Makefile.am
new file mode 100644
index 000000000..80643fba4
--- /dev/null
+++ b/tderesources/kolab/kabc/Makefile.am
@@ -0,0 +1,27 @@
+METASOURCES = AUTO
+
+INCLUDES = -I$(top_srcdir)/tderesources/kolab/shared -I$(top_srcdir) $(all_includes)
+
+# The kolab wizard links to this library too
+lib_LTLIBRARIES = libkabckolab.la
+
+libkabckolab_la_SOURCES = resourcekolab.cpp contact.cpp
+libkabckolab_la_LDFLAGS = $(all_libraries) -no-undefined
+libkabckolab_la_LIBADD = \
+ $(top_builddir)/tderesources/kolab/shared/libresourcekolabshared.la \
+ -ltderesources -lkabc
+
+kde_module_LTLIBRARIES = kabc_kolab.la
+
+noinst_HEADERS = resourcekolab.h contact.h
+
+kabc_kolab_la_SOURCES = resourcekolab_plugin.cpp
+kabc_kolab_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) -no-undefined
+kabc_kolab_la_LIBADD = libkabckolab.la
+
+servicedir = $(kde_servicesdir)/tderesources/kabc
+service_DATA = kolab.desktop
+
+install-data-local: $(srcdir)/../uninstall.desktop
+ $(mkinstalldirs) $(DESTDIR)$(servicedir)
+ $(INSTALL_DATA) $(srcdir)/../uninstall.desktop $(DESTDIR)$(servicedir)/imap.desktop
diff --git a/tderesources/kolab/kabc/contact.cpp b/tderesources/kolab/kabc/contact.cpp
new file mode 100644
index 000000000..ff8f869b7
--- /dev/null
+++ b/tderesources/kolab/kabc/contact.cpp
@@ -0,0 +1,1326 @@
+/*
+ This file is part of libkabc and/or kaddressbook.
+ Copyright (c) 2004 Klarälvdalens Datakonsult AB
+ <info@klaralvdalens-datakonsult.se>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ TQt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "contact.h"
+#include "resourcekolab.h"
+
+#include <kabc/addressee.h>
+#include <kabc/stdaddressbook.h>
+#include <libkcal/freebusyurlstore.h>
+#include <libtdepim/distributionlist.h>
+#include <kio/netaccess.h>
+#include <kdebug.h>
+#include <tqfile.h>
+#include <float.h>
+
+using namespace Kolab;
+
+static const char* s_pictureAttachmentName = "kolab-picture.png";
+static const char* s_logoAttachmentName = "kolab-logo.png";
+static const char* s_soundAttachmentName = "sound";
+static const char* s_unhandledTagAppName = "KOLABUNHANDLED"; // no hyphens in appnames!
+
+// saving (addressee->xml)
+Contact::Contact( const KABC::Addressee* addr )
+ : mHasGeo( false )
+{
+ setFields( addr );
+}
+
+// loading (xml->addressee)
+Contact::Contact( const TQString& xml, KABC::ResourceKolab* resource, const TQString& subResource, TQ_UINT32 sernum )
+ : mHasGeo( false )
+{
+ load( xml );
+ if ( !mPictureAttachmentName.isEmpty() )
+ mPicture = loadPictureFromKMail( mPictureAttachmentName, resource, subResource, sernum );
+ if ( !mLogoAttachmentName.isEmpty() )
+ mLogo = loadPictureFromKMail( mLogoAttachmentName, resource, subResource, sernum );
+ if ( !mSoundAttachmentName.isEmpty() )
+ mSound = loadDataFromKMail( mSound, resource, subResource, sernum );
+}
+
+Contact::~Contact()
+{
+}
+
+void Contact::setGivenName( const TQString& name )
+{
+ mGivenName = name;
+}
+
+TQString Contact::givenName() const
+{
+ return mGivenName;
+}
+
+void Contact::setMiddleNames( const TQString& names )
+{
+ mMiddleNames = names;
+}
+
+TQString Contact::middleNames() const
+{
+ return mMiddleNames;
+}
+
+void Contact::setLastName( const TQString& name )
+{
+ mLastName = name;
+}
+
+TQString Contact::lastName() const
+{
+ return mLastName;
+}
+
+void Contact::setFullName( const TQString& name )
+{
+ mFullName = name;
+}
+
+TQString Contact::fullName() const
+{
+ return mFullName;
+}
+
+void Contact::setInitials( const TQString& initials )
+{
+ mInitials = initials;
+}
+
+TQString Contact::initials() const
+{
+ return mInitials;
+}
+
+void Contact::setPrefix( const TQString& prefix )
+{
+ mPrefix = prefix;
+}
+
+TQString Contact::prefix() const
+{
+ return mPrefix;
+}
+
+void Contact::setSuffix( const TQString& suffix )
+{
+ mSuffix = suffix;
+}
+
+TQString Contact::suffix() const
+{
+ return mSuffix;
+}
+
+void Contact::setRole( const TQString& role )
+{
+ mRole = role;
+}
+
+TQString Contact::role() const
+{
+ return mRole;
+}
+
+void Contact::setFreeBusyUrl( const TQString& fbUrl )
+{
+ mFreeBusyUrl = fbUrl;
+}
+
+TQString Contact::freeBusyUrl() const
+{
+ return mFreeBusyUrl;
+}
+
+void Contact::setOrganization( const TQString& organization )
+{
+ mOrganization = organization;
+}
+
+TQString Contact::organization() const
+{
+ return mOrganization;
+}
+
+void Contact::setWebPage( const TQString& url )
+{
+ mWebPage = url;
+}
+
+TQString Contact::webPage() const
+{
+ return mWebPage;
+}
+
+void Contact::setIMAddress( const TQString& imAddress )
+{
+ mIMAddress = imAddress;
+}
+
+TQString Contact::imAddress() const
+{
+ return mIMAddress;
+}
+
+void Contact::setDepartment( const TQString& department )
+{
+ mDepartment = department;
+}
+
+TQString Contact::department() const
+{
+ return mDepartment;
+}
+
+void Contact::setOfficeLocation( const TQString& location )
+{
+ mOfficeLocation = location;
+}
+
+TQString Contact::officeLocation() const
+{
+ return mOfficeLocation;
+}
+
+void Contact::setProfession( const TQString& profession )
+{
+ mProfession = profession;
+}
+
+TQString Contact::profession() const
+{
+ return mProfession;
+}
+
+void Contact::setJobTitle( const TQString& title )
+{
+ mJobTitle = title;
+}
+
+TQString Contact::jobTitle() const
+{
+ return mJobTitle;
+}
+
+void Contact::setManagerName( const TQString& name )
+{
+ mManagerName = name;
+}
+
+TQString Contact::managerName() const
+{
+ return mManagerName;
+}
+
+void Contact::setAssistant( const TQString& name )
+{
+ mAssistant = name;
+}
+
+TQString Contact::assistant() const
+{
+ return mAssistant;
+}
+
+void Contact::setNickName( const TQString& name )
+{
+ mNickName = name;
+}
+
+TQString Contact::nickName() const
+{
+ return mNickName;
+}
+
+void Contact::setSpouseName( const TQString& name )
+{
+ mSpouseName = name;
+}
+
+TQString Contact::spouseName() const
+{
+ return mSpouseName;
+}
+
+void Contact::setBirthday( const TQDate& date )
+{
+ mBirthday = date;
+}
+
+TQDate Contact::birthday() const
+{
+ return mBirthday;
+}
+
+void Contact::setAnniversary( const TQDate& date )
+{
+ mAnniversary = date;
+}
+
+TQDate Contact::anniversary() const
+{
+ return mAnniversary;
+}
+
+void Contact::setChildren( const TQString& children )
+{
+ mChildren = children;
+}
+
+TQString Contact::children() const
+{
+ return mChildren;
+}
+
+void Contact::setGender( const TQString& gender )
+{
+ mGender = gender;
+}
+
+TQString Contact::gender() const
+{
+ return mGender;
+}
+
+void Contact::setLanguage( const TQString& language )
+{
+ mLanguage = language;
+}
+
+TQString Contact::language() const
+{
+ return mLanguage;
+}
+
+void Contact::addPhoneNumber( const PhoneNumber& number )
+{
+ mPhoneNumbers.append( number );
+}
+
+TQValueList<Contact::PhoneNumber>& Contact::phoneNumbers()
+{
+ return mPhoneNumbers;
+}
+
+const TQValueList<Contact::PhoneNumber>& Contact::phoneNumbers() const
+{
+ return mPhoneNumbers;
+}
+
+void Contact::addEmail( const Email& email )
+{
+ mEmails.append( email );
+}
+
+TQValueList<Contact::Email>& Contact::emails()
+{
+ return mEmails;
+}
+
+const TQValueList<Contact::Email>& Contact::emails() const
+{
+ return mEmails;
+}
+
+void Contact::addAddress( const Contact::Address& address )
+{
+ mAddresses.append( address );
+}
+
+TQValueList<Contact::Address>& Contact::addresses()
+{
+ return mAddresses;
+}
+
+const TQValueList<Contact::Address>& Contact::addresses() const
+{
+ return mAddresses;
+}
+
+void Contact::setPreferredAddress( const TQString& address )
+{
+ mPreferredAddress = address;
+}
+
+TQString Contact::preferredAddress() const
+{
+ return mPreferredAddress;
+}
+
+bool Contact::loadNameAttribute( TQDomElement& element )
+{
+ for ( TQDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ TQDomElement e = n.toElement();
+ TQString tagName = e.tagName();
+
+ if ( tagName == "given-name" )
+ setGivenName( e.text() );
+ else if ( tagName == "middle-names" )
+ setMiddleNames( e.text() );
+ else if ( tagName == "last-name" )
+ setLastName( e.text() );
+ else if ( tagName == "full-name" )
+ setFullName( e.text() );
+ else if ( tagName == "initials" )
+ setInitials( e.text() );
+ else if ( tagName == "prefix" )
+ setPrefix( e.text() );
+ else if ( tagName == "suffix" )
+ setSuffix( e.text() );
+ else
+ // TODO: Unhandled tag - save for later storage
+ kdDebug() << "Warning: Unhandled tag " << e.tagName() << endl;
+ } else
+ kdDebug() << "Node is not a comment or an element???" << endl;
+ }
+
+ return true;
+}
+
+void Contact::saveNameAttribute( TQDomElement& element ) const
+{
+ TQDomElement e = element.ownerDocument().createElement( "name" );
+ element.appendChild( e );
+
+ writeString( e, "given-name", givenName() );
+ writeString( e, "middle-names", middleNames() );
+ writeString( e, "last-name", lastName() );
+ writeString( e, "full-name", fullName() );
+ writeString( e, "initials", initials() );
+ writeString( e, "prefix", prefix() );
+ writeString( e, "suffix", suffix() );
+}
+
+bool Contact::loadPhoneAttribute( TQDomElement& element )
+{
+ PhoneNumber number;
+ for ( TQDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ TQDomElement e = n.toElement();
+ TQString tagName = e.tagName();
+
+ if ( tagName == "type" )
+ number.type = e.text();
+ else if ( tagName == "number" )
+ number.number = e.text();
+ else
+ // TODO: Unhandled tag - save for later storage
+ kdDebug() << "Warning: Unhandled tag " << e.tagName() << endl;
+ } else
+ kdDebug() << "Node is not a comment or an element???" << endl;
+ }
+
+ addPhoneNumber( number );
+ return true;
+}
+
+void Contact::savePhoneAttributes( TQDomElement& element ) const
+{
+ TQValueList<PhoneNumber>::ConstIterator it = mPhoneNumbers.begin();
+ for ( ; it != mPhoneNumbers.end(); ++it ) {
+ TQDomElement e = element.ownerDocument().createElement( "phone" );
+ element.appendChild( e );
+ const PhoneNumber& p = *it;
+ writeString( e, "type", p.type );
+ writeString( e, "number", p.number );
+ }
+}
+
+void Contact::saveEmailAttributes( TQDomElement& element ) const
+{
+ TQValueList<Email>::ConstIterator it = mEmails.begin();
+ for ( ; it != mEmails.end(); ++it )
+ saveEmailAttribute( element, *it );
+}
+
+void Contact::loadCustomAttributes( TQDomElement& element )
+{
+ Custom custom;
+ custom.app = element.attribute( "app" );
+ custom.name = element.attribute( "name" );
+ custom.value = element.attribute( "value" );
+ mCustomList.append( custom );
+}
+
+void Contact::saveCustomAttributes( TQDomElement& element ) const
+{
+ TQValueList<Custom>::ConstIterator it = mCustomList.begin();
+ for ( ; it != mCustomList.end(); ++it ) {
+ Q_ASSERT( !(*it).name.isEmpty() );
+ if ( (*it).app == s_unhandledTagAppName ) {
+ writeString( element, (*it).name, (*it).value );
+ } else {
+ // skip writing the freebusyurl as it is a hack we need to remove eventually
+ if ( (*it).name == TQString::fromLatin1( "FreeBusyURL" ) ) {
+ continue;
+ }
+
+ // Let's use attributes so that other tag-preserving-code doesn't need sub-elements
+ TQDomElement e = element.ownerDocument().createElement( "x-custom" );
+ element.appendChild( e );
+ e.setAttribute( "app", (*it).app );
+ e.setAttribute( "name", (*it).name );
+ e.setAttribute( "value", (*it).value );
+ }
+ }
+}
+
+bool Contact::loadAddressAttribute( TQDomElement& element )
+{
+ Address address;
+
+ for ( TQDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ TQDomElement e = n.toElement();
+ TQString tagName = e.tagName();
+
+ if ( tagName == "type" )
+ address.type = e.text();
+ else if ( tagName == "x-kde-type" )
+ address.kdeAddressType = e.text().toInt();
+ else if ( tagName == "street" )
+ address.street = e.text();
+ else if ( tagName == "pobox" )
+ address.pobox = e.text();
+ else if ( tagName == "locality" )
+ address.locality = e.text();
+ else if ( tagName == "region" )
+ address.region = e.text();
+ else if ( tagName == "postal-code" )
+ address.postalCode = e.text();
+ else if ( tagName == "country" )
+ address.country = e.text();
+ else
+ // TODO: Unhandled tag - save for later storage
+ kdDebug() << "Warning: Unhandled tag " << e.tagName() << endl;
+ } else
+ kdDebug() << "Node is not a comment or an element???" << endl;
+ }
+
+ addAddress( address );
+ return true;
+}
+
+void Contact::saveAddressAttributes( TQDomElement& element ) const
+{
+ TQValueList<Address>::ConstIterator it = mAddresses.begin();
+ for ( ; it != mAddresses.end(); ++it ) {
+ TQDomElement e = element.ownerDocument().createElement( "address" );
+ element.appendChild( e );
+ const Address& a = *it;
+ writeString( e, "type", a.type );
+ writeString( e, "x-kde-type", TQString::number( a.kdeAddressType ) );
+ if ( !a.street.isEmpty() )
+ writeString( e, "street", a.street );
+ if ( !a.pobox.isEmpty() )
+ writeString( e, "pobox", a.pobox );
+ if ( !a.locality.isEmpty() )
+ writeString( e, "locality", a.locality );
+ if ( !a.region.isEmpty() )
+ writeString( e, "region", a.region );
+ if ( !a.postalCode.isEmpty() )
+ writeString( e, "postal-code", a.postalCode );
+ if ( !a.country.isEmpty() )
+ writeString( e, "country", a.country );
+ }
+}
+
+
+void Kolab::Contact::loadDistrListMember( const TQDomElement& element )
+{
+ Member member;
+ for ( TQDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ TQDomElement e = n.toElement();
+ TQString tagName = e.tagName();
+ if ( tagName == "display-name" )
+ member.displayName = e.text();
+ else if ( tagName == "smtp-address" )
+ member.email = e.text();
+ }
+ }
+ mDistrListMembers.append( member );
+}
+
+void Contact::saveDistrListMembers( TQDomElement& element ) const
+{
+ TQValueList<Member>::ConstIterator it = mDistrListMembers.begin();
+ for( ; it != mDistrListMembers.end(); ++it ) {
+ TQDomElement e = element.ownerDocument().createElement( "member" );
+ element.appendChild( e );
+ const Member& m = *it;
+ writeString( e, "display-name", m.displayName );
+ writeString( e, "smtp-address", m.email );
+ }
+}
+
+bool Contact::loadAttribute( TQDomElement& element )
+{
+ const TQString tagName = element.tagName();
+ switch ( tagName[0].latin1() ) {
+ case 'a':
+ if ( tagName == "address" )
+ return loadAddressAttribute( element );
+ if ( tagName == "assistant" ) {
+ setAssistant( element.text() );
+ return true;
+ }
+ if ( tagName == "anniversary" ) {
+ if ( !element.text().isEmpty() )
+ setAnniversary( stringToDate( element.text() ) );
+ return true;
+ }
+ break;
+ case 'b':
+ if ( tagName == "birthday" ) {
+ if ( !element.text().isEmpty() )
+ setBirthday( stringToDate( element.text() ) );
+ return true;
+ }
+ break;
+ case 'c':
+ if ( tagName == "children" ) {
+ setChildren( element.text() );
+ return true;
+ }
+ break;
+ case 'd':
+ if ( tagName == "department" ) {
+ setDepartment( element.text() );
+ return true;
+ }
+ if ( mIsDistributionList && tagName == "display-name" ) {
+ setFullName( element.text() );
+ return true;
+ }
+ break;
+ case 'e':
+ if ( tagName == "email" ) {
+ Email email;
+ if ( loadEmailAttribute( element, email ) ) {
+ addEmail( email );
+ return true;
+ } else
+ return false;
+ }
+ break;
+ case 'f':
+ if ( tagName == "free-busy-url" ) {
+ setFreeBusyUrl( element.text() );
+ return true;
+ }
+ break;
+ case 'g':
+ if ( tagName == "gender" ) {
+ setGender( element.text() );
+ return true;
+ }
+ break;
+ case 'i':
+ if ( tagName == "im-address" ) {
+ setIMAddress( element.text() );
+ return true;
+ }
+ break;
+ case 'j':
+ if ( tagName == "job-title" ) {
+ // see saveAttributes: <job-title> is mapped to the Role field
+ setJobTitle( element.text() );
+ return true;
+ }
+ break;
+ case 'l':
+ if ( tagName == "language" ) {
+ setLanguage( element.text() );
+ return true;
+ }
+ if ( tagName == "latitude" ) {
+ setLatitude( element.text().toFloat() );
+ mHasGeo = true;
+ return true;
+ }
+ if ( tagName == "longitude" ) {
+ setLongitude( element.text().toFloat() );
+ mHasGeo = true;
+ }
+ break;
+ case 'm':
+ if ( tagName == "manager-name" ) {
+ setManagerName( element.text() );
+ return true;
+ }
+ if ( mIsDistributionList && tagName == "member" ) {
+ loadDistrListMember( element );
+ return true;
+ }
+ break;
+ case 'n':
+ if ( tagName == "name" )
+ return loadNameAttribute( element );
+ if ( tagName == "nick-name" ) {
+ setNickName( element.text() );
+ return true;
+ }
+ break;
+ case 'o':
+ if ( tagName == "organization" ) {
+ setOrganization( element.text() );
+ return true;
+ }
+ if ( tagName == "office-location" ) {
+ setOfficeLocation( element.text() );
+ return true;
+ }
+ break;
+ case 'p':
+ if ( tagName == "profession" ) {
+ setProfession( element.text() );
+ return true;
+ }
+ if ( tagName == "picture" ) {
+ mPictureAttachmentName = element.text();
+ return true;
+ }
+ if ( tagName == "phone" ) {
+ return loadPhoneAttribute( element );
+ return true;
+ }
+ if ( tagName == "preferred-address" ) {
+ setPreferredAddress( element.text() );
+ return true;
+ }
+ break;
+ case 'r':
+ if ( tagName == "role" ) {
+ setRole( element.text() );
+ return true;
+ }
+ break;
+ case 's':
+ if ( tagName == "spouse-name" ) {
+ setSpouseName( element.text() );
+ return true;
+ }
+ break;
+ case 'x':
+ if ( tagName == "x-logo" ) {
+ mLogoAttachmentName = element.text();
+ return true;
+ }
+ if ( tagName == "x-sound" ) {
+ mSoundAttachmentName = element.text();
+ return true;
+ }
+ if ( tagName == "x-custom" ) {
+ loadCustomAttributes( element );
+ return true;
+ }
+ break;
+ case 'w':
+ if ( tagName == "web-page" ) {
+ setWebPage( element.text() );
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+ return KolabBase::loadAttribute( element );
+}
+
+bool Contact::saveAttributes( TQDomElement& element ) const
+{
+ // Save the base class elements
+ KolabBase::saveAttributes( element );
+ if ( mIsDistributionList ) {
+ writeString( element, "display-name", fullName() );
+ saveDistrListMembers( element );
+ } else {
+ saveNameAttribute( element );
+ writeString( element, "free-busy-url", freeBusyUrl() );
+ writeString( element, "organization", organization() );
+ writeString( element, "web-page", webPage() );
+ writeString( element, "im-address", imAddress() );
+ writeString( element, "department", department() );
+ writeString( element, "office-location", officeLocation() );
+ writeString( element, "profession", profession() );
+ writeString( element, "role", role() );
+ writeString( element, "job-title", jobTitle() );
+ writeString( element, "manager-name", managerName() );
+ writeString( element, "assistant", assistant() );
+ writeString( element, "nick-name", nickName() );
+ writeString( element, "spouse-name", spouseName() );
+ writeString( element, "birthday", dateToString( birthday() ) );
+ writeString( element, "anniversary", dateToString( anniversary() ) );
+ if ( !picture().isNull() )
+ writeString( element, "picture", mPictureAttachmentName );
+ if ( !logo().isNull() )
+ writeString( element, "x-logo", mLogoAttachmentName );
+ if ( !sound().isNull() )
+ writeString( element, "x-sound", mSoundAttachmentName );
+ writeString( element, "children", children() );
+ writeString( element, "gender", gender() );
+ writeString( element, "language", language() );
+ savePhoneAttributes( element );
+ saveEmailAttributes( element );
+ saveAddressAttributes( element );
+ writeString( element, "preferred-address", preferredAddress() );
+ if ( mHasGeo ) {
+ writeString( element, "latitude", TQString::number( latitude(), 'g', DBL_DIG ) );
+ writeString( element, "longitude", TQString::number( longitude(), 'g', DBL_DIG ) );
+ }
+ }
+ saveCustomAttributes( element );
+
+ return true;
+}
+
+bool Contact::loadXML( const TQDomDocument& document )
+{
+ TQDomElement top = document.documentElement();
+
+ mIsDistributionList = top.tagName() == "distribution-list";
+ if ( top.tagName() != "contact" && !mIsDistributionList ) {
+ tqWarning( "XML error: Top tag was %s instead of the expected contact or distribution-list",
+ top.tagName().ascii() );
+ return false;
+ }
+
+
+ for ( TQDomNode n = top.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ TQDomElement e = n.toElement();
+ if ( !loadAttribute( e ) ) {
+ // Unhandled tag - save for later storage
+ //kdDebug() << "Saving unhandled tag " << e.tagName() << endl;
+ Custom c;
+ c.app = s_unhandledTagAppName;
+ c.name = e.tagName();
+ c.value = e.text();
+ mCustomList.append( c );
+ }
+ } else
+ kdDebug() << "Node is not a comment or an element???" << endl;
+ }
+
+ return true;
+}
+
+TQString Contact::saveXML() const
+{
+ TQDomDocument document = domTree();
+ TQDomElement element = document.createElement(
+ mIsDistributionList ? "distribution-list" : "contact" );
+ element.setAttribute( "version", "1.0" );
+ saveAttributes( element );
+ document.appendChild( element );
+ return document.toString();
+}
+
+static TQString addressTypeToString( int /*KABC::Address::Type*/ type )
+{
+ if ( type & KABC::Address::Home )
+ return "home";
+ if ( type & KABC::Address::Work )
+ return "business";
+ return "other";
+}
+
+static int addressTypeFromString( const TQString& type )
+{
+ if ( type == "home" )
+ return KABC::Address::Home;
+ if ( type == "business" )
+ return KABC::Address::Work;
+ // well, this shows "other" in the editor, which is what we want...
+ return KABC::Address::Dom | KABC::Address::Intl | KABC::Address::Postal | KABC::Address::Parcel;
+}
+
+static TQStringList phoneTypeToString( int /*KABC::PhoneNumber::Types*/ type )
+{
+ // KABC has a bitfield, i.e. the same phone number can be used for work and home
+ // and fax and cellphone etc. etc.
+ // So when saving we need to create as many tags as bits that were set.
+ TQStringList types;
+ if ( type & KABC::PhoneNumber::Fax ) {
+ if ( type & KABC::PhoneNumber::Home )
+ types << "homefax";
+ else // assume work -- if ( type & KABC::PhoneNumber::Work )
+ types << "businessfax";
+ type = type & ~KABC::PhoneNumber::Home;
+ type = type & ~KABC::PhoneNumber::Work;
+ }
+
+ // To support both "home1" and "home2", map Home+Pref to home2
+ if ( ( type & KABC::PhoneNumber::Home ) && ( type & KABC::PhoneNumber::Pref ) )
+ {
+ types << "home2";
+ type = type & ~KABC::PhoneNumber::Home;
+ type = type & ~KABC::PhoneNumber::Pref;
+ }
+ // To support both "business1" and "business2", map Work+Pref to business2
+ if ( ( type & KABC::PhoneNumber::Work ) && ( type & KABC::PhoneNumber::Pref ) )
+ {
+ types << "business2";
+ type = type & ~KABC::PhoneNumber::Work;
+ type = type & ~KABC::PhoneNumber::Pref;
+ }
+
+
+ if ( type & KABC::PhoneNumber::Home )
+ types << "home1";
+ if ( type & KABC::PhoneNumber::Msg ) // Msg==messaging
+ types << "company";
+ if ( type & KABC::PhoneNumber::Work )
+ types << "business1";
+ if ( type & KABC::PhoneNumber::Pref )
+ types << "primary";
+ if ( type & KABC::PhoneNumber::Voice )
+ types << "callback"; // ##
+ if ( type & KABC::PhoneNumber::Cell )
+ types << "mobile";
+ if ( type & KABC::PhoneNumber::Video )
+ types << "radio"; // ##
+ if ( type & KABC::PhoneNumber::Bbs )
+ types << "ttytdd";
+ if ( type & KABC::PhoneNumber::Modem )
+ types << "telex"; // #
+ if ( type & KABC::PhoneNumber::Car )
+ types << "car";
+ if ( type & KABC::PhoneNumber::Isdn )
+ types << "isdn";
+ if ( type & KABC::PhoneNumber::Pcs )
+ types << "assistant"; // ## Assistant is e.g. secretary
+ if ( type & KABC::PhoneNumber::Pager )
+ types << "pager";
+ return types;
+}
+
+static int /*KABC::PhoneNumber::Types*/ phoneTypeFromString( const TQString& type )
+{
+ if ( type == "homefax" )
+ return KABC::PhoneNumber::Home | KABC::PhoneNumber::Fax;
+ if ( type == "businessfax" )
+ return KABC::PhoneNumber::Work | KABC::PhoneNumber::Fax;
+ if ( type == "business2" )
+ return KABC::PhoneNumber::Work | KABC::PhoneNumber::Pref;
+ if ( type == "business1" )
+ return KABC::PhoneNumber::Work;
+ if ( type == "home2" )
+ return KABC::PhoneNumber::Home | KABC::PhoneNumber::Pref;
+ if ( type == "home1" )
+ return KABC::PhoneNumber::Home;
+ if ( type == "company" )
+ return KABC::PhoneNumber::Msg;
+ if ( type == "primary" )
+ return KABC::PhoneNumber::Pref;
+ if ( type == "callback" )
+ return KABC::PhoneNumber::Voice;
+ if ( type == "mobile" )
+ return KABC::PhoneNumber::Cell;
+ if ( type == "radio" )
+ return KABC::PhoneNumber::Video;
+ if ( type == "ttytdd" )
+ return KABC::PhoneNumber::Bbs;
+ if ( type == "telex" )
+ return KABC::PhoneNumber::Modem;
+ if ( type == "car" )
+ return KABC::PhoneNumber::Car;
+ if ( type == "isdn" )
+ return KABC::PhoneNumber::Isdn;
+ if ( type == "assistant" )
+ return KABC::PhoneNumber::Pcs;
+ if ( type == "pager" )
+ return KABC::PhoneNumber::Pager;
+ return KABC::PhoneNumber::Home; // whatever
+}
+
+static const char* s_knownCustomFields[] = {
+ "X-IMAddress",
+ "X-Department",
+ "X-Office",
+ "X-Profession",
+ "X-ManagersName",
+ "X-AssistantsName",
+ "X-SpousesName",
+ "X-Anniversary",
+ "DistributionList",
+ 0
+};
+
+// The saving is addressee -> Contact -> xml, this is the first part
+void Contact::setFields( const KABC::Addressee* addressee )
+{
+ KolabBase::setFields( addressee );
+
+ mIsDistributionList = KPIM::DistributionList::isDistributionList( *addressee );
+ if ( mIsDistributionList ) {
+ // Hopefully all resources are available during saving, so we can look up
+ // in the addressbook to get name+email from the UID.
+ KPIM::DistributionList distrList( *addressee );
+ const KPIM::DistributionList::Entry::List entries = distrList.entries( KABC::StdAddressBook::self() );
+ KPIM::DistributionList::Entry::List::ConstIterator it = entries.begin();
+ for ( ; it != entries.end() ; ++it ) {
+ Member m;
+ m.displayName = (*it).addressee.formattedName();
+ m.email = (*it).email;
+ if ( m.email.isEmpty() )
+ m.email = (*it).addressee.preferredEmail();
+ mDistrListMembers.append( m );
+ }
+ }
+
+ setGivenName( addressee->givenName() );
+ setMiddleNames( addressee->additionalName() );
+ setLastName( addressee->familyName() );
+ setFullName( addressee->formattedName() );
+ setPrefix( addressee->prefix() );
+ setSuffix( addressee->suffix() );
+ setOrganization( addressee->organization() );
+ setWebPage( addressee->url().url() );
+ setIMAddress( addressee->custom( "KADDRESSBOOK", "X-IMAddress" ) );
+#if KDE_IS_VERSION(3,5,8)
+ setDepartment( addressee->department());
+#else
+ setDepartment( addressee->custom( "KADDRESSBOOK", "X-Department" ) );
+#endif
+ setOfficeLocation( addressee->custom( "KADDRESSBOOK", "X-Office" ) );
+ setProfession( addressee->custom( "KADDRESSBOOK", "X-Profession" ) );
+ setRole( addressee->role() );
+ setJobTitle( addressee->title() );
+ setManagerName( addressee->custom( "KADDRESSBOOK", "X-ManagersName" ) );
+ setAssistant( addressee->custom( "KADDRESSBOOK", "X-AssistantsName" ) );
+ setNickName( addressee->nickName() );
+ setSpouseName( addressee->custom( "KADDRESSBOOK", "X-SpousesName" ) );
+ if ( !addressee->birthday().isNull() )
+ setBirthday( addressee->birthday().date() );
+ const TQString& anniversary = addressee->custom( "KADDRESSBOOK", "X-Anniversary" );
+ if ( !anniversary.isEmpty() )
+ setAnniversary( stringToDate( anniversary ) );
+
+ const TQStringList emails = addressee->emails();
+ // Conversion problem here:
+ // KABC::Addressee has only one full name and N addresses, but the XML format
+ // has N times (fullname+address). So we just copy the fullname over and ignore it on loading.
+ for ( TQStringList::ConstIterator it = emails.begin(); it != emails.end(); ++it ) {
+ Email email;
+ email.displayName = fullName();
+ email.smtpAddress = *it;
+ addEmail( email );
+ }
+
+ // Now the real-world addresses
+ TQString preferredAddress = "home";
+ const KABC::Address::List addresses = addressee->addresses();
+ for ( KABC::Address::List::ConstIterator it = addresses.begin() ; it != addresses.end(); ++it ) {
+ Address address;
+ address.kdeAddressType = (*it).type();
+ address.type = addressTypeToString( address.kdeAddressType );
+ address.street = (*it).street();
+ address.pobox = (*it).postOfficeBox();
+ address.locality = (*it).locality();
+ address.region = (*it).region();
+ address.postalCode = (*it).postalCode();
+ address.country = (*it).country();
+ // ## TODO not in the XML format: extended address info.
+ // ## KDE-specific tags? Or hiding those fields? Or adding a warning?
+ addAddress( address );
+ if ( address.kdeAddressType & KABC::Address::Pref ) {
+ preferredAddress = address.type; // home, business or other
+ }
+ }
+ setPreferredAddress( preferredAddress );
+
+ const KABC::PhoneNumber::List phones = addressee->phoneNumbers();
+ for ( KABC::PhoneNumber::List::ConstIterator it = phones.begin(); it != phones.end(); ++it ) {
+ // Create a tag per phone type set in the bitfield
+ TQStringList types = phoneTypeToString( (*it).type() );
+ for( TQStringList::Iterator typit = types.begin(); typit != types.end(); ++typit ) {
+ PhoneNumber phoneNumber;
+ phoneNumber.type = *typit;
+ phoneNumber.number = (*it).number();
+ addPhoneNumber( phoneNumber );
+ }
+ }
+
+ setPicture( loadPictureFromAddressee( addressee->photo() ) );
+ mPictureAttachmentName = addressee->custom( "KOLAB", "PictureAttachmentName" );
+ if ( mPictureAttachmentName.isEmpty() )
+ mPictureAttachmentName = s_pictureAttachmentName;
+
+ setLogo( loadPictureFromAddressee( addressee->logo() ) );
+ mLogoAttachmentName = addressee->custom( "KOLAB", "LogoAttachmentName" );
+ if ( mLogoAttachmentName.isEmpty() )
+ mLogoAttachmentName = s_logoAttachmentName;
+
+ setSound( loadSoundFromAddressee( addressee->sound() ) );
+ mSoundAttachmentName = addressee->custom( "KOLAB", "SoundAttachmentName" );
+ if ( mSoundAttachmentName.isEmpty() )
+ mSoundAttachmentName = s_soundAttachmentName;
+
+ if ( addressee->geo().isValid() ) {
+ setLatitude( addressee->geo().latitude() );
+ setLongitude( addressee->geo().longitude() );
+ mHasGeo = true;
+ }
+
+ // Other KADDRESSBOOK custom fields than those already handled
+ // (includes e.g. crypto settings, and extra im addresses)
+ TQStringList knownCustoms;
+ for ( const char** p = s_knownCustomFields; *p; ++p )
+ knownCustoms << TQString::fromLatin1( *p );
+ TQStringList customs = addressee->customs();
+ for( TQStringList::Iterator it = customs.begin(); it != customs.end(); ++it ) {
+ // KABC::Addressee doesn't offer a real way to iterate over customs, other than splitting strings ourselves
+ // The format is "app-name:value".
+ int pos = (*it).find( '-' );
+ if ( pos == -1 ) continue;
+ TQString app = (*it).left( pos );
+ if ( app == "KOLAB" ) continue;
+ TQString name = (*it).mid( pos + 1 );
+ pos = name.find( ':' );
+ if ( pos == -1 ) continue;
+ TQString value = name.mid( pos + 1 );
+ name = name.left( pos );
+ if ( !knownCustoms.contains( name ) ) {
+ //kdDebug() << k_funcinfo << "app=" << app << " name=" << name << " value=" << value << endl;
+ Custom c;
+ if ( app != "KADDRESSBOOK" ) // that's the default
+ c.app = app;
+ c.name = name;
+ c.value = value;
+ mCustomList.append( c );
+ }
+ }
+
+ TQString url = KCal::FreeBusyUrlStore::self()->readUrl( addressee->preferredEmail() );
+ if ( !url.isEmpty() ) {
+ setFreeBusyUrl( url );
+ }
+
+ // Those fields, although defined in Addressee, are not used in KDE
+ // (e.g. not visible in kaddressbook/addresseeeditorwidget.cpp)
+ // So it doesn't matter much if we don't have them in the XML.
+ // mailer, timezone, productId, sortString, agent, rfc2426 name()
+
+ // Things KAddressBook can't handle, so they are saved as unhandled tags:
+ // initials, children, gender, language
+}
+
+// The loading is: xml -> Contact -> addressee, this is the second part
+void Contact::saveTo( KABC::Addressee* addressee )
+{
+ // TODO: This needs the same set of TODOs as the setFields method
+ KolabBase::saveTo( addressee );
+
+ if ( mIsDistributionList ) {
+ KPIM::DistributionList distrList( *addressee );
+ distrList.setName( fullName() );
+ TQValueList<Member>::ConstIterator mit = mDistrListMembers.begin();
+ for ( ; mit != mDistrListMembers.end(); ++mit ) {
+ TQString displayName = (*mit).displayName;
+ // fixup the display name DistributionList::assumes neither ',' nor ';' is present
+ displayName.replace( ',', ' ' );
+ displayName.replace( ';', ' ' );
+ distrList.insertEntry( displayName, (*mit).email );
+ }
+ addressee->insertCustom( "KADDRESSBOOK", "DistributionList", distrList.custom( "KADDRESSBOOK", "DistributionList" ) );
+ Q_ASSERT( KPIM::DistributionList::isDistributionList( *addressee ) );
+ }
+
+ addressee->setGivenName( givenName() );
+ addressee->setAdditionalName( middleNames() );
+ addressee->setFamilyName( lastName() );
+ addressee->setFormattedName( fullName() );
+ if ( mIsDistributionList )
+ addressee->setName( fullName() );
+ addressee->setPrefix( prefix() );
+ addressee->setSuffix( suffix() );
+ addressee->setOrganization( organization() );
+ addressee->setUrl( webPage() );
+ addressee->insertCustom( "KADDRESSBOOK", "X-IMAddress", imAddress() );
+#if KDE_IS_VERSION(3,5,8)
+ addressee->setDepartment( department() );
+#else
+ addressee->insertCustom( "KADDRESSBOOK", "X-Department", department() );
+#endif
+ addressee->insertCustom( "KADDRESSBOOK", "X-Office", officeLocation() );
+ addressee->insertCustom( "KADDRESSBOOK", "X-Profession", profession() );
+ addressee->setRole( role() );
+ addressee->setTitle( jobTitle() );
+ addressee->insertCustom( "KADDRESSBOOK", "X-ManagersName", managerName() );
+ addressee->insertCustom( "KADDRESSBOOK", "X-AssistantsName", assistant() );
+ addressee->setNickName( nickName() );
+ addressee->insertCustom( "KADDRESSBOOK", "X-SpousesName", spouseName() );
+ if ( birthday().isValid() )
+ addressee->setBirthday( TQDateTime( birthday() ) );
+
+ if ( anniversary().isValid() )
+ addressee->insertCustom( "KADDRESSBOOK", "X-Anniversary",
+ dateToString( anniversary() ) );
+ else
+ addressee->removeCustom( "KADDRESSBOOK", "X-Anniversary" );
+
+ // We need to store both the original attachment name and the picture data into the addressee.
+ // This is important, otherwise we would save the image under another attachment name w/o deleting the original one!
+ if ( !mPicture.isNull() )
+ addressee->setPhoto( KABC::Picture( mPicture ) );
+ // Note that we must save the filename in all cases, so that removing the picture
+ // actually deletes the attachment.
+ addressee->insertCustom( "KOLAB", "PictureAttachmentName", mPictureAttachmentName );
+ if ( !mLogo.isNull() )
+ addressee->setLogo( KABC::Picture( mLogo ) );
+ addressee->insertCustom( "KOLAB", "LogoAttachmentName", mLogoAttachmentName );
+ if ( !mSound.isNull() )
+ addressee->setSound( KABC::Sound( mSound ) );
+ addressee->insertCustom( "KOLAB", "SoundAttachmentName", mSoundAttachmentName );
+
+ if ( mHasGeo )
+ addressee->setGeo( KABC::Geo( mLatitude, mLongitude ) );
+
+ TQStringList emailAddresses;
+ for ( TQValueList<Email>::ConstIterator it = mEmails.begin(); it != mEmails.end(); ++it ) {
+ // we can't do anything with (*it).displayName
+ emailAddresses.append( (*it).smtpAddress );
+ }
+ addressee->setEmails( emailAddresses );
+
+ for ( TQValueList<Address>::ConstIterator it = mAddresses.begin(); it != mAddresses.end(); ++it ) {
+ KABC::Address address;
+ int type = (*it).kdeAddressType;
+ if ( type == -1 ) { // no kde-specific type available
+ type = addressTypeFromString( (*it).type );
+ if ( (*it).type == mPreferredAddress )
+ type |= KABC::Address::Pref;
+ }
+ address.setType( type );
+ address.setStreet( (*it).street );
+ address.setPostOfficeBox( (*it).pobox );
+ address.setLocality( (*it).locality );
+ address.setRegion( (*it).region );
+ address.setPostalCode( (*it).postalCode );
+ address.setCountry( (*it).country );
+ addressee->insertAddress( address );
+ }
+
+ for ( TQValueList<PhoneNumber>::ConstIterator it = mPhoneNumbers.begin(); it != mPhoneNumbers.end(); ++it ) {
+ KABC::PhoneNumber number;
+ number.setType( phoneTypeFromString( (*it).type ) );
+ number.setNumber( (*it).number );
+ addressee->insertPhoneNumber( number );
+ }
+
+ for( TQValueList<Custom>::ConstIterator it = mCustomList.begin(); it != mCustomList.end(); ++it ) {
+ TQString app = (*it).app.isEmpty() ? TQString::fromLatin1( "KADDRESSBOOK" ) : (*it).app;
+ addressee->insertCustom( app, (*it).name, (*it).value );
+ }
+ //kdDebug(5006) << addressee->customs() << endl;
+}
+
+TQImage Contact::loadPictureFromKMail( const TQString& attachmentName, KABC::ResourceKolab* resource, const TQString& subResource, TQ_UINT32 sernum )
+{
+ TQImage img;
+ KURL url;
+ if ( resource->kmailGetAttachment( url, subResource, sernum, attachmentName ) && !url.isEmpty() ) {
+ const TQString path = url.path();
+ img.load( path );
+ TQFile::remove(path);
+ }
+ return img;
+}
+
+TQImage Contact::loadPictureFromAddressee( const KABC::Picture& picture )
+{
+ TQImage img;
+ if ( !picture.isIntern() && !picture.url().isEmpty() ) {
+ TQString tmpFile;
+ if ( TDEIO::NetAccess::download( picture.url(), tmpFile, 0 /*no widget known*/ ) ) {
+ img.load( tmpFile );
+ TDEIO::NetAccess::removeTempFile( tmpFile );
+ }
+ } else
+ img = picture.data();
+ return img;
+}
+
+TQByteArray Kolab::Contact::loadDataFromKMail( const TQString& attachmentName, KABC::ResourceKolab* resource, const TQString& subResource, TQ_UINT32 sernum )
+{
+ TQByteArray data;
+ KURL url;
+ if ( resource->kmailGetAttachment( url, subResource, sernum, attachmentName ) && !url.isEmpty() ) {
+ TQFile f( url.path() );
+ if ( f.open( IO_ReadOnly ) ) {
+ data = f.readAll();
+ f.close();
+ }
+ f.remove();
+ }
+ return data;
+}
+
+TQByteArray Kolab::Contact::loadSoundFromAddressee( const KABC::Sound& sound )
+{
+ TQByteArray data;
+ if ( !sound.isIntern() && !sound.url().isEmpty() ) {
+ TQString tmpFile;
+ if ( TDEIO::NetAccess::download( sound.url(), tmpFile, 0 /*no widget known*/ ) ) {
+ TQFile f( tmpFile );
+ if ( f.open( IO_ReadOnly ) ) {
+ data = f.readAll();
+ f.close();
+ }
+ TDEIO::NetAccess::removeTempFile( tmpFile );
+ }
+ } else
+ data = sound.data();
+ return data;
+}
+
+TQString Kolab::Contact::productID() const
+{
+ // TODO: When KAB has the version number in a header file, don't hardcode (Bo)
+ // Or we could use Addressee::productID? (David)
+ return "KAddressBook 3.3, Kolab resource";
+}
diff --git a/tderesources/kolab/kabc/contact.h b/tderesources/kolab/kabc/contact.h
new file mode 100644
index 000000000..6e0de80bc
--- /dev/null
+++ b/tderesources/kolab/kabc/contact.h
@@ -0,0 +1,286 @@
+/*
+ This file is part of libkabc and/or kaddressbook.
+ Copyright (c) 2002 - 2004 Klarälvdalens Datakonsult AB
+ <info@klaralvdalens-datakonsult.se>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ TQt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef KOLABCONTACT_H
+#define KOLABCONTACT_H
+
+#include <kolabbase.h>
+#include <tqimage.h>
+
+namespace KABC {
+ class Addressee;
+ class ResourceKolab;
+ class Picture;
+ class Sound;
+}
+
+namespace Kolab {
+
+class Contact : public KolabBase {
+public:
+ struct PhoneNumber {
+ public:
+ TQString type;
+ TQString number;
+ };
+
+ struct Address {
+ public:
+ Address() : kdeAddressType( -1 )
+ {
+ }
+ int kdeAddressType; // KABC::Address::Type
+ TQString type; // kolab-compliant address type: home, work or other
+ TQString street;
+ TQString pobox;
+ TQString locality;
+ TQString region;
+ TQString postalCode;
+ TQString country;
+ };
+
+ explicit Contact( const KABC::Addressee* address );
+ Contact( const TQString& xml, KABC::ResourceKolab* resource, const TQString& subResource, TQ_UINT32 sernum );
+ ~Contact();
+
+ void saveTo( KABC::Addressee* address );
+
+ TQString type() const { return "Contact"; }
+
+ void setGivenName( const TQString& name );
+ TQString givenName() const;
+
+ void setMiddleNames( const TQString& names );
+ TQString middleNames() const;
+
+ void setLastName( const TQString& name );
+ TQString lastName() const;
+
+ void setFullName( const TQString& name );
+ TQString fullName() const;
+
+ void setInitials( const TQString& initials );
+ TQString initials() const;
+
+ void setPrefix( const TQString& prefix );
+ TQString prefix() const;
+
+ void setSuffix( const TQString& suffix );
+ TQString suffix() const;
+
+ void setRole( const TQString& role );
+ TQString role() const;
+
+ void setFreeBusyUrl( const TQString& fbUrl );
+ TQString freeBusyUrl() const;
+
+ void setOrganization( const TQString& organization );
+ TQString organization() const;
+
+ void setWebPage( const TQString& url );
+ TQString webPage() const;
+
+ void setIMAddress( const TQString& imAddress );
+ TQString imAddress() const;
+
+ void setDepartment( const TQString& department );
+ TQString department() const;
+
+ void setOfficeLocation( const TQString& location );
+ TQString officeLocation() const;
+
+ void setProfession( const TQString& profession );
+ TQString profession() const;
+
+ void setJobTitle( const TQString& title );
+ TQString jobTitle() const;
+
+ void setManagerName( const TQString& name );
+ TQString managerName() const;
+
+ void setAssistant( const TQString& name );
+ TQString assistant() const;
+
+ void setNickName( const TQString& name );
+ TQString nickName() const;
+
+ void setSpouseName( const TQString& name );
+ TQString spouseName() const;
+
+ void setBirthday( const TQDate& date );
+ TQDate birthday() const;
+
+ void setAnniversary( const TQDate& date );
+ TQDate anniversary() const;
+
+ void setPicture( const TQImage& image) { mPicture = image; }
+ TQString pictureAttachmentName() const { return mPictureAttachmentName; }
+ TQImage picture() const { return mPicture; }
+
+ void setLogo( const TQImage& image ) { mLogo = image; }
+ TQString logoAttachmentName() const { return mLogoAttachmentName; }
+ TQImage logo() const { return mLogo; }
+
+ void setSound( const TQByteArray& sound ) { mSound = sound; }
+ TQString soundAttachmentName() const { return mSoundAttachmentName; }
+ TQByteArray sound() const { return mSound; }
+
+ void setChildren( const TQString& children );
+ TQString children() const;
+
+ void setGender( const TQString& gender );
+ TQString gender() const;
+
+ void setLanguage( const TQString& language );
+ TQString language() const;
+
+ void addPhoneNumber( const PhoneNumber& number );
+ TQValueList<PhoneNumber>& phoneNumbers();
+ const TQValueList<PhoneNumber>& phoneNumbers() const;
+
+ void addEmail( const Email& email );
+ TQValueList<Email>& emails();
+ const TQValueList<Email>& emails() const;
+
+ void addAddress( const Address& address );
+ TQValueList<Address>& addresses();
+ const TQValueList<Address>& addresses() const;
+
+ // which address is preferred: home or business or other
+ void setPreferredAddress( const TQString& address );
+ TQString preferredAddress() const;
+
+ float latitude() const { return mLatitude; }
+ void setLatitude( float latitude ) { mLatitude = latitude; }
+
+ float longitude() const { return mLongitude; }
+ void setLongitude( float longitude ) { mLongitude = longitude; }
+
+ // Load the attributes of this class
+ bool loadAttribute( TQDomElement& );
+
+ // Save the attributes of this class
+ bool saveAttributes( TQDomElement& ) const;
+
+ // Load this note by reading the XML file
+ bool loadXML( const TQDomDocument& xml );
+
+ // Serialize this note to an XML string
+ TQString saveXML() const;
+
+ // Return true if this contact is a distr list
+ bool isDistributionList() const { return mIsDistributionList; }
+
+protected:
+ void setFields( const KABC::Addressee* );
+
+private:
+ bool loadNameAttribute( TQDomElement& element );
+ void saveNameAttribute( TQDomElement& element ) const;
+
+ bool loadPhoneAttribute( TQDomElement& element );
+ void savePhoneAttributes( TQDomElement& element ) const;
+
+ void saveEmailAttributes( TQDomElement& element ) const;
+
+ bool loadAddressAttribute( TQDomElement& element );
+ void saveAddressAttributes( TQDomElement& element ) const;
+
+ void loadCustomAttributes( TQDomElement& element );
+ void saveCustomAttributes( TQDomElement& element ) const;
+
+ void loadDistrListMember( const TQDomElement& element );
+ void saveDistrListMembers( TQDomElement& element ) const;
+
+ TQImage loadPictureFromKMail( const TQString& attachmentName, KABC::ResourceKolab* resource, const TQString& subResource, TQ_UINT32 sernum );
+ TQImage loadPictureFromAddressee( const KABC::Picture& picture );
+
+ TQByteArray loadDataFromKMail( const TQString& attachmentName, KABC::ResourceKolab* resource, const TQString& subResource, TQ_UINT32 sernum );
+ TQByteArray loadSoundFromAddressee( const KABC::Sound& sound );
+
+ TQString productID() const;
+
+ TQString mGivenName;
+ TQString mMiddleNames;
+ TQString mLastName;
+ TQString mFullName;
+ TQString mInitials;
+ TQString mPrefix;
+ TQString mSuffix;
+ TQString mRole;
+ TQString mFreeBusyUrl;
+ TQString mOrganization;
+ TQString mWebPage;
+ TQString mIMAddress;
+ TQString mDepartment;
+ TQString mOfficeLocation;
+ TQString mProfession;
+ TQString mJobTitle;
+ TQString mManagerName;
+ TQString mAssistant;
+ TQString mNickName;
+ TQString mSpouseName;
+ TQDate mBirthday;
+ TQDate mAnniversary;
+ TQImage mPicture;
+ TQImage mLogo;
+ TQByteArray mSound;
+ TQString mPictureAttachmentName;
+ TQString mLogoAttachmentName;
+ TQString mSoundAttachmentName;
+ TQString mChildren;
+ TQString mGender;
+ TQString mLanguage;
+ TQValueList<PhoneNumber> mPhoneNumbers;
+ TQValueList<Email> mEmails;
+ TQValueList<Address> mAddresses;
+ TQString mPreferredAddress;
+ float mLatitude;
+ float mLongitude;
+ bool mHasGeo;
+ bool mIsDistributionList;
+ struct Custom {
+ TQString app;
+ TQString name;
+ TQString value;
+ };
+ TQValueList<Custom> mCustomList;
+ struct Member {
+ TQString displayName;
+ TQString email;
+ };
+ TQValueList<Member> mDistrListMembers;
+};
+
+}
+
+#endif // KOLABCONTACT_H
diff --git a/tderesources/kolab/kabc/kolab.desktop b/tderesources/kolab/kabc/kolab.desktop
new file mode 100644
index 000000000..e0a478c0a
--- /dev/null
+++ b/tderesources/kolab/kabc/kolab.desktop
@@ -0,0 +1,52 @@
+[Desktop Entry]
+Name=Addressbook on IMAP Server via KMail
+Name[af]=Adresboek op IMAP bediener via KMail
+Name[bg]=Адресник на сървър IMAP през KMail
+Name[br]=Karned chomlec'hioù war ur servijer IMAP gant KMail
+Name[ca]=Llibreta d'adreces sobre servidor IMAP mitjançant KMail
+Name[cs]=Kniha adres na IMAP serveru přes KMail
+Name[da]=Adressebog på IMAP-server via KMail
+Name[de]=Adressbuch auf einem IMAP-Server via KMail
+Name[el]=Ημερολόγιο σε εξυπηρετητή IMAP μέσω του KMail
+Name[es]=Libreta de direcciones en servidor IMAP por medio de KMail
+Name[et]=Aadressiraamat IMAP-serveris (KMaili vahendusel)
+Name[eu]=Helbide-liburua IMAP zerbitzarian KMail-en bidez
+Name[fa]=کتاب نشانی روی کارساز IMAP از طریق KMail
+Name[fi]=Osoitekirja IMAP-palvelimella KMailin avulla
+Name[fr]=Carnet d'adresse sur serveur IMAP (via KMail)
+Name[fy]=Adresboek op IMAP-tsjinner fia KMail
+Name[ga]=Leabhar Seoltaí ar Fhreastalaí IMAP via KMail
+Name[gl]=Caderno de enderezos nun servidor IMAP mediante KMail
+Name[hu]=IMAP-kiszolgálón tárolt címjegyzék a KMailen keresztül
+Name[is]=Vistfangaskrá á IMAP þjóni gegnum KMail
+Name[it]=Rubrica indirizzi su server IMAP via KMail
+Name[ja]=KMail 経由 IMAP サーバのアドレス帳
+Name[kk]=KMail арқылы IMAP серверіндегі адрестік кітапша
+Name[km]=សៀវភៅ​អាសយដ្ឋាន​លើ​ម៉ាស៊ីន​បម្រើ IMAP តាម​រយៈ KMail
+Name[lt]=Adresų knygelė IMAP serveryje per KMail
+Name[mk]=Адресар на IMAP-сервер преку КПошта
+Name[ms]=Buku alamat pada pelayan IMAP melalui KMail
+Name[nb]=Adressebok på IMAP-tjener via KMail
+Name[nds]=Adressbook op IMAP-Server över KMail
+Name[ne]=केडीई मेल मार्फत IMAP सर्भरमा ठेगाना पुस्तिका
+Name[nl]=Adresboek op IMAP-server via KMail
+Name[nn]=Adressebok på IMAP-tenar via KMail
+Name[pl]=Książka adresowa na serwerze IMAP za pośrednictwem KMail
+Name[pt]=Livro de Endereços em Servidor IMAP via KMail
+Name[pt_BR]=Livro de Endereços em servidor IMAP via KMail
+Name[ru]=Адресная книга на сервере IMAP через KMail
+Name[sk]=Adresár na IMAP-serveri pomocou KMail
+Name[sl]=Adresar na strežniku IMAP preko KMaila
+Name[sr]=Адресар на IMAP серверу преко KMail-а
+Name[sr@Latn]=Adresar na IMAP serveru preko KMail-a
+Name[sv]=Adressbok på IMAP-server via Kmail
+Name[ta]=IMAP சேவகன் மூலம் கேஅஞ்சல் முகவரிப்புத்தகம்
+Name[tr]=KMail Aracılığı ile IMAP Sunucusunda Adres Defteri
+Name[uk]=Адресна книга на сервері IMAP через KMail
+Name[zh_CN]=通过 KMail 访问 IMAP 服务器上的地址簿
+Name[zh_TW]=透過 KMail 取得 IMAP 伺服器上的通訊錄
+X-TDE-Library=kabc_kolab
+Type=Service
+ServiceTypes=KResources/Plugin
+X-TDE-ResourceFamily=contact
+X-TDE-ResourceType=imap
diff --git a/tderesources/kolab/kabc/resourcekolab.cpp b/tderesources/kolab/kabc/resourcekolab.cpp
new file mode 100644
index 000000000..ce7c18c42
--- /dev/null
+++ b/tderesources/kolab/kabc/resourcekolab.cpp
@@ -0,0 +1,694 @@
+/*
+ This file is part of libkabc and/or kaddressbook.
+ Copyright (c) 2002 - 2004 Klarälvdalens Datakonsult AB
+ <info@klaralvdalens-datakonsult.se>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ TQt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "resourcekolab.h"
+#include "contact.h"
+
+#include <kdebug.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <ktempfile.h>
+#include <kio/observer.h>
+#include <kio/uiserver_stub.h>
+#include <kabc/vcardconverter.h>
+#include <kmainwindow.h>
+#include <kapplication.h>
+#include <dcopclient.h>
+
+#include <tqobject.h>
+#include <tqtimer.h>
+#include <tqstring.h>
+#include <tqfile.h>
+#include <tqapplication.h>
+
+#include <assert.h>
+
+using namespace Kolab;
+
+class KolabFactory : public KRES::PluginFactoryBase
+{
+ public:
+ KRES::Resource *resource( const TDEConfig *config )
+ {
+ return new KABC::ResourceKolab( config );
+ }
+
+ KRES::ConfigWidget *configWidget( TQWidget* )
+ {
+ return 0;
+ }
+};
+
+K_EXPORT_COMPONENT_FACTORY(kabc_kolab,KolabFactory)
+
+static const char* s_kmailContentsType = "Contact";
+static const char* s_attachmentMimeTypeContact = "application/x-vnd.kolab.contact";
+static const char* s_attachmentMimeTypeDistList = "application/x-vnd.kolab.contact.distlist";
+static const char* s_inlineMimeType = "text/x-vcard";
+
+KABC::ResourceKolab::ResourceKolab( const TDEConfig *config )
+ : KPIM::ResourceABC( config ),
+ Kolab::ResourceKolabBase( "ResourceKolab-KABC" ),
+ mCachedSubresource( TQString() ), mCachedSubresourceNotFound( false ), mLocked( false )
+{
+ setType( "imap" );
+ if ( !config ) {
+ setResourceName( i18n( "Kolab Server" ) );
+ }
+}
+
+KABC::ResourceKolab::~ResourceKolab()
+{
+ // The resource is deleted on exit (StdAddressBook's KStaticDeleter),
+ // and it wasn't closed before that, so close here to save the config.
+ if ( isOpen() ) {
+ close();
+ }
+}
+
+void KABC::ResourceKolab::loadSubResourceConfig( TDEConfig& config,
+ const TQString& name,
+ const TQString& label,
+ bool writable )
+{
+ TDEConfigGroup group( &config, name );
+ bool active = group.readBoolEntry( "Active", true );
+ int completionWeight = group.readNumEntry( "CompletionWeight", 80 );
+ mSubResources.insert( name, Kolab::SubResource( active, writable, label,
+ completionWeight ) );
+}
+
+bool KABC::ResourceKolab::doOpen()
+{
+ TDEConfig config( configFile() );
+
+ // Read the calendar entries
+ TQValueList<KMailICalIface::SubResource> subResources;
+ if ( !kmailSubresources( subResources, s_kmailContentsType ) )
+ return false;
+ mSubResources.clear();
+ TQValueList<KMailICalIface::SubResource>::ConstIterator it;
+ for ( it = subResources.begin(); it != subResources.end(); ++it ) {
+ loadSubResourceConfig( config, (*it).location, (*it).label, (*it).writable );
+ }
+
+ return true;
+}
+
+void KABC::ResourceKolab::doClose()
+{
+ writeConfig();
+}
+
+KABC::Ticket * KABC::ResourceKolab::requestSaveTicket()
+{
+ if ( !addressBook() ) {
+ kdError() << "no addressbook" << endl;
+ return 0;
+ }
+ mLocked = true;
+
+ return createTicket( this );
+}
+
+void KABC::ResourceKolab::releaseSaveTicket( Ticket* ticket )
+{
+ mLocked = false;
+ mCachedSubresource = TQString();
+ mCachedSubresourceNotFound = false;
+ delete ticket;
+}
+
+TQString KABC::ResourceKolab::loadContact( const TQString& contactData,
+ const TQString& subResource,
+ TQ_UINT32 sernum,
+ KMailICalIface::StorageFormat format )
+{
+ KABC::Addressee addr;
+ if ( format == KMailICalIface::StorageXML ) {
+ Contact contact( contactData, this, subResource, sernum ); // load
+ contact.saveTo( &addr );
+ } else {
+ KABC::VCardConverter converter;
+#if defined(KABC_VCARD_ENCODING_FIX)
+ addr = converter.parseVCardRaw( contactData.utf8() );
+#else
+ addr = converter.parseVCard( contactData );
+#endif
+ }
+
+ addr.setResource( this );
+ addr.setChanged( false );
+ KABC::Resource::insertAddressee( addr ); // same as mAddrMap.insert( addr.uid(), addr );
+ mUidMap[ addr.uid() ] = StorageReference( subResource, sernum );
+ kdDebug(5650) << "Loaded contact uid=" << addr.uid() << " sernum=" << sernum << " fullName=" << addr.name() << endl;
+ return addr.uid();
+}
+
+static const struct { const char* mimetype; KMailICalIface::StorageFormat format; } s_formats[] =
+{
+ { s_attachmentMimeTypeContact, KMailICalIface::StorageXML },
+ { s_attachmentMimeTypeDistList, KMailICalIface::StorageXML },
+ { s_inlineMimeType, KMailICalIface::StorageIcalVcard }
+};
+
+bool KABC::ResourceKolab::loadSubResource( const TQString& subResource )
+{
+ int count = 0;
+ if ( !kmailIncidencesCount( count, TQString(), subResource ) ) {
+ kdError() << "Communication problem in KABC::ResourceKolab::loadSubResource()\n";
+ return false;
+ }
+ if ( !count )
+ return true;
+
+ // Read that many contacts at a time.
+ // If this number is too small we lose time in kmail.
+ // If it's too big the progressbar is jumpy.
+ const int nbMessages = 200;
+
+ (void)Observer::self(); // ensure kio_uiserver is running
+ UIServer_stub uiserver( "kio_uiserver", "UIServer" );
+ int progressId = 0;
+ if ( count > 200 ) {
+ progressId = uiserver.newJob( kapp->dcopClient()->appId(), true );
+ uiserver.totalFiles( progressId, count );
+ uiserver.infoMessage( progressId, i18n( "Loading contacts..." ) );
+ uiserver.transferring( progressId, "Contacts" );
+ }
+
+ for ( int startIndex = 0; startIndex < count; startIndex += nbMessages ) {
+
+ // TODO it would be faster to pass the s_formats array to kmail and let it load
+ // all events - to avoid loading each mail 3 times. But then we need to extend the returned
+ // TQMap to also tell us the StorageFormat of each found contact...
+ for ( int indexFormat = 0; indexFormat < 3; ++indexFormat ) {
+ const char* mimetype = s_formats[indexFormat].mimetype;
+ KMailICalIface::StorageFormat format = s_formats[indexFormat].format;
+ TQMap<TQ_UINT32, TQString> lst;
+ if ( !kmailIncidences( lst, mimetype, subResource, startIndex, nbMessages ) ) {
+ kdError() << "Communication problem in KABC::ResourceKolab::loadSubResource()\n";
+ if ( progressId )
+ uiserver.jobFinished( progressId );
+ return false;
+ }
+
+ for( TQMap<TQ_UINT32, TQString>::ConstIterator it = lst.begin(); it != lst.end(); ++it ) {
+ loadContact( it.data(), subResource, it.key(), format );
+ }
+
+ }
+ if ( progressId ) {
+ uiserver.processedFiles( progressId, startIndex );
+ uiserver.percent( progressId, 100 * startIndex / count );
+ }
+
+// if ( progress.wasCanceled() ) {
+// uiserver.jobFinished( progressId );
+// return false;
+// }
+
+ }
+
+ kdDebug(5650) << "Contacts kolab resource: got " << count << " contacts in " << subResource << endl;
+
+ if ( progressId )
+ uiserver.jobFinished( progressId );
+ return true;
+}
+
+bool KABC::ResourceKolab::load()
+{
+ mUidMap.clear();
+ mAddrMap.clear();
+
+ bool rc = true;
+ Kolab::ResourceMap::ConstIterator itR;
+ for ( itR = mSubResources.begin(); itR != mSubResources.end(); ++itR ) {
+ if ( !itR.data().active() )
+ // This resource is disabled
+ continue;
+
+ rc &= loadSubResource( itR.key() );
+ }
+
+ return rc;
+}
+
+bool KABC::ResourceKolab::save( Ticket* )
+{
+ bool rc = true;
+
+ for( ConstIterator it = begin(); it != end(); ++it )
+ if( (*it).changed() ) {
+ rc &= kmailUpdateAddressee( *it );
+ }
+
+ if ( !rc )
+ kdDebug(5650) << k_funcinfo << " failed." << endl;
+ return rc;
+}
+
+namespace Kolab {
+struct AttachmentList {
+ TQStringList attachmentURLs;
+ TQStringList attachmentNames;
+ TQStringList attachmentMimeTypes;
+ TQStringList deletedAttachments;
+ TQValueList<KTempFile *> tempFiles;
+
+ void addAttachment( const TQString& url, const TQString& name, const TQString& mimetype ) {
+ attachmentURLs.append( url );
+ attachmentNames.append( name );
+ attachmentMimeTypes.append( mimetype );
+ }
+
+ void updatePictureAttachment( const TQImage& image, const TQString& name );
+ void updateAttachment( const TQByteArray& data, const TQString& name, const char* mimetype );
+};
+} // namespace
+
+void AttachmentList::updatePictureAttachment( const TQImage& image, const TQString& name )
+{
+ assert( !name.isEmpty() );
+ if ( !image.isNull() ) {
+ KTempFile tempFile;
+ image.save( tempFile.file(), "PNG" );
+ tempFile.close();
+ KURL url;
+ url.setPath( tempFile.name() );
+ kdDebug(5650) << "picture saved to " << url.path() << endl;
+ addAttachment( url.url(), name, "image/png" );
+ } else {
+ deletedAttachments.append( name );
+ }
+}
+
+void AttachmentList::updateAttachment( const TQByteArray& data, const TQString& name, const char* mimetype )
+{
+ assert( !name.isEmpty() );
+ if ( !data.isNull() ) {
+ KTempFile tempFile;
+ tempFile.file()->writeBlock( data );
+ tempFile.close();
+ KURL url;
+ url.setPath( tempFile.name() );
+ kdDebug(5650) << "data saved to " << url.path() << endl;
+ addAttachment( url.url(), name, mimetype );
+ } else {
+ deletedAttachments.append( name );
+ }
+}
+
+bool KABC::ResourceKolab::kmailUpdateAddressee( const Addressee& addr )
+{
+ const TQString uid = addr.uid();
+ TQString subResource;
+ TQ_UINT32 sernum;
+ if ( mUidMap.find( uid ) != mUidMap.end() ) {
+ subResource = mUidMap[ uid ].resource();
+ if ( !subresourceWritable( subResource ) ) {
+ kdWarning() << "Wow! Something tried to update a non-writable addressee! Fix this caller: " << kdBacktrace() << endl;
+ return false;
+ }
+ sernum = mUidMap[ uid ].serialNumber();
+ } else {
+ if ( !mCachedSubresource.isNull() || mCachedSubresourceNotFound ) {
+ subResource = mCachedSubresource;
+ } else {
+ subResource = findWritableResource( Kolab::Contacts, mSubResources );
+ // We were locked, remember the subresource we are working with until
+ // we are unlocked
+ if ( mLocked ) {
+ mCachedSubresource = subResource;
+
+ // If the subresource is empty here, it means findWritableResource() failed, for example
+ // because the user cancelled the resource selection dialog. Remember that, so we avoid
+ // asking multiple times when locked.
+ mCachedSubresourceNotFound = subResource.isEmpty();
+ }
+ }
+ if ( subResource.isEmpty() )
+ return false;
+ sernum = 0;
+ }
+ TQString data;
+ TQString mimetype;
+ AttachmentList att;
+ bool isXMLStorageFormat = kmailStorageFormat( subResource ) == KMailICalIface::StorageXML;
+ TQString subject = uid; // as per kolab2 spec
+ if ( isXMLStorageFormat ) {
+ Contact contact( &addr );
+ // The addressee is converted to: 1) the xml 2) the optional picture 3) the optional logo 4) the optional sound
+ data = contact.saveXML();
+ att.updatePictureAttachment( contact.picture(), contact.pictureAttachmentName() );
+ att.updatePictureAttachment( contact.logo(), contact.logoAttachmentName() );
+ // no way to know the mimetype. The addressee editor allows to attach _any_ kind of file,
+ // and the sound system sorts it out.
+ att.updateAttachment( contact.sound(), contact.soundAttachmentName(), "audio/unknown" );
+ mimetype = contact.isDistributionList() ?
+ s_attachmentMimeTypeDistList : s_attachmentMimeTypeContact;
+ } else {
+ mimetype = s_inlineMimeType;
+ KABC::VCardConverter converter;
+#if defined(KABC_VCARD_ENCODING_FIX)
+ data = TQString::fromUtf8( converter.createVCardRaw( addr ) );
+#else
+ data = converter.createVCard( addr );
+#endif
+ subject.prepend( "vCard " ); // as per kolab1 spec
+ }
+ bool rc = kmailUpdate( subResource, sernum, data, mimetype, subject,
+ CustomHeaderMap(),
+ att.attachmentURLs, att.attachmentMimeTypes, att.attachmentNames,
+ att.deletedAttachments );
+ if ( !rc )
+ kdDebug(5650) << "kmailUpdate returned false!" << endl;
+ if ( rc ) {
+ kdDebug(5650) << "kmailUpdate returned, now sernum=" << sernum << " for uid=" << uid << endl;
+ mUidMap[ uid ] = StorageReference( subResource, sernum );
+ // This is ugly, but it's faster than doing
+ // mAddrMap.find(addr.uid()), which would give the same :-(
+ // Reason for this: The Changed attribute of Addressee should
+ // be mutable
+ const_cast<Addressee&>(addr).setChanged( false );
+ }
+
+ for( TQValueList<KTempFile *>::Iterator it = att.tempFiles.begin(); it != att.tempFiles.end(); ++it ) {
+ (*it)->setAutoDelete( true );
+ delete (*it);
+ }
+ return rc;
+}
+
+void KABC::ResourceKolab::insertAddressee( const Addressee& addr )
+{
+ const TQString uid = addr.uid();
+ //kdDebug(5650) << k_funcinfo << uid << endl;
+ bool ok = false;
+ if ( mUidMap.contains( uid ) ) {
+ mUidsPendingUpdate.append( uid );
+ } else {
+ mUidsPendingAdding.append( uid );
+ }
+
+ ok = kmailUpdateAddressee( addr );
+
+ if ( ok )
+ Resource::insertAddressee( addr );
+}
+
+void KABC::ResourceKolab::removeAddressee( const Addressee& addr )
+{
+ const TQString uid = addr.uid();
+ if ( mUidMap.find( uid ) == mUidMap.end() ) return;
+ //kdDebug(5650) << k_funcinfo << uid << endl;
+ const TQString resource = mUidMap[ uid ].resource();
+ if ( !subresourceWritable( resource ) ) {
+ kdWarning() << "Wow! Something tried to delete a non-writable addressee! Fix this caller: " << kdBacktrace() << endl;
+ return;
+ }
+ /* The user told us to delete, tell KMail */
+ kmailDeleteIncidence( resource,
+ mUidMap[ uid ].serialNumber() );
+ mUidsPendingDeletion.append( uid );
+ mUidMap.remove( uid );
+
+ Resource::removeAddressee( addr );
+}
+
+/*
+ * These are the DCOP slots that KMail call to notify when something
+ * changed.
+ */
+bool KABC::ResourceKolab::fromKMailAddIncidence( const TQString& type,
+ const TQString& subResource,
+ TQ_UINT32 sernum,
+ int format,
+ const TQString& contactXML )
+{
+ // Check if this is a contact
+ if( type != s_kmailContentsType || !subresourceActive( subResource ) )
+ return false;
+
+ // Load contact to find the UID
+ const TQString uid = loadContact( contactXML, subResource, sernum,
+ ( KMailICalIface::StorageFormat )format );
+
+ //kdDebug(5650) << k_funcinfo << uid << endl;
+
+ // Emit "addressbook changed" if this comes from kmail and not from the GUI
+ if ( !mUidsPendingAdding.contains( uid )
+ && !mUidsPendingUpdate.contains( uid ) ) {
+ addressBook()->emitAddressBookChanged();
+ } else {
+ mUidsPendingAdding.remove( uid );
+ mUidsPendingUpdate.remove( uid );
+ }
+
+ return true;
+}
+
+void KABC::ResourceKolab::fromKMailDelIncidence( const TQString& type,
+ const TQString& subResource,
+ const TQString& uid )
+{
+ // Check if this is a contact
+ if( type != s_kmailContentsType || !subresourceActive( subResource ) )
+ return;
+
+ //kdDebug(5650) << k_funcinfo << uid << endl;
+
+ // Can't be in both, by contract
+ if ( mUidsPendingDeletion.contains( uid ) ) {
+ mUidsPendingDeletion.remove( uid );
+ } else if ( mUidsPendingUpdate.contains( uid ) ) {
+ // It's good to know if was deleted, but we are waiting on a new one to
+ // replace it, so let's just sit tight.
+ } else {
+ // We didn't trigger this, so KMail did, remove the reference to the uid
+ mAddrMap.remove( uid );
+ mUidMap.remove( uid );
+ addressBook()->emitAddressBookChanged();
+ }
+}
+
+void KABC::ResourceKolab::fromKMailRefresh( const TQString& type,
+ const TQString& /*subResource*/ )
+{
+ // Check if this is a contact
+ if( type != s_kmailContentsType ) return;
+
+ //kdDebug(5650) << k_funcinfo << endl;
+
+ load(); // ### should call loadSubResource(subResource) probably
+ addressBook()->emitAddressBookChanged();
+}
+
+void KABC::ResourceKolab::fromKMailAddSubresource( const TQString& type,
+ const TQString& subResource,
+ const TQString& label,
+ bool writable,
+ bool )
+{
+ if( type != s_kmailContentsType ) return;
+
+ if ( mSubResources.contains( subResource ) )
+ // Already registered
+ return;
+
+ TDEConfig config( configFile() );
+ config.setGroup( "Contact" );
+ loadSubResourceConfig( config, subResource, label, writable );
+ loadSubResource( subResource );
+ addressBook()->emitAddressBookChanged();
+ emit signalSubresourceAdded( this, type, subResource );
+}
+
+void KABC::ResourceKolab::fromKMailDelSubresource( const TQString& type,
+ const TQString& subResource )
+{
+ if( type != s_kmailContentsType ) return;
+
+ if ( !mSubResources.contains( subResource ) )
+ // Not registered
+ return;
+
+ // Ok, it's our job, and we have it here
+ mSubResources.erase( subResource );
+
+ TDEConfig config( configFile() );
+ config.deleteGroup( subResource );
+ config.sync();
+
+ // Make a list of all uids to remove
+ Kolab::UidMap::ConstIterator mapIt;
+ TQStringList uids;
+ for ( mapIt = mUidMap.begin(); mapIt != mUidMap.end(); ++mapIt )
+ if ( mapIt.data().resource() == subResource )
+ // We have a match
+ uids << mapIt.key();
+
+ // Finally delete all the incidences
+ if ( !uids.isEmpty() ) {
+ TQStringList::ConstIterator it;
+ for ( it = uids.begin(); it != uids.end(); ++it ) {
+ mAddrMap.remove( *it );
+ mUidMap.remove( *it );
+ }
+
+ addressBook()->emitAddressBookChanged();
+ }
+
+ emit signalSubresourceRemoved( this, type, subResource );
+}
+
+
+
+void KABC::ResourceKolab::fromKMailAsyncLoadResult( const TQMap<TQ_UINT32, TQString>& map,
+ const TQString& /* type */,
+ const TQString& folder )
+{
+ // FIXME
+ KMailICalIface::StorageFormat format = KMailICalIface::StorageXML;
+ for( TQMap<TQ_UINT32, TQString>::ConstIterator it = map.begin(); it != map.end(); ++it ) {
+ loadContact( it.data(), folder, it.key(), format );
+ }
+ if ( !addressBook() ){
+ kdDebug(5650) << "asyncLoadResult() : addressBook() returning NULL pointer.\n";
+ }else
+ addressBook()->emitAddressBookChanged();
+}
+
+TQStringList KABC::ResourceKolab::subresources() const
+{
+ return mSubResources.keys();
+}
+
+bool KABC::ResourceKolab::subresourceActive( const TQString& subresource ) const
+{
+ if ( mSubResources.contains( subresource ) ) {
+ return mSubResources[ subresource ].active();
+ }
+
+ // Safe default bet:
+ kdDebug(5650) << "subresourceActive( " << subresource << " ): Safe bet\n";
+
+ return true;
+}
+
+bool KABC::ResourceKolab::subresourceWritable( const TQString& subresource ) const
+{
+ if ( mSubResources.contains( subresource ) ) {
+ return mSubResources[ subresource ].writable();
+ }
+ return false; //better a safe default
+}
+
+int KABC::ResourceKolab::subresourceCompletionWeight( const TQString& subresource ) const
+{
+ if ( mSubResources.contains( subresource ) ) {
+ return mSubResources[ subresource ].completionWeight();
+ }
+
+ kdDebug(5650) << "subresourceCompletionWeight( " << subresource << " ): not found, using default\n";
+
+ return 80;
+}
+
+TQString KABC::ResourceKolab::subresourceLabel( const TQString& subresource ) const
+{
+ if ( mSubResources.contains( subresource ) ) {
+ return mSubResources[ subresource ].label();
+ }
+
+ kdDebug(5650) << "subresourceLabel( " << subresource << " ): not found!\n";
+ return TQString();
+}
+
+void KABC::ResourceKolab::setSubresourceCompletionWeight( const TQString& subresource, int completionWeight )
+{
+ if ( mSubResources.contains( subresource ) ) {
+ mSubResources[ subresource ].setCompletionWeight( completionWeight );
+ } else {
+ kdDebug(5650) << "setSubresourceCompletionWeight: subresource " << subresource << " not found" << endl;
+ }
+}
+
+TQMap<TQString, TQString> KABC::ResourceKolab::uidToResourceMap() const
+{
+ // TODO: Couldn't this be made simpler?
+ TQMap<TQString, TQString> map;
+ Kolab::UidMap::ConstIterator mapIt;
+ for ( mapIt = mUidMap.begin(); mapIt != mUidMap.end(); ++mapIt )
+ map[ mapIt.key() ] = mapIt.data().resource();
+ return map;
+}
+
+void KABC::ResourceKolab::setSubresourceActive( const TQString &subresource, bool active )
+{
+ if ( mSubResources.contains( subresource ) ) {
+ mSubResources[ subresource ].setActive( active );
+ load();
+ } else {
+ kdDebug(5650) << "setSubresourceCompletionWeight: subresource " << subresource << " not found" << endl;
+ }
+ writeConfig();
+}
+
+
+/*virtual*/
+bool KABC::ResourceKolab::addSubresource( const TQString& label, const TQString& parent )
+{
+ return kmailAddSubresource( label, parent, s_kmailContentsType );
+}
+
+/*virtual*/
+bool KABC::ResourceKolab::removeSubresource( const TQString& id )
+{
+ return kmailRemoveSubresource( id );
+}
+
+void KABC::ResourceKolab::writeConfig()
+{
+ TDEConfig config( configFile() );
+
+ Kolab::ResourceMap::ConstIterator it;
+ for ( it = mSubResources.constBegin(); it != mSubResources.constEnd(); ++it ) {
+ config.setGroup( it.key() );
+ config.writeEntry( "Active", it.data().active() );
+ config.writeEntry( "CompletionWeight", it.data().completionWeight() );
+ }
+}
+
+#include "resourcekolab.moc"
diff --git a/tderesources/kolab/kabc/resourcekolab.h b/tderesources/kolab/kabc/resourcekolab.h
new file mode 100644
index 000000000..3a142b209
--- /dev/null
+++ b/tderesources/kolab/kabc/resourcekolab.h
@@ -0,0 +1,179 @@
+/*
+ This file is part of libkabc and/or kaddressbook.
+ Copyright (c) 2002 - 2004 Klarälvdalens Datakonsult AB
+ <info@klaralvdalens-datakonsult.se>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ TQt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef KABC_RESOURCEKOLAB_H
+#define KABC_RESOURCEKOLAB_H
+
+#include <libtdepim/resourceabc.h>
+#include <dcopobject.h>
+#include "../shared/resourcekolabbase.h"
+#include "../shared/subresource.h"
+#include <kmail/kmailicalIface.h>
+#include <tdepimmacros.h>
+
+namespace KABC {
+
+ class FormatPlugin;
+
+/**
+ * This class implements a KAddressBook resource that keeps its
+ * addresses in an Kolab folder in KMail (or other conforming email
+ * clients).
+ */
+class KDE_EXPORT ResourceKolab : public KPIM::ResourceABC,
+ public Kolab::ResourceKolabBase
+{
+ Q_OBJECT
+
+
+public:
+ /**
+ * Constructor
+ */
+ ResourceKolab( const TDEConfig* );
+
+ /**
+ * Destructor.
+ */
+ virtual ~ResourceKolab();
+
+ /**
+ * Open the contacts list
+ */
+ virtual bool doOpen();
+
+ /**
+ * Request a ticket, you have to pass through save() to
+ * allow locking.
+ */
+ virtual Ticket *requestSaveTicket();
+
+ /**
+ Releases the ticket previousely requested with requestSaveTicket().
+ The resource has to remove its locks in this function.
+ */
+ virtual void releaseSaveTicket( Ticket* );
+
+ /**
+ * Load all addressees to the addressbook
+ */
+ virtual bool load();
+
+ /**
+ * Save all addressees to the addressbook.
+ *
+ * @param ticket The ticket you get by requestSaveTicket()
+ */
+ virtual bool save( Ticket *ticket );
+
+ /**
+ Insert an addressee into the resource.
+ */
+ virtual void insertAddressee( const Addressee& );
+
+ /**
+ * Removes a addressee from resource. This method is mainly
+ * used by record-based resources like LDAP or SQL.
+ */
+ virtual void removeAddressee( const Addressee& addr );
+
+ // Listen to KMail changes in the amount of sub resources
+ void fromKMailAddSubresource( const TQString& type, const TQString& id,
+ const TQString& label, bool writable,
+ bool alarmRelevant );
+ void fromKMailDelSubresource( const TQString& type, const TQString& id );
+
+ bool fromKMailAddIncidence( const TQString& type, const TQString& resource,
+ TQ_UINT32 sernum, int format, const TQString& contact );
+ void fromKMailDelIncidence( const TQString& type, const TQString& resource,
+ const TQString& contact );
+ void fromKMailRefresh( const TQString& type, const TQString& resource );
+
+ void fromKMailAsyncLoadResult( const TQMap<TQ_UINT32, TQString>& map,
+ const TQString& type,
+ const TQString& folder );
+
+ /// Return the list of subresources.
+ TQStringList subresources() const;
+
+ /// Is this subresource active?
+ bool subresourceActive( const TQString& ) const;
+ /// Is this subresource writable?
+ virtual bool subresourceWritable( const TQString& ) const;
+
+ virtual void setSubresourceActive( const TQString &, bool );
+
+ virtual bool addSubresource( const TQString&, const TQString& );
+
+ virtual bool removeSubresource( const TQString& );
+
+ virtual bool canHaveSubresources() const { return true; }
+
+ /// Completion weight for a given subresource
+ virtual int subresourceCompletionWeight( const TQString& ) const;
+
+ /// Label for a given subresource
+ virtual TQString subresourceLabel( const TQString& ) const;
+
+ /// Set completion weight for a given subresource
+ virtual void setSubresourceCompletionWeight( const TQString&, int );
+
+ /// Give the uidmap. Used for ordered searching
+ TQMap<TQString, TQString> uidToResourceMap() const;
+
+protected:
+ bool kmailUpdateAddressee( const Addressee& );
+
+ void doClose();
+
+ void loadSubResourceConfig( TDEConfig& config, const TQString& name,
+ const TQString& label, bool writable );
+ bool loadSubResource( const TQString& subResource );
+ TQString loadContact( const TQString& contactData, const TQString& subResource,
+ TQ_UINT32 sernum, const KMailICalIface::StorageFormat format );
+
+ TQString configFile() const {
+ return Kolab::ResourceKolabBase::configFile( "kabc" );
+ }
+
+ void writeConfig();
+
+ // The list of subresources
+ Kolab::ResourceMap mSubResources;
+ TQString mCachedSubresource;
+ bool mCachedSubresourceNotFound;
+ bool mLocked;
+};
+
+}
+
+#endif // KABC_RESOURCEKOLAB_H
diff --git a/tderesources/kolab/kabc/resourcekolab_plugin.cpp b/tderesources/kolab/kabc/resourcekolab_plugin.cpp
new file mode 100644
index 000000000..55ac64205
--- /dev/null
+++ b/tderesources/kolab/kabc/resourcekolab_plugin.cpp
@@ -0,0 +1,52 @@
+/*
+ This file is part of libkabc and/or kaddressbook.
+ Copyright (c) 2002 - 2004 Klarlvdalens Datakonsult AB
+ <info@klaralvdalens-datakonsult.se>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ TQt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "resourcekolab.h"
+
+using namespace Kolab;
+
+class KolabFactory : public KRES::PluginFactoryBase
+{
+ public:
+ KRES::Resource *resource( const TDEConfig *config )
+ {
+ return new KABC::ResourceKolab( config );
+ }
+
+ KRES::ConfigWidget *configWidget( TQWidget* )
+ {
+ return 0;
+ }
+};
+
+K_EXPORT_COMPONENT_FACTORY(kabc_kolab,KolabFactory)
+
diff --git a/tderesources/kolab/kcal/CMakeLists.txt b/tderesources/kolab/kcal/CMakeLists.txt
new file mode 100644
index 000000000..9f932b5e1
--- /dev/null
+++ b/tderesources/kolab/kcal/CMakeLists.txt
@@ -0,0 +1,57 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/../shared
+ ${CMAKE_CURRENT_SOURCE_DIR}/../kcal
+ ${CMAKE_SOURCE_DIR}
+ ${CMAKE_SOURCE_DIR}/libtdepim
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install(
+ FILES kolab.desktop
+ DESTINATION ${SERVICES_INSTALL_DIR}/tderesources/kcal )
+
+install(
+ FILES ${CMAKE_CURRENT_SOURCE_DIR}/../uninstall.desktop
+ DESTINATION ${SERVICES_INSTALL_DIR}/tderesources/kcal
+ RENAME imap.desktop)
+
+
+##### kcal_kolab (module) #######################
+
+tde_add_kpart( kcal_kolab AUTOMOC
+ SOURCES
+ resourcekolab_plugin.cpp
+ LINK kcalkolab-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
+
+
+##### kcalkolab (shared) ########################
+
+tde_add_library( kcalkolab SHARED AUTOMOC
+ SOURCES
+ incidence.cpp event.cpp task.cpp journal.cpp resourcekolab.cpp
+ VERSION 0.0.0
+ LINK resourcekolabshared-static kgroupwarebase-shared
+ DESTINATION ${LIB_INSTALL_DIR}
+)
diff --git a/tderesources/kolab/kcal/Makefile.am b/tderesources/kolab/kcal/Makefile.am
new file mode 100644
index 000000000..a25027919
--- /dev/null
+++ b/tderesources/kolab/kcal/Makefile.am
@@ -0,0 +1,27 @@
+METASOURCES = AUTO
+
+INCLUDES = -I$(top_srcdir)/tderesources/kolab/shared -I$(top_srcdir) \
+ -I$(top_builddir)/libtdepim $(all_includes)
+
+# The kolab wizard links to this library too
+lib_LTLIBRARIES = libkcalkolab.la
+
+libkcalkolab_la_SOURCES = incidence.cpp event.cpp task.cpp journal.cpp resourcekolab.cpp
+libkcalkolab_la_LDFLAGS = $(all_libraries) -no-undefined
+libkcalkolab_la_LIBADD = $(top_builddir)/libkcal/libkcal.la \
+ $(top_builddir)/tderesources/kolab/shared/libresourcekolabshared.la \
+ -ltderesources
+
+kde_module_LTLIBRARIES = kcal_kolab.la
+
+kcal_kolab_la_SOURCES = resourcekolab_plugin.cpp
+kcal_kolab_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) -no-undefined
+kcal_kolab_la_LIBADD = libkcalkolab.la
+
+servicedir = $(kde_servicesdir)/tderesources/kcal
+service_DATA = kolab.desktop
+
+install-data-local: $(srcdir)/../uninstall.desktop
+ $(mkinstalldirs) $(DESTDIR)$(servicedir)
+ $(INSTALL_DATA) $(srcdir)/../uninstall.desktop $(DESTDIR)$(servicedir)/imap.desktop
+
diff --git a/tderesources/kolab/kcal/event.cpp b/tderesources/kolab/kcal/event.cpp
new file mode 100644
index 000000000..c15c567d8
--- /dev/null
+++ b/tderesources/kolab/kcal/event.cpp
@@ -0,0 +1,223 @@
+/*
+ This file is part of the kolab resource - the implementation of the
+ Kolab storage format. See www.kolab.org for documentation on this.
+
+ Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ TQt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "event.h"
+
+#include <libkcal/event.h>
+#include <kdebug.h>
+
+using namespace Kolab;
+
+
+KCal::Event* Event::xmlToEvent( const TQString& xml, const TQString& tz, KCal::ResourceKolab* res,
+ const TQString& subResource, TQ_UINT32 sernum )
+{
+ Event event( res, subResource, sernum, tz );
+ event.load( xml );
+ KCal::Event* kcalEvent = new KCal::Event();
+ event.saveTo( kcalEvent );
+ return kcalEvent;
+}
+
+TQString Event::eventToXML( KCal::Event* kcalEvent, const TQString& tz )
+{
+ Event event( 0, TQString(), 0, tz, kcalEvent );
+ return event.saveXML();
+}
+
+Event::Event( KCal::ResourceKolab *res, const TQString &subResource, TQ_UINT32 sernum,
+ const TQString& tz, KCal::Event* event )
+ : Incidence( res, subResource, sernum, tz ),
+ mShowTimeAs( KCal::Event::Opaque ), mHasEndDate( false )
+{
+ if ( event )
+ setFields( event );
+}
+
+Event::~Event()
+{
+}
+
+void Event::setTransparency( KCal::Event::Transparency transparency )
+{
+ mShowTimeAs = transparency;
+}
+
+KCal::Event::Transparency Event::transparency() const
+{
+ return mShowTimeAs;
+}
+
+void Event::setEndDate( const TQDateTime& date )
+{
+ mEndDate = date;
+ mHasEndDate = true;
+ if ( mFloatingStatus == AllDay )
+ kdDebug() << "ERROR: Time on end date but no time on the event\n";
+ mFloatingStatus = HasTime;
+}
+
+void Event::setEndDate( const TQDate& date )
+{
+ mEndDate = date;
+ mHasEndDate = true;
+ if ( mFloatingStatus == HasTime )
+ kdDebug() << "ERROR: No time on end date but time on the event\n";
+ mFloatingStatus = AllDay;
+}
+
+void Event::setEndDate( const TQString& endDate )
+{
+ if ( endDate.length() > 10 )
+ // This is a date + time
+ setEndDate( stringToDateTime( endDate ) );
+ else
+ // This is only a date
+ setEndDate( stringToDate( endDate ) );
+}
+
+TQDateTime Event::endDate() const
+{
+ return mEndDate;
+}
+
+bool Event::loadAttribute( TQDomElement& element )
+{
+ // This method doesn't handle the color-label tag yet
+ TQString tagName = element.tagName();
+
+ if ( tagName == "show-time-as" ) {
+ // TODO: Support tentative and outofoffice
+ if ( element.text() == "free" )
+ setTransparency( KCal::Event::Transparent );
+ else
+ setTransparency( KCal::Event::Opaque );
+ } else if ( tagName == "end-date" )
+ setEndDate( element.text() );
+ else
+ return Incidence::loadAttribute( element );
+
+ // We handled this
+ return true;
+}
+
+bool Event::saveAttributes( TQDomElement& element ) const
+{
+ // Save the base class elements
+ Incidence::saveAttributes( element );
+
+ // TODO: Support tentative and outofoffice
+ if ( transparency() == KCal::Event::Transparent )
+ writeString( element, "show-time-as", "free" );
+ else
+ writeString( element, "show-time-as", "busy" );
+ if ( mHasEndDate ) {
+ if ( mFloatingStatus == HasTime )
+ writeString( element, "end-date", dateTimeToString( endDate() ) );
+ else
+ writeString( element, "end-date", dateToString( endDate().date() ) );
+ }
+
+ return true;
+}
+
+
+bool Event::loadXML( const TQDomDocument& document )
+{
+ TQDomElement top = document.documentElement();
+
+ if ( top.tagName() != "event" ) {
+ tqWarning( "XML error: Top tag was %s instead of the expected event",
+ top.tagName().ascii() );
+ return false;
+ }
+
+ for ( TQDomNode n = top.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ TQDomElement e = n.toElement();
+ loadAttribute( e );
+ } else
+ kdDebug() << "Node is not a comment or an element???" << endl;
+ }
+
+ loadAttachments();
+ return true;
+}
+
+TQString Event::saveXML() const
+{
+ TQDomDocument document = domTree();
+ TQDomElement element = document.createElement( "event" );
+ element.setAttribute( "version", "1.0" );
+ saveAttributes( element );
+ document.appendChild( element );
+ return document.toString();
+}
+
+void Event::setFields( const KCal::Event* event )
+{
+ Incidence::setFields( event );
+
+ // note: if hasEndDate() is false and hasDuration() is true
+ // dtEnd() returns start+duration
+ if ( event->hasEndDate() || event->hasDuration() ) {
+ if ( event->doesFloat() ) {
+ // This is a floating event. Don't timezone move this one
+ mFloatingStatus = AllDay;
+ setEndDate( event->dtEnd().date() );
+ } else {
+ mFloatingStatus = HasTime;
+ setEndDate( localToUTC( event->dtEnd() ) );
+ }
+ } else {
+ mHasEndDate = false;
+ }
+ setTransparency( event->transparency() );
+}
+
+void Event::saveTo( KCal::Event* event )
+{
+ Incidence::saveTo( event );
+
+ event->setHasEndDate( mHasEndDate );
+ if ( mHasEndDate ) {
+ if ( mFloatingStatus == AllDay )
+ // This is a floating event. Don't timezone move this one
+ event->setDtEnd( endDate() );
+ else
+ event->setDtEnd( utcToLocal( endDate() ) );
+ }
+ event->setTransparency( transparency() );
+}
diff --git a/tderesources/kolab/kcal/event.h b/tderesources/kolab/kcal/event.h
new file mode 100644
index 000000000..57aa3358f
--- /dev/null
+++ b/tderesources/kolab/kcal/event.h
@@ -0,0 +1,102 @@
+/*
+ This file is part of the kolab resource - the implementation of the
+ Kolab storage format. See www.kolab.org for documentation on this.
+
+ Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ TQt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef KOLAB_EVENT_H
+#define KOLAB_EVENT_H
+
+#include "incidence.h"
+
+#include <libkcal/event.h>
+
+class TQDomElement;
+
+
+namespace Kolab {
+
+/**
+ * This class represents an event, and knows how to load/save it
+ * from/to XML, and from/to a KCal::Event.
+ * The instances of this class are temporary, only used to convert
+ * one to the other.
+ */
+class Event : public Incidence {
+public:
+ /// Use this to parse an xml string to a event entry
+ /// The caller is responsible for deleting the returned event
+ static KCal::Event* xmlToEvent( const TQString& xml, const TQString& tz, KCal::ResourceKolab* res = 0,
+ const TQString& subResource = TQString(), TQ_UINT32 sernum = 0 );
+
+ /// Use this to get an xml string describing this event entry
+ static TQString eventToXML( KCal::Event*, const TQString& tz );
+
+ /// Create a event object and
+ explicit Event( KCal::ResourceKolab *res, const TQString &subResource, TQ_UINT32 sernum,
+ const TQString& tz, KCal::Event* event = 0 );
+ virtual ~Event();
+
+ void saveTo( KCal::Event* event );
+
+ virtual TQString type() const { return "Event"; }
+
+ virtual void setTransparency( KCal::Event::Transparency transparency );
+ virtual KCal::Event::Transparency transparency() const;
+
+ virtual void setEndDate( const TQDateTime& date );
+ virtual void setEndDate( const TQDate& date );
+ virtual void setEndDate( const TQString& date );
+ virtual TQDateTime endDate() const;
+
+ // Load the attributes of this class
+ virtual bool loadAttribute( TQDomElement& );
+
+ // Save the attributes of this class
+ virtual bool saveAttributes( TQDomElement& ) const;
+
+ // Load this event by reading the XML file
+ virtual bool loadXML( const TQDomDocument& xml );
+
+ // Serialize this event to an XML string
+ virtual TQString saveXML() const;
+
+protected:
+ // Read all known fields from this ical incidence
+ void setFields( const KCal::Event* );
+
+ KCal::Event::Transparency mShowTimeAs;
+ TQDateTime mEndDate;
+ bool mHasEndDate;
+};
+
+}
+
+#endif // KOLAB_EVENT_H
diff --git a/tderesources/kolab/kcal/incidence.cpp b/tderesources/kolab/kcal/incidence.cpp
new file mode 100644
index 000000000..ddc31491b
--- /dev/null
+++ b/tderesources/kolab/kcal/incidence.cpp
@@ -0,0 +1,1039 @@
+/*
+ This file is part of the kolab resource - the implementation of the
+ Kolab storage format. See www.kolab.org for documentation on this.
+
+ Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ TQt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "incidence.h"
+#include "resourcekolab.h"
+
+#include <tqfile.h>
+#include <tqvaluelist.h>
+
+#include <libkcal/journal.h>
+#include <korganizer/version.h>
+#include <libemailfunctions/email.h>
+
+#include <kdebug.h>
+#include <kmdcodec.h>
+#include <kurl.h>
+#include <kio/netaccess.h>
+
+using namespace Kolab;
+
+
+Incidence::Incidence( KCal::ResourceKolab *res, const TQString &subResource, TQ_UINT32 sernum,
+ const TQString& tz )
+ : KolabBase( tz ), mFloatingStatus( Unset ), mHasAlarm( false ),
+ mResource( res ),
+ mSubResource( subResource ),
+ mSernum( sernum )
+{
+}
+
+Incidence::~Incidence()
+{
+}
+
+void Incidence::setSummary( const TQString& summary )
+{
+ mSummary = summary;
+}
+
+TQString Incidence::summary() const
+{
+ return mSummary;
+}
+
+void Incidence::setLocation( const TQString& location )
+{
+ mLocation = location;
+}
+
+TQString Incidence::location() const
+{
+ return mLocation;
+}
+
+void Incidence::setOrganizer( const Email& organizer )
+{
+ mOrganizer = organizer;
+}
+
+KolabBase::Email Incidence::organizer() const
+{
+ return mOrganizer;
+}
+
+void Incidence::setStartDate( const TQDateTime& startDate )
+{
+ mStartDate = startDate;
+ if ( mFloatingStatus == AllDay )
+ kdDebug() << "ERROR: Time on start date but no time on the event\n";
+ mFloatingStatus = HasTime;
+}
+
+void Incidence::setStartDate( const TQDate& startDate )
+{
+ mStartDate = startDate;
+ if ( mFloatingStatus == HasTime )
+ kdDebug() << "ERROR: No time on start date but time on the event\n";
+ mFloatingStatus = AllDay;
+}
+
+void Incidence::setStartDate( const TQString& startDate )
+{
+ if ( startDate.length() > 10 )
+ // This is a date + time
+ setStartDate( stringToDateTime( startDate ) );
+ else
+ // This is only a date
+ setStartDate( stringToDate( startDate ) );
+}
+
+TQDateTime Incidence::startDate() const
+{
+ return mStartDate;
+}
+
+void Incidence::setAlarm( float alarm )
+{
+ mAlarm = alarm;
+ mHasAlarm = true;
+}
+
+float Incidence::alarm() const
+{
+ return mAlarm;
+}
+
+Incidence::Recurrence Incidence::recurrence() const
+{
+ return mRecurrence;
+}
+
+void Incidence::addAttendee( const Attendee& attendee )
+{
+ mAttendees.append( attendee );
+}
+
+TQValueList<Incidence::Attendee>& Incidence::attendees()
+{
+ return mAttendees;
+}
+
+const TQValueList<Incidence::Attendee>& Incidence::attendees() const
+{
+ return mAttendees;
+}
+
+void Incidence::setInternalUID( const TQString& iuid )
+{
+ mInternalUID = iuid;
+}
+
+TQString Incidence::internalUID() const
+{
+ return mInternalUID;
+}
+
+bool Incidence::loadAttendeeAttribute( TQDomElement& element,
+ Attendee& attendee )
+{
+ for ( TQDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ TQDomElement e = n.toElement();
+ TQString tagName = e.tagName();
+
+ if ( tagName == "display-name" ) {
+ // Quote the text in case it contains commas or other quotable chars.
+ TQString tusername = KPIM::quoteNameIfNecessary( e.text() );
+
+ TQString tname, temail;
+ // ignore the return value because it will always be false since
+ // tusername does not contain "@domain".
+ KPIM::getNameAndMail( tusername, tname, temail );
+ attendee.displayName = tname;
+ }
+ else if ( tagName == "smtp-address" )
+ attendee.smtpAddress = e.text();
+ else if ( tagName == "status" )
+ attendee.status = e.text();
+ else if ( tagName == "request-response" )
+ // This sets reqResp to false, if the text is "false". Otherwise it
+ // sets it to true. This means the default setting is true.
+ attendee.requestResponse = ( e.text().lower() != "false" );
+ else if ( tagName == "invitation-sent" )
+ // Like above, only this defaults to false
+ attendee.invitationSent = ( e.text().lower() != "true" );
+ else if ( tagName == "role" )
+ attendee.role = e.text();
+ else if ( tagName == "delegated-to" )
+ attendee.delegate = e.text();
+ else if ( tagName == "delegated-from" )
+ attendee.delegator = e.text();
+ else
+ // TODO: Unhandled tag - save for later storage
+ kdDebug() << "Warning: Unhandled tag " << e.tagName() << endl;
+ } else
+ kdDebug() << "Node is not a comment or an element???" << endl;
+ }
+
+ return true;
+}
+
+void Incidence::saveAttendeeAttribute( TQDomElement& element,
+ const Attendee& attendee ) const
+{
+ TQDomElement e = element.ownerDocument().createElement( "attendee" );
+ element.appendChild( e );
+ writeString( e, "display-name", attendee.displayName );
+ writeString( e, "smtp-address", attendee.smtpAddress );
+ writeString( e, "status", attendee.status );
+ writeString( e, "request-response",
+ ( attendee.requestResponse ? "true" : "false" ) );
+ writeString( e, "invitation-sent",
+ ( attendee.invitationSent ? "true" : "false" ) );
+ writeString( e, "role", attendee.role );
+ writeString( e, "delegated-to", attendee.delegate );
+ writeString( e, "delegated-from", attendee.delegator );
+}
+
+void Incidence::saveAttendees( TQDomElement& element ) const
+{
+ TQValueList<Attendee>::ConstIterator it = mAttendees.begin();
+ for ( ; it != mAttendees.end(); ++it )
+ saveAttendeeAttribute( element, *it );
+}
+
+void Incidence::saveAttachments( TQDomElement& element ) const
+{
+ KCal::Attachment::List::ConstIterator it = mAttachments.begin();
+ for ( ; it != mAttachments.end(); ++it ) {
+ KCal::Attachment *a = (*it);
+ if ( a->isUri() ) {
+ writeString( element, "link-attachment", a->uri() );
+ } else if ( a->isBinary() ) {
+ writeString( element, "inline-attachment", a->label() );
+ }
+ }
+}
+
+void Incidence::saveAlarms( TQDomElement& element ) const
+{
+ if ( mAlarms.isEmpty() ) return;
+
+ TQDomElement list = element.ownerDocument().createElement( "advanced-alarms" );
+ element.appendChild( list );
+ for ( KCal::Alarm::List::ConstIterator it = mAlarms.constBegin(); it != mAlarms.constEnd(); ++it ) {
+ KCal::Alarm* a = *it;
+ TQDomElement e = list.ownerDocument().createElement( "alarm" );
+ list.appendChild( e );
+
+ writeString( e, "enabled", a->enabled() ? "1" : "0" );
+ if ( a->hasStartOffset() ) {
+ writeString( e, "start-offset", TQString::number( a->startOffset().asSeconds()/60 ) );
+ }
+ if ( a->hasEndOffset() ) {
+ writeString( e, "end-offset", TQString::number( a->endOffset().asSeconds()/60 ) );
+ }
+ if ( a->repeatCount() ) {
+ writeString( e, "repeat-count", TQString::number( a->repeatCount() ) );
+ writeString( e, "repeat-interval", TQString::number( a->snoozeTime() ) );
+ }
+
+ switch ( a->type() ) {
+ case KCal::Alarm::Invalid:
+ break;
+ case KCal::Alarm::Display:
+ e.setAttribute( "type", "display" );
+ writeString( e, "text", a->text() );
+ break;
+ case KCal::Alarm::Procedure:
+ e.setAttribute( "type", "procedure" );
+ writeString( e, "program", a->programFile() );
+ writeString( e, "arguments", a->programArguments() );
+ break;
+ case KCal::Alarm::Email:
+ {
+ e.setAttribute( "type", "email" );
+ TQDomElement addresses = e.ownerDocument().createElement( "addresses" );
+ e.appendChild( addresses );
+ for ( TQValueList<KCal::Person>::ConstIterator it = a->mailAddresses().constBegin(); it != a->mailAddresses().constEnd(); ++it ) {
+ writeString( addresses, "address", (*it).fullName() );
+ }
+ writeString( e, "subject", a->mailSubject() );
+ writeString( e, "mail-text", a->mailText() );
+ TQDomElement attachments = e.ownerDocument().createElement( "attachments" );
+ e.appendChild( attachments );
+ for ( TQStringList::ConstIterator it = a->mailAttachments().constBegin(); it != a->mailAttachments().constEnd(); ++it ) {
+ writeString( attachments, "attachment", *it );
+ }
+ break;
+ }
+ case KCal::Alarm::Audio:
+ e.setAttribute( "type", "audio" );
+ writeString( e, "file", a->audioFile() );
+ break;
+ default:
+ kdWarning() << "Unhandled alarm type:" << a->type() << endl;
+ break;
+ }
+ }
+}
+
+void Incidence::saveRecurrence( TQDomElement& element ) const
+{
+ TQDomElement e = element.ownerDocument().createElement( "recurrence" );
+ element.appendChild( e );
+ e.setAttribute( "cycle", mRecurrence.cycle );
+ if ( !mRecurrence.type.isEmpty() )
+ e.setAttribute( "type", mRecurrence.type );
+ writeString( e, "interval", TQString::number( mRecurrence.interval ) );
+ for( TQStringList::ConstIterator it = mRecurrence.days.begin(); it != mRecurrence.days.end(); ++it ) {
+ writeString( e, "day", *it );
+ }
+ if ( !mRecurrence.dayNumber.isEmpty() )
+ writeString( e, "daynumber", mRecurrence.dayNumber );
+ if ( !mRecurrence.month.isEmpty() )
+ writeString( e, "month", mRecurrence.month );
+ if ( !mRecurrence.rangeType.isEmpty() ) {
+ TQDomElement range = element.ownerDocument().createElement( "range" );
+ e.appendChild( range );
+ range.setAttribute( "type", mRecurrence.rangeType );
+ TQDomText t = element.ownerDocument().createTextNode( mRecurrence.range );
+ range.appendChild( t );
+ }
+ for( TQValueList<TQDate>::ConstIterator it = mRecurrence.exclusions.begin();
+ it != mRecurrence.exclusions.end(); ++it ) {
+ writeString( e, "exclusion", dateToString( *it ) );
+ }
+}
+
+void Incidence::loadRecurrence( const TQDomElement& element )
+{
+ mRecurrence.interval = 0;
+ mRecurrence.cycle = element.attribute( "cycle" );
+ mRecurrence.type = element.attribute( "type" );
+ for ( TQDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ TQDomElement e = n.toElement();
+ TQString tagName = e.tagName();
+
+ if ( tagName == "interval" ) {
+ //kolab/issue4229, sometimes the interval value can be empty
+ if ( e.text().isEmpty() || e.text().toInt() <= 0 ) {
+ mRecurrence.interval = 1;
+ } else {
+ mRecurrence.interval = e.text().toInt();
+ }
+ }
+ else if ( tagName == "day" ) // can be present multiple times
+ mRecurrence.days.append( e.text() );
+ else if ( tagName == "daynumber" )
+ mRecurrence.dayNumber = e.text();
+ else if ( tagName == "month" )
+ mRecurrence.month = e.text();
+ else if ( tagName == "range" ) {
+ mRecurrence.rangeType = e.attribute( "type" );
+ mRecurrence.range = e.text();
+ } else if ( tagName == "exclusion" ) {
+ mRecurrence.exclusions.append( stringToDate( e.text() ) );
+ } else
+ // TODO: Unhandled tag - save for later storage
+ kdDebug() << "Warning: Unhandled tag " << e.tagName() << endl;
+ }
+ }
+}
+
+static void loadAddressesHelper( const TQDomElement& element, KCal::Alarm* a )
+{
+ for ( TQDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ TQDomElement e = n.toElement();
+ TQString tagName = e.tagName();
+
+ if ( tagName == "address" ) {
+ a->addMailAddress( KCal::Person( e.text() ) );
+ } else {
+ kdWarning() << "Unhandled tag" << tagName << endl;
+ }
+ }
+ }
+}
+
+static void loadAttachmentsHelper( const TQDomElement& element, KCal::Alarm* a )
+{
+ for ( TQDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ TQDomElement e = n.toElement();
+ TQString tagName = e.tagName();
+
+ if ( tagName == "attachment" ) {
+ a->addMailAttachment( e.text() );
+ } else {
+ kdWarning() << "Unhandled tag" << tagName << endl;
+ }
+ }
+ }
+}
+
+static void loadAlarmHelper( const TQDomElement& element, KCal::Alarm* a )
+{
+ for ( TQDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ TQDomElement e = n.toElement();
+ TQString tagName = e.tagName();
+
+ if ( tagName == "start-offset" ) {
+ a->setStartOffset( e.text().toInt()*60 );
+ } else if ( tagName == "end-offset" ) {
+ a->setEndOffset( e.text().toInt()*60 );
+ } else if ( tagName == "repeat-count" ) {
+ a->setRepeatCount( e.text().toInt() );
+ } else if ( tagName == "repeat-interval" ) {
+ a->setSnoozeTime( e.text().toInt() );
+ } else if ( tagName == "text" ) {
+ a->setText( e.text() );
+ } else if ( tagName == "program" ) {
+ a->setProgramFile( e.text() );
+ } else if ( tagName == "arguments" ) {
+ a->setProgramArguments( e.text() );
+ } else if ( tagName == "addresses" ) {
+ loadAddressesHelper( e, a );
+ } else if ( tagName == "subject" ) {
+ a->setMailSubject( e.text() );
+ } else if ( tagName == "mail-text" ) {
+ a->setMailText( e.text() );
+ } else if ( tagName == "attachments" ) {
+ loadAttachmentsHelper( e, a );
+ } else if ( tagName == "file" ) {
+ a->setAudioFile( e.text() );
+ } else if ( tagName == "enabled" ) {
+ a->setEnabled( e.text().toInt() != 0 );
+ } else {
+ kdWarning() << "Unhandled tag" << tagName << endl;
+ }
+ }
+ }
+}
+
+void Incidence::loadAlarms( const TQDomElement& element )
+{
+ for ( TQDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ TQDomElement e = n.toElement();
+ TQString tagName = e.tagName();
+
+ if ( tagName == "alarm" ) {
+ KCal::Alarm *a = new KCal::Alarm( 0 );
+ a->setEnabled( true ); // default to enabled, unless some XML attribute says otherwise.
+ TQString type = e.attribute( "type" );
+ if ( type == "display" ) {
+ a->setType( KCal::Alarm::Display );
+ } else if ( type == "procedure" ) {
+ a->setType( KCal::Alarm::Procedure );
+ } else if ( type == "email" ) {
+ a->setType( KCal::Alarm::Email );
+ } else if ( type == "audio" ) {
+ a->setType( KCal::Alarm::Audio );
+ } else {
+ kdWarning() << "Unhandled alarm type:" << type << endl;
+ }
+
+ loadAlarmHelper( e, a );
+ mAlarms << a;
+ } else {
+ kdWarning() << "Unhandled tag" << tagName << endl;
+ }
+ }
+ }
+}
+
+bool Incidence::loadAttribute( TQDomElement& element )
+{
+ TQString tagName = element.tagName();
+
+ if ( tagName == "summary" )
+ setSummary( element.text() );
+ else if ( tagName == "location" )
+ setLocation( element.text() );
+ else if ( tagName == "organizer" ) {
+ Email email;
+ if ( loadEmailAttribute( element, email ) ) {
+ setOrganizer( email );
+ return true;
+ } else
+ return false;
+ } else if ( tagName == "start-date" )
+ setStartDate( element.text() );
+ else if ( tagName == "recurrence" )
+ loadRecurrence( element );
+ else if ( tagName == "attendee" ) {
+ Attendee attendee;
+ if ( loadAttendeeAttribute( element, attendee ) ) {
+ addAttendee( attendee );
+ return true;
+ } else
+ return false;
+ } else if ( tagName == "link-attachment" ) {
+ mAttachments.push_back( new KCal::Attachment( element.text() ) );
+ } else if ( tagName == "alarm" )
+ // Alarms should be minutes before. Libkcal uses event time + alarm time
+ setAlarm( - element.text().toInt() );
+ else if ( tagName == "advanced-alarms" )
+ loadAlarms( element );
+ else if ( tagName == "x-kde-internaluid" )
+ setInternalUID( element.text() );
+ else if ( tagName == "x-custom" )
+ loadCustomAttributes( element );
+ else {
+ bool ok = KolabBase::loadAttribute( element );
+ if ( !ok ) {
+ // Unhandled tag - save for later storage
+ //kdDebug() << "Saving unhandled tag " << element.tagName() << endl;
+ Custom c;
+ c.key = TQCString( "X-TDE-KolabUnhandled-" ) + element.tagName().latin1();
+ c.value = element.text();
+ mCustomList.append( c );
+ }
+ }
+ // We handled this
+ return true;
+}
+
+bool Incidence::saveAttributes( TQDomElement& element ) const
+{
+ // Save the base class elements
+ KolabBase::saveAttributes( element );
+
+ if ( mFloatingStatus == HasTime )
+ writeString( element, "start-date", dateTimeToString( startDate() ) );
+ else
+ writeString( element, "start-date", dateToString( startDate().date() ) );
+ writeString( element, "summary", summary() );
+ writeString( element, "location", location() );
+ saveEmailAttribute( element, organizer(), "organizer" );
+ if ( !mRecurrence.cycle.isEmpty() )
+ saveRecurrence( element );
+ saveAttendees( element );
+ saveAttachments( element );
+ if ( mHasAlarm ) {
+ // Alarms should be minutes before. Libkcal uses event time + alarm time
+ int alarmTime = tqRound( -alarm() );
+ writeString( element, "alarm", TQString::number( alarmTime ) );
+ }
+ saveAlarms( element );
+ writeString( element, "x-kde-internaluid", internalUID() );
+ saveCustomAttributes( element );
+ return true;
+}
+
+void Incidence::saveCustomAttributes( TQDomElement& element ) const
+{
+ TQValueList<Custom>::ConstIterator it = mCustomList.begin();
+ for ( ; it != mCustomList.end(); ++it ) {
+ TQString key = (*it).key;
+ Q_ASSERT( !key.isEmpty() );
+ if ( key.startsWith( "X-TDE-KolabUnhandled-" ) ) {
+ key = key.mid( strlen( "X-TDE-KolabUnhandled-" ) );
+ writeString( element, key, (*it).value );
+ } else {
+ // Let's use attributes so that other tag-preserving-code doesn't need sub-elements
+ TQDomElement e = element.ownerDocument().createElement( "x-custom" );
+ element.appendChild( e );
+ e.setAttribute( "key", key );
+ e.setAttribute( "value", (*it).value );
+ }
+ }
+}
+
+void Incidence::loadCustomAttributes( TQDomElement& element )
+{
+ Custom custom;
+ custom.key = element.attribute( "key" ).latin1();
+ custom.value = element.attribute( "value" );
+ mCustomList.append( custom );
+}
+
+static KCal::Attendee::PartStat attendeeStringToStatus( const TQString& s )
+{
+ if ( s == "none" )
+ return KCal::Attendee::NeedsAction;
+ if ( s == "tentative" )
+ return KCal::Attendee::Tentative;
+ if ( s == "accepted" )
+ return KCal::Attendee::Accepted;
+ if ( s == "declined" )
+ return KCal::Attendee::Declined;
+ if ( s == "delegated" )
+ return KCal::Attendee::Delegated;
+
+ // Default:
+ return KCal::Attendee::None;
+}
+
+static TQString attendeeStatusToString( KCal::Attendee::PartStat status )
+{
+ switch( status ) {
+ case KCal::Attendee::NeedsAction:
+ return "none";
+ case KCal::Attendee::Accepted:
+ return "accepted";
+ case KCal::Attendee::Declined:
+ return "declined";
+ case KCal::Attendee::Tentative:
+ return "tentative";
+ case KCal::Attendee::Delegated:
+ return "delegated";
+ case KCal::Attendee::Completed:
+ case KCal::Attendee::InProcess:
+ // These don't have any meaning in the Kolab format, so just use:
+ return "accepted";
+ }
+
+ // Default for the case that there are more added later:
+ return "accepted";
+}
+
+static KCal::Attendee::Role attendeeStringToRole( const TQString& s )
+{
+ if ( s == "optional" )
+ return KCal::Attendee::OptParticipant;
+ if ( s == "resource" )
+ return KCal::Attendee::NonParticipant;
+ return KCal::Attendee::ReqParticipant;
+}
+
+static TQString attendeeRoleToString( KCal::Attendee::Role role )
+{
+ switch( role ) {
+ case KCal::Attendee::ReqParticipant:
+ return "required";
+ case KCal::Attendee::OptParticipant:
+ return "optional";
+ case KCal::Attendee::Chair:
+ // We don't have the notion of chair, so use
+ return "required";
+ case KCal::Attendee::NonParticipant:
+ // In Kolab, a non-participant is a resource
+ return "resource";
+ }
+
+ // Default for the case that there are more added later:
+ return "required";
+}
+
+static const char *s_weekDayName[] =
+{
+ "monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"
+};
+
+static const char *s_monthName[] =
+{
+ "january", "february", "march", "april", "may", "june", "july",
+ "august", "september", "october", "november", "december"
+};
+
+void Incidence::setRecurrence( KCal::Recurrence* recur )
+{
+ mRecurrence.interval = recur->frequency();
+ switch ( recur->recurrenceType() ) {
+ case KCal::Recurrence::rMinutely: // Not handled by the kolab XML
+ mRecurrence.cycle = "minutely";
+ break;
+ case KCal::Recurrence::rHourly: // Not handled by the kolab XML
+ mRecurrence.cycle = "hourly";
+ break;
+ case KCal::Recurrence::rDaily:
+ mRecurrence.cycle = "daily";
+ break;
+ case KCal::Recurrence::rWeekly: // every X weeks
+ mRecurrence.cycle = "weekly";
+ {
+ TQBitArray arr = recur->days();
+ for ( uint idx = 0 ; idx < 7 ; ++idx )
+ if ( arr.testBit( idx ) )
+ mRecurrence.days.append( s_weekDayName[idx] );
+ }
+ break;
+ case KCal::Recurrence::rMonthlyPos: {
+ mRecurrence.cycle = "monthly";
+ mRecurrence.type = "weekday";
+ TQValueList<KCal::RecurrenceRule::WDayPos> monthPositions = recur->monthPositions();
+ if ( !monthPositions.isEmpty() ) {
+ KCal::RecurrenceRule::WDayPos monthPos = monthPositions.first();
+ // TODO: Handle multiple days in the same week
+ mRecurrence.dayNumber = TQString::number( monthPos.pos() );
+ mRecurrence.days.append( s_weekDayName[ monthPos.day()-1 ] );
+ // Not (properly) handled(?): monthPos.negative (nth days before end of month)
+ }
+ break;
+ }
+ case KCal::Recurrence::rMonthlyDay: {
+ mRecurrence.cycle = "monthly";
+ mRecurrence.type = "daynumber";
+ TQValueList<int> monthDays = recur->monthDays();
+ // ####### Kolab XML limitation: only the first month day is used
+ if ( !monthDays.isEmpty() )
+ mRecurrence.dayNumber = TQString::number( monthDays.first() );
+ break;
+ }
+ case KCal::Recurrence::rYearlyMonth: // (day n of Month Y)
+ {
+ mRecurrence.cycle = "yearly";
+ mRecurrence.type = "monthday";
+ TQValueList<int> rmd = recur->yearDates();
+ int day = !rmd.isEmpty() ? rmd.first() : recur->startDate().day();
+ mRecurrence.dayNumber = TQString::number( day );
+ TQValueList<int> months = recur->yearMonths();
+ if ( !months.isEmpty() )
+ mRecurrence.month = s_monthName[ months.first() - 1 ]; // #### Kolab XML limitation: only one month specified
+ break;
+ }
+ case KCal::Recurrence::rYearlyDay: // YearlyDay (day N of the year). Not supported by Outlook
+ mRecurrence.cycle = "yearly";
+ mRecurrence.type = "yearday";
+ mRecurrence.dayNumber = TQString::number( recur->yearDays().first() );
+ break;
+ case KCal::Recurrence::rYearlyPos: // (weekday X of week N of month Y)
+ mRecurrence.cycle = "yearly";
+ mRecurrence.type = "weekday";
+ TQValueList<int> months = recur->yearMonths();
+ if ( !months.isEmpty() )
+ mRecurrence.month = s_monthName[ months.first() - 1 ]; // #### Kolab XML limitation: only one month specified
+ TQValueList<KCal::RecurrenceRule::WDayPos> monthPositions = recur->yearPositions();
+ if ( !monthPositions.isEmpty() ) {
+ KCal::RecurrenceRule::WDayPos monthPos = monthPositions.first();
+ // TODO: Handle multiple days in the same week
+ mRecurrence.dayNumber = TQString::number( monthPos.pos() );
+ mRecurrence.days.append( s_weekDayName[ monthPos.day()-1 ] );
+
+ //mRecurrence.dayNumber = TQString::number( *recur->yearNums().getFirst() );
+ // Not handled: monthPos.negative (nth days before end of month)
+ }
+ break;
+ }
+ int howMany = recur->duration();
+ if ( howMany > 0 ) {
+ mRecurrence.rangeType = "number";
+ mRecurrence.range = TQString::number( howMany );
+ } else if ( howMany == 0 ) {
+ mRecurrence.rangeType = "date";
+ mRecurrence.range = dateToString( recur->endDate() );
+ } else {
+ mRecurrence.rangeType = "none";
+ }
+}
+
+void Incidence::setFields( const KCal::Incidence* incidence )
+{
+ KolabBase::setFields( incidence );
+
+ if ( incidence->doesFloat() ) {
+ // This is a floating event. Don't timezone move this one
+ mFloatingStatus = AllDay;
+ setStartDate( incidence->dtStart().date() );
+ } else {
+ mFloatingStatus = HasTime;
+ setStartDate( localToUTC( incidence->dtStart() ) );
+ }
+
+ setSummary( incidence->summary() );
+ setLocation( incidence->location() );
+
+ // Alarm
+ mHasAlarm = false; // Will be set to true, if we actually have one
+ if ( incidence->isAlarmEnabled() ) {
+ const KCal::Alarm::List& alarms = incidence->alarms();
+ if ( !alarms.isEmpty() ) {
+ const KCal::Alarm* alarm = alarms.first();
+ if ( alarm->hasStartOffset() ) {
+ int dur = alarm->startOffset().asSeconds();
+ setAlarm( (float)dur / 60.0 );
+ }
+ }
+ }
+
+ Email org( incidence->organizer().name(), incidence->organizer().email() );
+ setOrganizer( org );
+
+ // Attendees:
+ KCal::Attendee::List attendees = incidence->attendees();
+ KCal::Attendee::List::ConstIterator it;
+ for ( it = attendees.begin(); it != attendees.end(); ++it ) {
+ KCal::Attendee* kcalAttendee = *it;
+ Attendee attendee;
+
+ attendee.displayName = kcalAttendee->name();
+ attendee.smtpAddress = kcalAttendee->email();
+ attendee.status = attendeeStatusToString( kcalAttendee->status() );
+ attendee.requestResponse = kcalAttendee->RSVP();
+ // TODO: KCal::Attendee::mFlag is not accessible
+ // attendee.invitationSent = kcalAttendee->mFlag;
+ // DF: Hmm? mFlag is set to true and never used at all.... Did you mean another field?
+ attendee.role = attendeeRoleToString( kcalAttendee->role() );
+ attendee.delegate = kcalAttendee->delegate();
+ attendee.delegator = kcalAttendee->delegator();
+
+ addAttendee( attendee );
+ }
+
+ mAttachments.clear();
+
+ // Attachments
+ KCal::Attachment::List attachments = incidence->attachments();
+ KCal::Attachment::List::ConstIterator it2;
+ for ( it2 = attachments.begin(); it2 != attachments.end(); ++it2 ) {
+ KCal::Attachment *a = *it2;
+ mAttachments.push_back( a );
+ }
+
+ mAlarms.clear();
+
+ // Alarms
+ const KCal::Alarm::List alarms = incidence->alarms();
+ for ( KCal::Alarm::List::ConstIterator it = alarms.begin(); it != alarms.end(); ++it ) {
+ mAlarms.push_back( *it );
+ }
+
+ if ( incidence->doesRecur() ) {
+ setRecurrence( incidence->recurrence() );
+ mRecurrence.exclusions = incidence->recurrence()->exDates();
+ }
+
+ // Handle the scheduling ID
+ if ( incidence->schedulingID() == incidence->uid() ) {
+ // There is no scheduling ID
+ setInternalUID( TQString() );
+ } else {
+ // We've internally been using a different uid, so save that as the
+ // temporary (internal) uid and restore the original uid, the one that
+ // is used in the folder and the outside world
+ setUid( incidence->schedulingID() );
+ setInternalUID( incidence->uid() );
+ }
+
+ if ( incidence->pilotId() != 0 )
+ setPilotSyncId( incidence->pilotId() );
+
+ setPilotSyncStatus( incidence->syncStatus() );
+
+ // Unhandled tags and other custom properties (see libkcal/customproperties.h)
+ const TQMap<TQCString, TQString> map = incidence->customProperties();
+ TQMap<TQCString, TQString>::ConstIterator cit = map.begin();
+ for ( ; cit != map.end() ; ++cit ) {
+ Custom c;
+ c.key = cit.key();
+ c.value = cit.data();
+ mCustomList.append( c );
+ }
+}
+
+static TQBitArray daysListToBitArray( const TQStringList& days )
+{
+ TQBitArray arr( 7 );
+ arr.fill( false );
+ for( TQStringList::ConstIterator it = days.begin(); it != days.end(); ++it ) {
+ for ( uint i = 0; i < 7 ; ++i )
+ if ( *it == s_weekDayName[i] )
+ arr.setBit( i, true );
+ }
+ return arr;
+}
+
+
+void Incidence::saveTo( KCal::Incidence* incidence )
+{
+ KolabBase::saveTo( incidence );
+
+ if ( mFloatingStatus == AllDay ) {
+ // This is a floating event. Don't timezone move this one
+ incidence->setDtStart( startDate() );
+ incidence->setFloats( true );
+ } else {
+ incidence->setDtStart( utcToLocal( startDate() ) );
+ incidence->setFloats( false );
+ }
+
+ incidence->setSummary( summary() );
+ incidence->setLocation( location() );
+
+ if ( mHasAlarm && mAlarms.isEmpty() ) {
+ KCal::Alarm* alarm = incidence->newAlarm();
+ alarm->setStartOffset( tqRound( mAlarm * 60.0 ) );
+ alarm->setEnabled( true );
+ alarm->setType( KCal::Alarm::Display );
+ } else if ( !mAlarms.isEmpty() ) {
+ for ( KCal::Alarm::List::ConstIterator it = mAlarms.constBegin(); it != mAlarms.constEnd(); ++it ) {
+ KCal::Alarm *alarm = *it;
+ alarm->setParent( incidence );
+ incidence->addAlarm( alarm );
+ }
+ }
+
+ if ( organizer().displayName.isEmpty() )
+ incidence->setOrganizer( organizer().smtpAddress );
+ else
+ incidence->setOrganizer( organizer().displayName + "<"
+ + organizer().smtpAddress + ">" );
+
+ incidence->clearAttendees();
+ TQValueList<Attendee>::ConstIterator it;
+ for ( it = mAttendees.begin(); it != mAttendees.end(); ++it ) {
+ KCal::Attendee::PartStat status = attendeeStringToStatus( (*it).status );
+ KCal::Attendee::Role role = attendeeStringToRole( (*it).role );
+ KCal::Attendee* attendee = new KCal::Attendee( (*it).displayName,
+ (*it).smtpAddress,
+ (*it).requestResponse,
+ status, role );
+ attendee->setDelegate( (*it).delegate );
+ attendee->setDelegator( (*it).delegator );
+ incidence->addAttendee( attendee );
+ }
+
+ incidence->clearAttachments();
+ KCal::Attachment::List::ConstIterator it2;
+ for ( it2 = mAttachments.begin(); it2 != mAttachments.end(); ++it2 ) {
+ KCal::Attachment *a = (*it2);
+ // TODO should we copy?
+ incidence->addAttachment( a );
+ }
+
+ if ( !mRecurrence.cycle.isEmpty() ) {
+ KCal::Recurrence* recur = incidence->recurrence(); // yeah, this creates it
+ // done below recur->setFrequency( mRecurrence.interval );
+ if ( mRecurrence.cycle == "minutely" ) {
+ recur->setMinutely( mRecurrence.interval );
+ } else if ( mRecurrence.cycle == "hourly" ) {
+ recur->setHourly( mRecurrence.interval );
+ } else if ( mRecurrence.cycle == "daily" ) {
+ recur->setDaily( mRecurrence.interval );
+ } else if ( mRecurrence.cycle == "weekly" ) {
+ TQBitArray rDays = daysListToBitArray( mRecurrence.days );
+ recur->setWeekly( mRecurrence.interval, rDays );
+ } else if ( mRecurrence.cycle == "monthly" ) {
+ recur->setMonthly( mRecurrence.interval );
+ if ( mRecurrence.type == "weekday" ) {
+ recur->addMonthlyPos( mRecurrence.dayNumber.toInt(), daysListToBitArray( mRecurrence.days ) );
+ } else if ( mRecurrence.type == "daynumber" ) {
+ recur->addMonthlyDate( mRecurrence.dayNumber.toInt() );
+ } else kdWarning() << "Unhandled monthly recurrence type " << mRecurrence.type << endl;
+ } else if ( mRecurrence.cycle == "yearly" ) {
+ recur->setYearly( mRecurrence.interval );
+ if ( mRecurrence.type == "monthday" ) {
+ recur->addYearlyDate( mRecurrence.dayNumber.toInt() );
+ for ( int i = 0; i < 12; ++i )
+ if ( s_monthName[ i ] == mRecurrence.month )
+ recur->addYearlyMonth( i+1 );
+ } else if ( mRecurrence.type == "yearday" ) {
+ recur->addYearlyDay( mRecurrence.dayNumber.toInt() );
+ } else if ( mRecurrence.type == "weekday" ) {
+ for ( int i = 0; i < 12; ++i )
+ if ( s_monthName[ i ] == mRecurrence.month )
+ recur->addYearlyMonth( i+1 );
+ recur->addYearlyPos( mRecurrence.dayNumber.toInt(), daysListToBitArray( mRecurrence.days ) );
+ } else kdWarning() << "Unhandled yearly recurrence type " << mRecurrence.type << endl;
+ } else kdWarning() << "Unhandled recurrence cycle " << mRecurrence.cycle << endl;
+
+ if ( mRecurrence.rangeType == "number" ) {
+ recur->setDuration( mRecurrence.range.toInt() );
+ } else if ( mRecurrence.rangeType == "date" ) {
+ recur->setEndDate( stringToDate( mRecurrence.range ) );
+ } // "none" is default since tje set*ly methods set infinite recurrence
+
+ incidence->recurrence()->setExDates( mRecurrence.exclusions );
+
+ }
+ /* If we've stored a uid to be used internally instead of the real one
+ * (to deal with duplicates of events in different folders) before, then
+ * restore it, so it does not change. Keep the original uid around for
+ * scheduling purposes. */
+ if ( !internalUID().isEmpty() ) {
+ incidence->setUid( internalUID() );
+ incidence->setSchedulingID( uid() );
+ }
+ if ( hasPilotSyncId() )
+ incidence->setPilotId( pilotSyncId() );
+ if ( hasPilotSyncStatus() )
+ incidence->setSyncStatus( pilotSyncStatus() );
+
+ for( TQValueList<Custom>::ConstIterator it = mCustomList.constBegin(); it != mCustomList.constEnd(); ++it ) {
+ incidence->setNonKDECustomProperty( (*it).key, (*it).value );
+ }
+
+}
+
+void Incidence::loadAttachments()
+{
+ TQStringList attachments;
+ if ( mResource->kmailListAttachments( attachments, mSubResource, mSernum ) ) {
+ for ( TQStringList::ConstIterator it = attachments.constBegin(); it != attachments.constEnd(); ++it ) {
+ TQByteArray data;
+ KURL url;
+ if ( mResource->kmailGetAttachment( url, mSubResource, mSernum, *it ) && !url.isEmpty() ) {
+ TQFile f( url.path() );
+ if ( f.open( IO_ReadOnly ) ) {
+ data = f.readAll();
+ TQString mimeType;
+ if ( !mResource->kmailAttachmentMimetype( mimeType, mSubResource, mSernum, *it ) )
+ mimeType = "application/octet-stream";
+ KCal::Attachment *a = new KCal::Attachment( KCodecs::base64Encode( data ).data(), mimeType );
+ a->setLabel( *it );
+ mAttachments.append( a );
+ f.close();
+ }
+ f.remove();
+ }
+ }
+ }
+}
+
+TQString Incidence::productID() const
+{
+ return TQString( "KOrganizer %1, Kolab resource" ).arg( korgVersion );
+}
+
+// Unhandled KCal::Incidence fields:
+// revision, status (unused), priority (done in tasks), attendee.uid,
+// mComments, mReadOnly
+
diff --git a/tderesources/kolab/kcal/incidence.h b/tderesources/kolab/kcal/incidence.h
new file mode 100644
index 000000000..926ec1e4f
--- /dev/null
+++ b/tderesources/kolab/kcal/incidence.h
@@ -0,0 +1,175 @@
+/*
+ This file is part of the kolab resource - the implementation of the
+ Kolab storage format. See www.kolab.org for documentation on this.
+
+ Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ TQt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef KOLAB_INCIDENCE_H
+#define KOLAB_INCIDENCE_H
+
+#include <kolabbase.h>
+
+class TQDomElement;
+
+namespace KCal {
+ class Incidence;
+ class Recurrence;
+ class Alarm;
+ class Attachment;
+ class ResourceKolab;
+}
+
+namespace Kolab {
+
+/**
+ * This abstract class represents an incidence which has the shared
+ * fields, of events and tasks and knows how to load/save these
+ * from/to XML, and from/to a KCal::Incidence.
+ */
+class Incidence : public KolabBase {
+public:
+ struct Recurrence {
+ TQString cycle;
+ TQString type;
+ int interval;
+ TQStringList days; // list of days-of-the-week
+ TQString dayNumber;
+ TQString month;
+ TQString rangeType;
+ TQString range; // date or number or nothing
+ TQValueList<TQDate> exclusions;
+ };
+
+ struct Attendee : Email {
+ Attendee() : requestResponse( true ), invitationSent( false ) {}
+ TQString status;
+ bool requestResponse;
+ bool invitationSent;
+ TQString role;
+ TQString delegate;
+ TQString delegator;
+ };
+
+ explicit Incidence( KCal::ResourceKolab *res, const TQString &subResource, TQ_UINT32 sernum,
+ const TQString& tz );
+ virtual ~Incidence();
+
+ void saveTo( KCal::Incidence* incidence );
+
+ virtual void setSummary( const TQString& summary );
+ virtual TQString summary() const;
+
+ virtual void setLocation( const TQString& location );
+ virtual TQString location() const;
+
+ virtual void setOrganizer( const Email& organizer );
+ virtual Email organizer() const;
+
+ virtual void setStartDate( const TQDateTime& startDate );
+ virtual void setStartDate( const TQDate& startDate );
+ virtual void setStartDate( const TQString& startDate );
+ virtual TQDateTime startDate() const;
+
+ virtual void setAlarm( float alarm );
+ virtual float alarm() const;
+
+ virtual void setRecurrence( KCal::Recurrence* recur );
+ virtual Recurrence recurrence() const;
+
+ virtual void addAttendee( const Attendee& attendee );
+ TQValueList<Attendee>& attendees();
+ const TQValueList<Attendee>& attendees() const;
+
+ /**
+ * The internal uid is used as the uid inside KOrganizer whenever
+ * two or more events with the same uid appear, which KOrganizer
+ * can't handle. To avoid keep that interal uid from changing all the
+ * time, it is persisted in the XML between a save and the next load.
+ */
+ void setInternalUID( const TQString& iuid );
+ TQString internalUID() const;
+
+ // Load the attributes of this class
+ virtual bool loadAttribute( TQDomElement& );
+
+ // Save the attributes of this class
+ virtual bool saveAttributes( TQDomElement& ) const;
+
+protected:
+ enum FloatingStatus { Unset, AllDay, HasTime };
+
+ // Read all known fields from this ical incidence
+ void setFields( const KCal::Incidence* );
+
+ bool loadAttendeeAttribute( TQDomElement&, Attendee& );
+ void saveAttendeeAttribute( TQDomElement& element,
+ const Attendee& attendee ) const;
+ void saveAttendees( TQDomElement& element ) const;
+ void saveAttachments( TQDomElement& element ) const;
+
+ void loadAlarms( const TQDomElement& element );
+ void saveAlarms( TQDomElement& element ) const;
+
+ void loadRecurrence( const TQDomElement& element );
+ void saveRecurrence( TQDomElement& element ) const;
+ void saveCustomAttributes( TQDomElement& element ) const;
+ void loadCustomAttributes( TQDomElement& element );
+
+ void loadAttachments();
+
+ TQString productID() const;
+
+ TQString mSummary;
+ TQString mLocation;
+ Email mOrganizer;
+ TQDateTime mStartDate;
+ FloatingStatus mFloatingStatus;
+ float mAlarm;
+ bool mHasAlarm;
+ Recurrence mRecurrence;
+ TQValueList<Attendee> mAttendees;
+ TQValueList<KCal::Alarm*> mAlarms;
+ TQValueList<KCal::Attachment*> mAttachments;
+ TQString mInternalUID;
+
+ struct Custom {
+ TQCString key;
+ TQString value;
+ };
+ TQValueList<Custom> mCustomList;
+
+ KCal::ResourceKolab *mResource;
+ TQString mSubResource;
+ TQ_UINT32 mSernum;
+};
+
+}
+
+#endif // KOLAB_INCIDENCE_H
diff --git a/tderesources/kolab/kcal/journal.cpp b/tderesources/kolab/kcal/journal.cpp
new file mode 100644
index 000000000..acfc4e71d
--- /dev/null
+++ b/tderesources/kolab/kcal/journal.cpp
@@ -0,0 +1,184 @@
+/*
+ This file is part of the kolab resource - the implementation of the
+ Kolab storage format. See www.kolab.org for documentation on this.
+
+ Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ TQt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "journal.h"
+
+#include <libkcal/journal.h>
+#include <korganizer/version.h>
+#include <kdebug.h>
+
+using namespace Kolab;
+
+
+KCal::Journal* Journal::xmlToJournal( const TQString& xml, const TQString& tz )
+{
+ Journal journal( tz );
+ journal.load( xml );
+ KCal::Journal* kcalJournal = new KCal::Journal();
+ journal.saveTo( kcalJournal );
+ return kcalJournal;
+}
+
+TQString Journal::journalToXML( KCal::Journal* kcalJournal, const TQString& tz )
+{
+ Journal journal( tz, kcalJournal );
+ return journal.saveXML();
+}
+
+Journal::Journal( const TQString& tz, KCal::Journal* journal )
+ : KolabBase( tz )
+{
+ if ( journal )
+ setFields( journal );
+}
+
+Journal::~Journal()
+{
+}
+
+void Journal::setSummary( const TQString& summary )
+{
+ mSummary = summary;
+}
+
+TQString Journal::summary() const
+{
+ return mSummary;
+}
+
+void Journal::setStartDate( const TQDateTime& startDate )
+{
+ mStartDate = startDate;
+}
+
+TQDateTime Journal::startDate() const
+{
+ return mStartDate;
+}
+
+void Journal::setEndDate( const TQDateTime& endDate )
+{
+ mEndDate = endDate;
+}
+
+TQDateTime Journal::endDate() const
+{
+ return mEndDate;
+}
+
+bool Journal::loadAttribute( TQDomElement& element )
+{
+ TQString tagName = element.tagName();
+
+ if ( tagName == "summary" )
+ setSummary( element.text() );
+ else if ( tagName == "start-date" )
+ setStartDate( stringToDateTime( element.text() ) );
+ else
+ // Not handled here
+ return KolabBase::loadAttribute( element );
+
+ // We handled this
+ return true;
+}
+
+bool Journal::saveAttributes( TQDomElement& element ) const
+{
+ // Save the base class elements
+ KolabBase::saveAttributes( element );
+
+ writeString( element, "summary", summary() );
+ writeString( element, "start-date", dateTimeToString( startDate() ) );
+
+ return true;
+}
+
+
+bool Journal::loadXML( const TQDomDocument& document )
+{
+ TQDomElement top = document.documentElement();
+
+ if ( top.tagName() != "journal" ) {
+ tqWarning( "XML error: Top tag was %s instead of the expected Journal",
+ top.tagName().ascii() );
+ return false;
+ }
+
+ for ( TQDomNode n = top.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ TQDomElement e = n.toElement();
+ if ( !loadAttribute( e ) ) {
+ // Unhandled tag - save for later storage
+ //tqDebug( "Unhandled tag: %s", e.toCString().data() );
+ }
+ } else
+ tqDebug( "Node is not a comment or an element???" );
+ }
+
+ return true;
+}
+
+TQString Journal::saveXML() const
+{
+ TQDomDocument document = domTree();
+ TQDomElement element = document.createElement( "journal" );
+ element.setAttribute( "version", "1.0" );
+ saveAttributes( element );
+ document.appendChild( element );
+ return document.toString();
+}
+
+void Journal::saveTo( KCal::Journal* journal )
+{
+ KolabBase::saveTo( journal );
+
+ journal->setSummary( summary() );
+ journal->setDtStart( utcToLocal( startDate() ) );
+}
+
+void Journal::setFields( const KCal::Journal* journal )
+{
+ // Set baseclass fields
+ KolabBase::setFields( journal );
+
+ // Set our own fields
+ setSummary( journal->summary() );
+ setStartDate( localToUTC( journal->dtStart() ) );
+}
+
+TQString Journal::productID() const
+{
+ return TQString( "KOrganizer " ) + korgVersion + ", Kolab resource";
+}
diff --git a/tderesources/kolab/kcal/journal.h b/tderesources/kolab/kcal/journal.h
new file mode 100644
index 000000000..cd583c6ca
--- /dev/null
+++ b/tderesources/kolab/kcal/journal.h
@@ -0,0 +1,103 @@
+/*
+ This file is part of the kolab resource - the implementation of the
+ Kolab storage format. See www.kolab.org for documentation on this.
+
+ Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ TQt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef KOLAB_JOURNAL_H
+#define KOLAB_JOURNAL_H
+
+#include <kolabbase.h>
+
+class TQDomElement;
+
+namespace KCal {
+ class Journal;
+}
+
+namespace Kolab {
+
+/**
+ * This class represents a journal entry, and knows how to load/save it
+ * from/to XML, and from/to a KCal::Journal.
+ * The instances of this class are temporary, only used to convert
+ * one to the other.
+ */
+class Journal : public KolabBase {
+public:
+ /// Use this to parse an xml string to a journal entry
+ /// The caller is responsible for deleting the returned journal
+ static KCal::Journal* xmlToJournal( const TQString& xml, const TQString& tz );
+
+ /// Use this to get an xml string describing this journal entry
+ static TQString journalToXML( KCal::Journal*, const TQString& tz );
+
+ explicit Journal( const TQString& tz, KCal::Journal* journal = 0 );
+ virtual ~Journal();
+
+ virtual TQString type() const { return "Journal"; }
+
+ void saveTo( KCal::Journal* journal );
+
+ virtual void setSummary( const TQString& summary );
+ virtual TQString summary() const;
+
+ virtual void setStartDate( const TQDateTime& startDate );
+ virtual TQDateTime startDate() const;
+
+ virtual void setEndDate( const TQDateTime& endDate );
+ virtual TQDateTime endDate() const;
+
+ // Load the attributes of this class
+ virtual bool loadAttribute( TQDomElement& );
+
+ // Save the attributes of this class
+ virtual bool saveAttributes( TQDomElement& ) const;
+
+ // Load this journal by reading the XML file
+ virtual bool loadXML( const TQDomDocument& xml );
+
+ // Serialize this journal to an XML string
+ virtual TQString saveXML() const;
+
+protected:
+ // Read all known fields from this ical journal
+ void setFields( const KCal::Journal* );
+
+ TQString productID() const;
+
+ TQString mSummary;
+ TQDateTime mStartDate;
+ TQDateTime mEndDate;
+};
+
+}
+
+#endif // KOLAB_JOURNAL_H
diff --git a/tderesources/kolab/kcal/kolab.desktop b/tderesources/kolab/kcal/kolab.desktop
new file mode 100644
index 000000000..40bcacb00
--- /dev/null
+++ b/tderesources/kolab/kcal/kolab.desktop
@@ -0,0 +1,52 @@
+[Desktop Entry]
+Name=Calendar on IMAP Server via KMail
+Name[af]=Kalender op IMAP bediener via KMail
+Name[bg]=Календар на сървър IMAP през KMail
+Name[br]=Deiziadur en ur servijer IMAP gant KMail
+Name[ca]=Calendari sobre servidor IMAP mitjançant KMail
+Name[cs]=Kalendář na IMAP serveru přes KMail
+Name[da]=Kalender på IMAP-server via KMail
+Name[de]=Kalender auf einem IMAP-Server via KMail
+Name[el]=Ημερολόγιο σε εξυπηρετητή IMAP μέσω του KMail
+Name[es]=Calendario en servidor IMAP por medio de KMail
+Name[et]=Kalender IMAP-serveris (KMaili vahendusel)
+Name[eu]=Egutegia IMAP zerbitzarian KMail-en bidez
+Name[fa]=تقویم روی کارساز IMAP از طریق KMail
+Name[fi]=Kalenteri IMAP-palvelimella KMailin avulla
+Name[fr]=Agenda sur serveur IMAP (via KMail)
+Name[fy]=Aginda op IMAP-tsjinner fia KMail
+Name[ga]=Féilire ar Fhreastalaí IMAP via KMail
+Name[gl]=Calendario no servidor IMAP mediante KMail
+Name[hu]=IMAP-kiszolgálón tárolt naptár a KMailen keresztül
+Name[is]=Dagatal á IMAP þjóni gegnum KMail
+Name[it]=Calendario su server IMAP via KMail
+Name[ja]=KMail 経由 IMAP サーバのカレンダー
+Name[kk]=KMail арқылы IMAP серверіндегі күнтізбе
+Name[km]=ប្រតិទិន​លើ​ម៉ាស៊ីន​បម្រើ IMAP តាម​រយៈ KMail
+Name[lt]=Kalendorius IMAP serveryje per KMail
+Name[mk]=Календар на IMAP-сервер преку КПошта
+Name[ms]=Kalendar pada pelayan IMAP melalui KMail
+Name[nb]=Kalender på IMAP-tjener via KMail
+Name[nds]=Kalenner op IMAP-Server över KMail
+Name[ne]=केडीई मेल मार्फत IMAP सर्भरमा क्यालेन्डर
+Name[nl]=Agenda op IMAP-server via KMail
+Name[nn]=Kalender på IMAP-tenar via KMail
+Name[pl]=Kalendarz na serwerze IMAP za pośrednictwem KMail
+Name[pt]=Calendário em Servidor IMAP via KMail
+Name[pt_BR]=Calendário em Servidor IMAP via KMail
+Name[ru]=Календарь на сервере IMAP через KMail
+Name[sk]=Kalendár na IMAP serveri pomocou KMail
+Name[sl]=Koledar na strežniku IMAP preko KMaila
+Name[sr]=Календар на IMAP серверу преко KMail-а
+Name[sr@Latn]=Kalendar na IMAP serveru preko KMail-a
+Name[sv]=Kalender på IMAP-server via Kmail
+Name[ta]=IMAP சேவையக வழியாக கேஅஞ்சலில் நாட்காட்டி
+Name[tr]=KMail Aracılığı ile IMAP Sunucusunda Takvim
+Name[uk]=Календар на сервері IMAP через KMail
+Name[zh_CN]=通过 KMail 访问 IMAP 服务器上的日历
+Name[zh_TW]=透過 KMail 取得 IMAP 伺服器上的行事曆
+X-TDE-Library=kcal_kolab
+Type=Service
+ServiceTypes=KResources/Plugin
+X-TDE-ResourceFamily=calendar
+X-TDE-ResourceType=imap
diff --git a/tderesources/kolab/kcal/resourcekolab.cpp b/tderesources/kolab/kcal/resourcekolab.cpp
new file mode 100644
index 000000000..44c13fd2b
--- /dev/null
+++ b/tderesources/kolab/kcal/resourcekolab.cpp
@@ -0,0 +1,1342 @@
+/*
+ This file is part of the kolab resource - the implementation of the
+ Kolab storage format. See www.kolab.org for documentation on this.
+
+ Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
+ 2004 Till Adam <till@klaralvdalens-datakonsult.se>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ TQt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "resourcekolab.h"
+#include "event.h"
+#include "task.h"
+#include "journal.h"
+
+#include <kio/observer.h>
+#include <kio/uiserver_stub.h>
+#include <kapplication.h>
+#include <dcopclient.h>
+#include <libtdepim/kincidencechooser.h>
+#include <kabc/locknull.h>
+#include <kmainwindow.h>
+#include <klocale.h>
+#include <kinputdialog.h>
+#include <ktempfile.h>
+#include <kmdcodec.h>
+
+#include <tqfile.h>
+#include <tqobject.h>
+#include <tqtimer.h>
+#include <tqapplication.h>
+
+#include <assert.h>
+
+using namespace KCal;
+using namespace Kolab;
+
+static const char* kmailCalendarContentsType = "Calendar";
+static const char* kmailTodoContentsType = "Task";
+static const char* kmailJournalContentsType = "Journal";
+static const char* eventAttachmentMimeType = "application/x-vnd.kolab.event";
+static const char* todoAttachmentMimeType = "application/x-vnd.kolab.task";
+static const char* journalAttachmentMimeType = "application/x-vnd.kolab.journal";
+static const char* incidenceInlineMimeType = "text/calendar";
+
+
+ResourceKolab::ResourceKolab( const TDEConfig *config )
+ : ResourceCalendar( config ), ResourceKolabBase( "ResourceKolab-libkcal" ),
+ mCalendar( TQString::fromLatin1("UTC") ), mOpen( false ),mResourceChangedTimer( 0,
+ "mResourceChangedTimer" ), mBatchAddingInProgress( false )
+{
+ if ( !config ) {
+ setResourceName( i18n( "Kolab Server" ) );
+ }
+ setType( "imap" );
+ connect( &mResourceChangedTimer, TQT_SIGNAL( timeout() ),
+ this, TQT_SLOT( slotEmitResourceChanged() ) );
+}
+
+ResourceKolab::~ResourceKolab()
+{
+ // The resource is deleted on exit (StdAddressBook's KStaticDeleter),
+ // and it wasn't closed before that, so close here to save the config.
+ if ( mOpen ) {
+ close();
+ }
+}
+
+void ResourceKolab::loadSubResourceConfig( TDEConfig& config,
+ const TQString& name,
+ const TQString& label,
+ bool writable,
+ bool alarmRelevant,
+ ResourceMap& subResource )
+{
+ TDEConfigGroup group( &config, name );
+ bool active = group.readBoolEntry( "Active", true );
+ subResource.insert( name, Kolab::SubResource( active, writable,
+ alarmRelevant, label ) );
+}
+
+bool ResourceKolab::openResource( TDEConfig& config, const char* contentType,
+ ResourceMap& map )
+{
+ // Read the subresource entries from KMail
+ TQValueList<KMailICalIface::SubResource> subResources;
+ if ( !kmailSubresources( subResources, contentType ) )
+ return false;
+ map.clear();
+ TQValueList<KMailICalIface::SubResource>::ConstIterator it;
+ for ( it = subResources.begin(); it != subResources.end(); ++it )
+ loadSubResourceConfig( config, (*it).location, (*it).label, (*it).writable,
+ (*it).alarmRelevant, map );
+ return true;
+}
+
+bool ResourceKolab::doOpen()
+{
+ if ( mOpen )
+ // Already open
+ return true;
+ mOpen = true;
+
+ TDEConfig config( configFile() );
+ config.setGroup( "General" );
+ mProgressDialogIncidenceLimit = config.readNumEntry("ProgressDialogIncidenceLimit", 200);
+
+ return openResource( config, kmailCalendarContentsType, mEventSubResources )
+ && openResource( config, kmailTodoContentsType, mTodoSubResources )
+ && openResource( config, kmailJournalContentsType, mJournalSubResources );
+}
+
+static void writeResourceConfig( TDEConfig& config, ResourceMap& map )
+{
+ ResourceMap::ConstIterator it;
+ for ( it = map.begin(); it != map.end(); ++it ) {
+ config.setGroup( it.key() );
+ config.writeEntry( "Active", it.data().active() );
+ }
+}
+
+void ResourceKolab::doClose()
+{
+ if ( !mOpen )
+ // Not open
+ return;
+ mOpen = false;
+
+ writeConfig();
+}
+
+bool ResourceKolab::loadSubResource( const TQString& subResource,
+ const char* mimetype )
+{
+ int count = 0;
+ if ( !kmailIncidencesCount( count, mimetype, subResource ) ) {
+ kdError(5650) << "Communication problem in ResourceKolab::load()\n";
+ return false;
+ }
+
+ if ( !count )
+ return true;
+
+ const int nbMessages = 200; // read 200 mails at a time (see kabc resource)
+
+ const TQString labelTxt = !strcmp(mimetype, "application/x-vnd.kolab.task") ? i18n( "Loading tasks..." )
+ : !strcmp(mimetype, "application/x-vnd.kolab.journal") ? i18n( "Loading journals..." )
+ : i18n( "Loading events..." );
+ const bool useProgress = tqApp && tqApp->type() != TQApplication::Tty && count > mProgressDialogIncidenceLimit;
+ if ( useProgress )
+ (void)::Observer::self(); // ensure kio_uiserver is running
+ UIServer_stub uiserver( "kio_uiserver", "UIServer" );
+ int progressId = 0;
+ if ( useProgress ) {
+ progressId = uiserver.newJob( kapp->dcopClient()->appId(), true );
+ uiserver.totalFiles( progressId, count );
+ uiserver.infoMessage( progressId, labelTxt );
+ uiserver.transferring( progressId, labelTxt );
+ }
+
+ for ( int startIndex = 0; startIndex < count; startIndex += nbMessages ) {
+ TQMap<TQ_UINT32, TQString> lst;
+ if ( !kmailIncidences( lst, mimetype, subResource, startIndex, nbMessages ) ) {
+ kdError(5650) << "Communication problem in ResourceKolab::load()\n";
+ if ( progressId )
+ uiserver.jobFinished( progressId );
+ return false;
+ }
+
+ { // for RAII scoping below
+ TemporarySilencer t( this );
+ for( TQMap<TQ_UINT32, TQString>::ConstIterator it = lst.begin(); it != lst.end(); ++it ) {
+ addIncidence( mimetype, it.data(), subResource, it.key() );
+ }
+ }
+ if ( progressId ) {
+ uiserver.processedFiles( progressId, startIndex );
+ uiserver.percent( progressId, 100 * startIndex / count );
+ }
+
+// if ( progress.wasCanceled() ) {
+// uiserver.jobFinished( progressId );
+// return false;
+// }
+ }
+
+ if ( progressId )
+ uiserver.jobFinished( progressId );
+ return true;
+}
+
+bool ResourceKolab::doLoad()
+{
+ if (!mUidMap.isEmpty() ) {
+ emit resourceLoaded( this );
+ return true;
+ }
+ mUidMap.clear();
+
+ bool result = loadAllEvents() & loadAllTodos() & loadAllJournals();
+ if ( result ) {
+ emit resourceLoaded( this );
+ } else {
+ // FIXME: anyone know if the resource correctly calls loadError()
+ // if it has one?
+ }
+
+ return result;
+}
+
+bool ResourceKolab::doLoadAll( ResourceMap& map, const char* mimetype )
+{
+ bool rc = true;
+ for ( ResourceMap::ConstIterator it = map.begin(); it != map.end(); ++it ) {
+ if ( !it.data().active() )
+ // This resource is disabled
+ continue;
+
+ rc &= loadSubResource( it.key(), mimetype );
+ }
+ return rc;
+}
+
+bool ResourceKolab::loadAllEvents()
+{
+ removeIncidences( "Event" );
+ mCalendar.deleteAllEvents();
+ bool kolabStyle = doLoadAll( mEventSubResources, eventAttachmentMimeType );
+ bool icalStyle = doLoadAll( mEventSubResources, incidenceInlineMimeType );
+ return kolabStyle && icalStyle;
+}
+
+bool ResourceKolab::loadAllTodos()
+{
+ removeIncidences( "Todo" );
+ mCalendar.deleteAllTodos();
+ bool kolabStyle = doLoadAll( mTodoSubResources, todoAttachmentMimeType );
+ bool icalStyle = doLoadAll( mTodoSubResources, incidenceInlineMimeType );
+
+ return kolabStyle && icalStyle;
+}
+
+bool ResourceKolab::loadAllJournals()
+{
+ removeIncidences( "Journal" );
+ mCalendar.deleteAllJournals();
+ bool kolabStyle = doLoadAll( mJournalSubResources, journalAttachmentMimeType );
+ bool icalStyle = doLoadAll( mJournalSubResources, incidenceInlineMimeType );
+
+ return kolabStyle && icalStyle;
+}
+
+void ResourceKolab::removeIncidences( const TQCString& incidenceType )
+{
+ Kolab::UidMap::Iterator mapIt = mUidMap.begin();
+ while ( mapIt != mUidMap.end() )
+ {
+ Kolab::UidMap::Iterator it = mapIt++;
+ // Check the type of this uid: event, todo or journal.
+ // Need to look up in mCalendar for that. Given the implementation of incidence(uid),
+ // better call event(uid), todo(uid) etc. directly.
+
+ // A faster but hackish way would probably be to check the type of the resource,
+ // like mEventSubResources.find( it.data().resource() ) != mEventSubResources.end() ?
+ const TQString& uid = it.key();
+ if ( incidenceType == "Event" && mCalendar.event( uid ) )
+ mUidMap.remove( it );
+ else if ( incidenceType == "Todo" && mCalendar.todo( uid ) )
+ mUidMap.remove( it );
+ else if ( incidenceType == "Journal" && mCalendar.journal( uid ) )
+ mUidMap.remove( it );
+ }
+}
+
+bool ResourceKolab::doSave()
+{
+ return true;
+ /*
+ return kmailTriggerSync( kmailCalendarContentsType )
+ && kmailTriggerSync( kmailTodoContentsType )
+ && kmailTriggerSync( kmailJournalContentsType );
+ */
+}
+void ResourceKolab::incidenceUpdatedSilent( KCal::IncidenceBase* incidencebase )
+{
+ const TQString uid = incidencebase->uid();
+ //kdDebug() << k_funcinfo << uid << endl;
+
+ if ( mUidsPendingUpdate.contains( uid ) || mUidsPendingAdding.contains( uid ) ) {
+ /* We are currently processing this event ( removing and readding or
+ * adding it ). If so, ignore this update. Keep the last of these around
+ * and process once we hear back from KMail on this event. */
+ mPendingUpdates.remove( uid );
+ mPendingUpdates.insert( uid, incidencebase );
+ return;
+ }
+
+ { // start optimization
+ /**
+ KOrganizer and libkcal like calling two Incidence::updated()
+ for only one user change. That's because after a change,
+ IncidenceChanger calls incidence->setRevision( rev++ );
+ which also calls Incidence::updated().
+
+ Lets ignore the first updated() and only send to kmail
+ the second. This makes things faster.
+ */
+
+ //IncidenceBase doesn't have revision(), downcast needed.
+ Incidence *i = dynamic_cast<Incidence*>( incidencebase );
+
+ if ( i ) {
+ bool ignoreThisUpdate = false;
+
+ if ( !mLastKnownRevisions.contains( uid ) ) {
+ mLastKnownRevisions[uid] = i->revision();
+ }
+
+ // update the last known revision
+ if ( mLastKnownRevisions[uid] < i->revision() ) {
+ mLastKnownRevisions[uid] = i->revision();
+ } else {
+ ignoreThisUpdate = true;
+ }
+
+ if ( ignoreThisUpdate ) {
+ return;
+ }
+ }
+ } // end optimization
+
+ TQString subResource;
+ TQ_UINT32 sernum = 0;
+ if ( mUidMap.contains( uid ) ) {
+ subResource = mUidMap[ uid ].resource();
+ sernum = mUidMap[ uid ].serialNumber();
+ mUidsPendingUpdate.append( uid );
+ }
+
+ sendKMailUpdate( incidencebase, subResource, sernum );
+}
+void ResourceKolab::incidenceUpdated( KCal::IncidenceBase* incidencebase )
+{
+ if ( incidencebase->isReadOnly() ) {
+ return;
+ }
+
+ incidencebase->setSyncStatusSilent( KCal::Event::SYNCMOD );
+ incidencebase->setLastModified( TQDateTime::currentDateTime() );
+
+ // we should probably update the revision number here,
+ // or internally in the Event itself when certain things change.
+ // need to verify with ical documentation.
+ incidenceUpdatedSilent( incidencebase );
+}
+
+void ResourceKolab::resolveConflict( KCal::Incidence* inc, const TQString& subresource, TQ_UINT32 sernum )
+{
+ if ( !inc ) {
+ return;
+ }
+
+ if ( !mResolveConflict ) {
+ // we should do no conflict resolution
+ delete inc;
+ return;
+ }
+ const TQString origUid = inc->uid();
+ Incidence* local = mCalendar.incidence( origUid );
+ Incidence* localIncidence = 0;
+ Incidence* addedIncidence = 0;
+ Incidence* result = 0;
+ if ( local ) {
+ if ( *local == *inc ) {
+ // real duplicate, remove the second one
+ result = local;
+ } else {
+ KIncidenceChooser* ch = new KIncidenceChooser();
+ ch->setIncidence( local ,inc );
+ if ( KIncidenceChooser::chooseMode == KIncidenceChooser::ask ) {
+ connect ( this, TQT_SIGNAL( useGlobalMode() ), ch, TQT_SLOT ( useGlobalMode() ) );
+ if ( ch->exec() ) {
+ if ( KIncidenceChooser::chooseMode != KIncidenceChooser::ask ) {
+ emit useGlobalMode() ;
+ }
+ }
+ }
+ result = ch->getIncidence();
+ delete ch;
+ }
+ } else {
+ // nothing there locally, just take the new one. Can't Happen (TM)
+ result = inc;
+ }
+ if ( result == local ) {
+ delete inc;
+ localIncidence = local;
+ } else if ( result == inc ) {
+ addedIncidence = inc;
+ } else if ( result == 0 ) { // take both
+ addedIncidence = inc;
+ addedIncidence->setSummary( i18n("Copy of: %1").arg( addedIncidence->summary() ) );
+ addedIncidence->setUid( CalFormat::createUniqueId() );
+ localIncidence = local;
+ }
+ const bool silent = mSilent;
+ mSilent = false;
+ if ( !localIncidence ) {
+ deleteIncidence( local ); // remove local from kmail
+ }
+ mUidsPendingDeletion.append( origUid );
+ if ( addedIncidence ) {
+ sendKMailUpdate( addedIncidence, subresource, sernum );
+ } else {
+ kmailDeleteIncidence( subresource, sernum );// remove new from kmail
+ }
+ mSilent = silent;
+}
+void ResourceKolab::addIncidence( const char* mimetype, const TQString& data,
+ const TQString& subResource, TQ_UINT32 sernum )
+{
+ // This uses pointer comparison, so it only works if we use the static
+ // objects defined in the top of the file
+ if ( mimetype == eventAttachmentMimeType )
+ addEvent( data, subResource, sernum );
+ else if ( mimetype == todoAttachmentMimeType )
+ addTodo( data, subResource, sernum );
+ else if ( mimetype == journalAttachmentMimeType )
+ addJournal( data, subResource, sernum );
+ else if ( mimetype == incidenceInlineMimeType ) {
+ Incidence *inc = mFormat.fromString( data );
+ addIncidence( inc, subResource, sernum );
+ }
+}
+
+
+bool ResourceKolab::sendKMailUpdate( KCal::IncidenceBase* incidencebase, const TQString& subresource,
+ TQ_UINT32 sernum )
+{
+ const TQString& type = incidencebase->type();
+ const char* mimetype = 0;
+ TQString data;
+ bool isXMLStorageFormat = kmailStorageFormat( subresource ) == KMailICalIface::StorageXML;
+ if ( type == "Event" ) {
+ if( isXMLStorageFormat ) {
+ mimetype = eventAttachmentMimeType;
+ data = Kolab::Event::eventToXML( static_cast<KCal::Event *>(incidencebase),
+ mCalendar.timeZoneId() );
+ } else {
+ mimetype = incidenceInlineMimeType;
+ data = mFormat.createScheduleMessage( static_cast<KCal::Event *>(incidencebase),
+ Scheduler::Request );
+ }
+ } else if ( type == "Todo" ) {
+ if( isXMLStorageFormat ) {
+ mimetype = todoAttachmentMimeType;
+ data = Kolab::Task::taskToXML( static_cast<KCal::Todo *>(incidencebase),
+ mCalendar.timeZoneId() );
+ } else {
+ mimetype = incidenceInlineMimeType;
+ data = mFormat.createScheduleMessage( static_cast<KCal::Todo *>(incidencebase),
+ Scheduler::Request );
+ }
+ } else if ( type == "Journal" ) {
+ if( isXMLStorageFormat ) {
+ mimetype = journalAttachmentMimeType;
+ data = Kolab::Journal::journalToXML( static_cast<KCal::Journal *>(incidencebase ),
+ mCalendar.timeZoneId() );
+ } else {
+ mimetype = incidenceInlineMimeType;
+ data = mFormat.createScheduleMessage( static_cast<KCal::Journal *>(incidencebase),
+ Scheduler::Request );
+ }
+ } else {
+ kdWarning(5006) << "Can't happen: unhandled type=" << type << endl;
+ }
+
+// kdDebug() << k_funcinfo << "Data string:\n" << data << endl;
+
+ KCal::Incidence* incidence = static_cast<KCal::Incidence *>( incidencebase );
+
+ KCal::Attachment::List atts = incidence->attachments();
+ TQStringList attURLs, attMimeTypes, attNames;
+ TQValueList<KTempFile*> tmpFiles;
+ for ( KCal::Attachment::List::ConstIterator it = atts.constBegin(); it != atts.constEnd(); ++it ) {
+ if ( (*it)->isUri() ) {
+ continue;
+ }
+ KTempFile *tempFile = new KTempFile;
+ if ( tempFile->status() == 0 ) { // open ok
+ const TQByteArray decoded = (*it)->decodedData() ;
+
+ tempFile->file()->writeBlock( decoded.data(), decoded.count() );
+ KURL url;
+ url.setPath( tempFile->name() );
+ attURLs.append( url.url() );
+ attMimeTypes.append( (*it)->mimeType() );
+ attNames.append( (*it)->label() );
+ tempFile->close();
+ tmpFiles.append( tempFile );
+ } else {
+ kdWarning(5006) << "Cannot open temporary file for attachment";
+ }
+ }
+ TQStringList deletedAtts;
+ if ( kmailListAttachments( deletedAtts, subresource, sernum ) ) {
+ for ( TQStringList::ConstIterator it = attNames.constBegin(); it != attNames.constEnd(); ++it ) {
+ deletedAtts.remove( *it );
+ }
+ }
+ CustomHeaderMap customHeaders;
+ if ( incidence->schedulingID() != incidence->uid() ) {
+ customHeaders.insert( "X-Kolab-SchedulingID", incidence->schedulingID() );
+ }
+
+ TQString subject = incidencebase->uid();
+ if ( !isXMLStorageFormat ) subject.prepend( "iCal " ); // conform to the old style
+
+ // behold, sernum is an in-parameter
+ const bool rc = kmailUpdate( subresource, sernum, data, mimetype, subject, customHeaders, attURLs, attMimeTypes, attNames, deletedAtts );
+ // update the serial number
+ if ( mUidMap.contains( incidencebase->uid() ) ) {
+ mUidMap[ incidencebase->uid() ].setSerialNumber( sernum );
+ }
+
+ for( TQValueList<KTempFile *>::Iterator it = tmpFiles.begin(); it != tmpFiles.end(); ++it ) {
+ (*it)->setAutoDelete( true );
+ delete (*it);
+ }
+
+ return rc;
+}
+
+bool ResourceKolab::addIncidence( KCal::Incidence* incidence, const TQString& _subresource,
+ TQ_UINT32 sernum )
+{
+ Q_ASSERT( incidence );
+ if ( !incidence ) {
+ return false;
+ }
+
+ kdDebug() << "Resourcekolab, adding incidence "
+ << incidence->summary()
+ << "; subresource = " << _subresource
+ << "; sernum = " << sernum
+ << "; mBatchAddingInProgress = " << mBatchAddingInProgress
+ << endl;
+
+ TQString uid = incidence->uid();
+ TQString subResource = _subresource;
+
+ Kolab::ResourceMap *map = &mEventSubResources; // don't use a ref here!
+
+ const TQString& type = incidence->type();
+ if ( type == "Event" ) {
+ map = &mEventSubResources;
+ } else if ( type == "Todo" ) {
+ map = &mTodoSubResources;
+ } else if ( type == "Journal" ) {
+ map = &mJournalSubResources;
+ } else {
+ kdWarning() << "unknown type " << type << endl;
+ }
+
+ if ( !mSilent ) { /* We got this one from the user, tell KMail. */
+ // Find out if this event was previously stored in KMail
+ bool newIncidence = _subresource.isEmpty();
+ if ( newIncidence ) {
+ ResourceType type = Incidences;
+ // Add a description of the incidence
+ TQString text = "<b><font size=\"+1\">";
+ if ( incidence->type() == "Event" ) {
+ type = Events;
+ text += i18n( "Choose the folder where you want to store this event" );
+ } else if ( incidence->type() == "Todo" ) {
+ type = Tasks;
+ text += i18n( "Choose the folder where you want to store this task" );
+ } else {
+ text += i18n( "Choose the folder where you want to store this incidence" );
+ }
+ text += "<font></b><br>";
+ if ( !incidence->summary().isEmpty() )
+ text += i18n( "<b>Summary:</b> %1" ).arg( incidence->summary() ) + "<br>";
+ if ( !incidence->location().isEmpty() )
+ text += i18n( "<b>Location:</b> %1" ).arg( incidence->location() );
+ text += "<br>";
+ if ( !incidence->doesFloat() )
+ text += i18n( "<b>Start:</b> %1, %2" )
+ .arg( incidence->dtStartDateStr(), incidence->dtStartTimeStr() );
+ else
+ text += i18n( "<b>Start:</b> %1" ).arg( incidence->dtStartDateStr() );
+ text += "<br>";
+ if ( incidence->type() == "Event" ) {
+ Event* event = static_cast<Event*>( incidence );
+ if ( event->hasEndDate() ) {
+ if ( !event->doesFloat() ) {
+ text += i18n( "<b>End:</b> %1, %2" )
+ .arg( event->dtEndDateStr(), event->dtEndTimeStr() );
+ } else {
+ text += i18n( "<b>End:</b> %1" ).arg( event->dtEndDateStr() );
+ }
+ }
+ text += "<br>";
+ }
+
+ // Lets not warn the user 100 times that there's no writable resource
+ // and not ask 100 times which resource to use
+ if ( !mBatchAddingInProgress || !mLastUsedResources.contains( type ) ) {
+ subResource = findWritableResource( type, *map, text );
+ mLastUsedResources[type] = subResource;
+ } else {
+ subResource = mLastUsedResources[type];
+ }
+
+ if ( subResource.isEmpty() ) {
+ switch( mErrorCode ) {
+ case NoWritableFound:
+ setException( new ErrorFormat( ErrorFormat::NoWritableFound ) );
+ break;
+ case UserCancel:
+ setException( new ErrorFormat( ErrorFormat::UserCancel ) );
+ break;
+ case NoError:
+ break;
+ }
+ }
+ }
+
+ if ( subResource.isEmpty() ) {
+ endAddingIncidences(); // cleanup
+ kdDebug(5650) << "ResourceKolab: subResource is empty" << endl;
+ return false;
+ }
+
+ mNewIncidencesMap.insert( uid, subResource );
+
+ if ( !sendKMailUpdate( incidence, subResource, sernum ) ) {
+ kdError(5650) << "Communication problem in ResourceKolab::addIncidence()\n";
+ endAddingIncidences(); // cleanup
+ return false;
+ } else {
+ // KMail is doing it's best to add the event now, put a sticker on it,
+ // so we know it's one of our transient ones
+ mUidsPendingAdding.append( uid );
+
+ /* Add to the cache immediately if this is a new event coming from
+ * KOrganizer. It relies on the incidence being in the calendar when
+ * addIncidence returns. */
+ if ( newIncidence || sernum == 0 ) {
+ mCalendar.addIncidence( incidence );
+ incidence->registerObserver( this );
+ }
+ }
+ } else { /* KMail told us */
+ const bool ourOwnUpdate = mUidsPendingUpdate.contains( uid );
+ kdDebug( 5650 ) << "addIncidence: ourOwnUpdate " << ourOwnUpdate << endl;
+ /* Check if we updated this one, which means kmail deleted and added it.
+ * We know the new state, so lets just not do much at all. The old incidence
+ * in the calendar remains valid, but the serial number changed, so we need to
+ * update that */
+ if ( ourOwnUpdate ) {
+ mUidsPendingUpdate.remove( uid );
+ mUidMap.remove( uid );
+ mUidMap[ uid ] = StorageReference( subResource, sernum );
+ } else {
+ /* This is a real add, from KMail, we didn't trigger this ourselves.
+ * If this uid already exists in this folder, do conflict resolution,
+ * unless the folder is read-only, in which case the user should not be
+ * offered a means of putting mails in a folder she'll later be unable to
+ * upload. Skip the incidence, in this case. */
+ if ( mUidMap.contains( uid ) ) {
+ if ( mUidMap[ uid ].resource() == subResource ) {
+ if ( (*map)[ subResource ].writable() ) {
+ kdDebug( 5650 ) << "lets resolve the conflict " << endl;
+ resolveConflict( incidence, subResource, sernum );
+ } else {
+ kdWarning( 5650 ) << "Duplicate event in a read-only folder detected! "
+ "Please inform the owner of the folder. " << endl;
+ }
+ return true;
+ } else {
+ // duplicate uid in a different folder, do the internal-uid tango
+ incidence->setSchedulingID( uid );
+
+ incidence->setUid( CalFormat::createUniqueId( ) );
+ uid = incidence->uid();
+
+ /* Will be needed when kmail triggers a delete, so we don't delete the inocent
+ * incidence that's sharing the uid with this one */
+ mOriginalUID2fakeUID[tqMakePair( incidence->schedulingID(), subResource )] = uid;
+ }
+ }
+ /* Add to the cache if the add didn't come from KOrganizer, in which case
+ * we've already added it, and listen to updates from KOrganizer for it. */
+ if ( !mUidsPendingAdding.contains( uid ) ) {
+ mCalendar.addIncidence( incidence );
+ incidence->registerObserver( this );
+ }
+ if ( !subResource.isEmpty() && sernum != 0 ) {
+ mUidMap[ uid ] = StorageReference( subResource, sernum );
+ incidence->setReadOnly( !(*map)[ subResource ].writable() );
+ }
+ }
+ /* Check if there are updates for this uid pending and if so process them. */
+ if ( KCal::IncidenceBase *update = mPendingUpdates.find( uid ) ) {
+ mSilent = false; // we do want to tell KMail
+ mPendingUpdates.remove( uid );
+ incidenceUpdated( update );
+ } else {
+ /* If the uid was added by KMail, KOrganizer needs to be told, so
+ * schedule emitting of the resourceChanged signal. */
+ if ( !mUidsPendingAdding.contains( uid ) ) {
+ if ( !ourOwnUpdate ) mResourceChangedTimer.changeInterval( 100 );
+ } else {
+ mUidsPendingAdding.remove( uid );
+ }
+ }
+
+ mNewIncidencesMap.remove( uid );
+ }
+ return true;
+}
+
+bool ResourceKolab::addEvent( KCal::Event *event )
+{
+ return addEvent( event, TQString() );
+}
+
+bool ResourceKolab::addEvent( KCal::Event *event, const TQString &subResource )
+{
+ if ( mUidMap.contains( event->uid() ) ) {
+ return true; //noop
+ } else {
+ return addIncidence( event, subResource, 0 );
+ }
+}
+
+void ResourceKolab::addEvent( const TQString& xml, const TQString& subresource,
+ TQ_UINT32 sernum )
+{
+ KCal::Event* event = Kolab::Event::xmlToEvent( xml, mCalendar.timeZoneId(), this, subresource, sernum );
+ Q_ASSERT( event );
+ if ( event ) {
+ addIncidence( event, subresource, sernum );
+ }
+}
+
+bool ResourceKolab::deleteIncidence( KCal::Incidence* incidence )
+{
+ if ( incidence->isReadOnly() ) {
+ return false;
+ }
+
+ const TQString uid = incidence->uid();
+ if( !mUidMap.contains( uid ) ) return false; // Odd
+ /* The user told us to delete, tell KMail */
+ if ( !mSilent ) {
+ kmailDeleteIncidence( mUidMap[ uid ].resource(),
+ mUidMap[ uid ].serialNumber() );
+ mUidsPendingDeletion.append( uid );
+ incidence->unRegisterObserver( this );
+ mCalendar.deleteIncidence( incidence );
+ mUidMap.remove( uid );
+ } else {
+ assert( false ); // If this still happens, something is very wrong
+ }
+ return true;
+}
+
+bool ResourceKolab::deleteEvent( KCal::Event* event )
+{
+ return deleteIncidence( event );
+}
+
+KCal::Event* ResourceKolab::event( const TQString& uid )
+{
+ return mCalendar.event(uid);
+}
+
+KCal::Event::List ResourceKolab::rawEvents( EventSortField sortField, SortDirection sortDirection )
+{
+ return mCalendar.rawEvents( sortField, sortDirection );
+}
+
+KCal::Event::List ResourceKolab::rawEventsForDate( const TQDate& date,
+ EventSortField sortField,
+ SortDirection sortDirection )
+{
+ return mCalendar.rawEventsForDate( date, sortField, sortDirection );
+}
+
+KCal::Event::List ResourceKolab::rawEventsForDate( const TQDateTime& qdt )
+{
+ return mCalendar.rawEventsForDate( qdt );
+}
+
+KCal::Event::List ResourceKolab::rawEvents( const TQDate& start,
+ const TQDate& end,
+ bool inclusive )
+{
+ return mCalendar.rawEvents( start, end, inclusive );
+}
+
+bool ResourceKolab::addTodo( KCal::Todo *todo )
+{
+ return addTodo( todo, TQString() );
+}
+
+bool ResourceKolab::addTodo( KCal::Todo *todo, const TQString &subResource )
+{
+ if ( mUidMap.contains( todo->uid() ) ) {
+ return true; //noop
+ } else {
+ return addIncidence( todo, subResource, 0 );
+ }
+}
+
+void ResourceKolab::addTodo( const TQString& xml, const TQString& subresource,
+ TQ_UINT32 sernum )
+{
+ KCal::Todo* todo = Kolab::Task::xmlToTask( xml, mCalendar.timeZoneId(), this, subresource, sernum );
+ Q_ASSERT( todo );
+ if ( todo ) {
+ addIncidence( todo, subresource, sernum );
+ }
+}
+
+bool ResourceKolab::deleteTodo( KCal::Todo* todo )
+{
+ return deleteIncidence( todo );
+}
+
+KCal::Todo* ResourceKolab::todo( const TQString& uid )
+{
+ return mCalendar.todo( uid );
+}
+
+KCal::Todo::List ResourceKolab::rawTodos( TodoSortField sortField, SortDirection sortDirection )
+{
+ return mCalendar.rawTodos( sortField, sortDirection );
+}
+
+KCal::Todo::List ResourceKolab::rawTodosForDate( const TQDate& date )
+{
+ return mCalendar.rawTodosForDate( date );
+}
+
+bool ResourceKolab::addJournal( KCal::Journal *journal )
+{
+ return addJournal( journal, TQString() );
+}
+
+bool ResourceKolab::addJournal( KCal::Journal *journal, const TQString &subResource )
+{
+ if ( mUidMap.contains( journal->uid() ) )
+ return true; //noop
+ else
+ return addIncidence( journal, subResource, 0 );
+}
+
+void ResourceKolab::addJournal( const TQString& xml, const TQString& subresource,
+ TQ_UINT32 sernum )
+{
+ KCal::Journal* journal =
+ Kolab::Journal::xmlToJournal( xml, mCalendar.timeZoneId() );
+ Q_ASSERT( journal );
+ if( journal ) {
+ addIncidence( journal, subresource, sernum );
+ }
+}
+
+bool ResourceKolab::deleteJournal( KCal::Journal* journal )
+{
+ return deleteIncidence( journal );
+}
+
+KCal::Journal* ResourceKolab::journal( const TQString& uid )
+{
+ return mCalendar.journal(uid);
+}
+
+KCal::Journal::List ResourceKolab::rawJournals( JournalSortField sortField, SortDirection sortDirection )
+{
+ return mCalendar.rawJournals( sortField, sortDirection );
+}
+
+KCal::Journal::List ResourceKolab::rawJournalsForDate( const TQDate &date )
+{
+ return mCalendar.rawJournalsForDate( date );
+}
+
+KCal::Alarm::List ResourceKolab::relevantAlarms( const KCal::Alarm::List &alarms )
+{
+ KCal::Alarm::List relevantAlarms;
+ KCal::Alarm::List::ConstIterator it( alarms.begin() );
+ while ( it != alarms.end() ) {
+ KCal::Alarm *a = (*it);
+ ++it;
+ const TQString &uid = a->parent()->uid();
+ if ( mUidMap.contains( uid ) ) {
+ const TQString &sr = mUidMap[ uid ].resource();
+ Kolab::SubResource *subResource = 0;
+ if ( mEventSubResources.contains( sr ) )
+ subResource = &( mEventSubResources[ sr ] );
+ else if ( mTodoSubResources.contains( sr ) )
+ subResource = &( mTodoSubResources[ sr ] );
+ assert( subResource );
+ if ( subResource->alarmRelevant() )
+ relevantAlarms.append ( a );
+ else {
+ kdDebug(5650) << "Alarm skipped, not relevant." << endl;
+ }
+ }
+ }
+ return relevantAlarms;
+}
+
+
+
+KCal::Alarm::List ResourceKolab::alarms( const TQDateTime& from,
+ const TQDateTime& to )
+{
+ return relevantAlarms( mCalendar.alarms( from, to ) );
+}
+
+KCal::Alarm::List ResourceKolab::alarmsTo( const TQDateTime& to )
+{
+ return relevantAlarms( mCalendar.alarmsTo(to) );
+}
+
+void ResourceKolab::setTimeZoneId( const TQString& tzid )
+{
+ mCalendar.setTimeZoneId( tzid );
+ mFormat.setTimeZone( mCalendar.timeZoneId(), !mCalendar.isLocalTime() );
+}
+
+bool ResourceKolab::fromKMailAddIncidence( const TQString& type,
+ const TQString& subResource,
+ TQ_UINT32 sernum,
+ int format,
+ const TQString& data )
+{
+ bool rc = true;
+ TemporarySilencer t( this ); // RAII
+ if ( type != kmailCalendarContentsType && type != kmailTodoContentsType
+ && type != kmailJournalContentsType ) {
+ // Not ours
+ return false;
+ }
+
+ if ( !subresourceActive( subResource ) ) {
+ return true;
+ }
+
+ if ( format == KMailICalIface::StorageXML ) {
+ // If this data file is one of ours, load it here
+ if ( type == kmailCalendarContentsType ) {
+ addEvent( data, subResource, sernum );
+ } else if ( type == kmailTodoContentsType ) {
+ addTodo( data, subResource, sernum );
+ } else if ( type == kmailJournalContentsType ) {
+ addJournal( data, subResource, sernum );
+ } else {
+ rc = false;
+ }
+ } else {
+ Incidence *inc = mFormat.fromString( data );
+ if ( inc ) {
+ addIncidence( inc, subResource, sernum );
+ } else {
+ rc = false;
+ }
+ }
+ return rc;
+}
+
+void ResourceKolab::fromKMailDelIncidence( const TQString& type,
+ const TQString& subResource,
+ const TQString& uid )
+{
+ if ( type != kmailCalendarContentsType && type != kmailTodoContentsType
+ && type != kmailJournalContentsType )
+ // Not ours
+ return;
+ if ( !subresourceActive( subResource ) ) return;
+
+ // Can't be in both, by contract
+ if ( mUidsPendingDeletion.find( uid ) != mUidsPendingDeletion.end() ) {
+ mUidsPendingDeletion.remove( mUidsPendingDeletion.find( uid ) );
+ } else if ( mUidsPendingUpdate.contains( uid ) ) {
+ // It's good to know if was deleted, but we are waiting on a new one to
+ // replace it, so let's just sit tight.
+ } else {
+ TQString uidToUse;
+
+ TQPair<TQString, TQString> p( uid, subResource );
+ if ( mOriginalUID2fakeUID.contains( p ) ) {
+ // Incidence with the same uid in a different folder...
+ // use the UID that addIncidence(...) generated
+ uidToUse = mOriginalUID2fakeUID[p];
+ } else {
+ uidToUse = uid;
+ }
+
+ // We didn't trigger this, so KMail did, remove the reference to the uid
+ KCal::Incidence* incidence = mCalendar.incidence( uidToUse );
+ if( incidence ) {
+ incidence->unRegisterObserver( this );
+ mCalendar.deleteIncidence( incidence );
+ }
+ mUidMap.remove( uidToUse );
+ mOriginalUID2fakeUID.remove( p );
+ mResourceChangedTimer.changeInterval( 100 );
+ }
+}
+
+void ResourceKolab::fromKMailRefresh( const TQString& type,
+ const TQString& /*subResource*/ )
+{
+ // TODO: Only load the specified subResource
+ if ( type == "Calendar" )
+ loadAllEvents();
+ else if ( type == "Task" )
+ loadAllTodos();
+ else if ( type == "Journal" )
+ loadAllJournals();
+ else
+ kdWarning(5006) << "KCal Kolab resource: fromKMailRefresh: unknown type " << type << endl;
+ mResourceChangedTimer.changeInterval( 100 );
+}
+
+void ResourceKolab::fromKMailAddSubresource( const TQString& type,
+ const TQString& subResource,
+ const TQString& label,
+ bool writable, bool alarmRelevant )
+{
+ ResourceMap* map = 0;
+ const char* mimetype = 0;
+ if ( type == kmailCalendarContentsType ) {
+ map = &mEventSubResources;
+ mimetype = eventAttachmentMimeType;
+ } else if ( type == kmailTodoContentsType ) {
+ map = &mTodoSubResources;
+ mimetype = todoAttachmentMimeType;
+ } else if ( type == kmailJournalContentsType ) {
+ map = &mJournalSubResources;
+ mimetype = journalAttachmentMimeType;
+ } else
+ // Not ours
+ return;
+
+ if ( map->contains( subResource ) )
+ // Already registered
+ return;
+
+ TDEConfig config( configFile() );
+ config.setGroup( subResource );
+
+ bool active = config.readBoolEntry( subResource, true );
+ (*map)[ subResource ] = Kolab::SubResource( active, writable,
+ alarmRelevant, label );
+ loadSubResource( subResource, mimetype );
+ emit signalSubresourceAdded( this, type, subResource, label );
+}
+
+void ResourceKolab::fromKMailDelSubresource( const TQString& type,
+ const TQString& subResource )
+{
+ ResourceMap* map = subResourceMap( type );
+ if ( !map ) // not ours
+ return;
+ if ( map->contains( subResource ) )
+ map->erase( subResource );
+ else
+ // Not registered
+ return;
+
+ // Delete from the config file
+ TDEConfig config( configFile() );
+ config.deleteGroup( subResource );
+ config.sync();
+
+ unloadSubResource( subResource );
+
+ emit signalSubresourceRemoved( this, type, subResource );
+}
+
+TQStringList ResourceKolab::subresources() const
+{
+ // Workaround: The ResourceView in KOrganizer wants to know this
+ // before it opens the resource :-( Make sure we are open
+ const_cast<ResourceKolab*>( this )->doOpen();
+ return ( mEventSubResources.keys()
+ + mTodoSubResources.keys()
+ + mJournalSubResources.keys() );
+}
+
+const TQString
+ResourceKolab::labelForSubresource( const TQString& subresource ) const
+{
+ if ( mEventSubResources.contains( subresource ) )
+ return mEventSubResources[ subresource ].label();
+ if ( mTodoSubResources.contains( subresource ) )
+ return mTodoSubResources[ subresource ].label();
+ if ( mJournalSubResources.contains( subresource ) )
+ return mJournalSubResources[ subresource ].label();
+ return subresource;
+}
+
+void ResourceKolab::fromKMailAsyncLoadResult( const TQMap<TQ_UINT32, TQString>& map,
+ const TQString& type,
+ const TQString& folder )
+{
+ TemporarySilencer t( this );
+ for( TQMap<TQ_UINT32, TQString>::ConstIterator it = map.begin(); it != map.end(); ++it )
+ addIncidence( type.latin1(), it.data(), folder, it.key() );
+}
+
+bool ResourceKolab::subresourceActive( const TQString& subresource ) const
+{
+ // Workaround: The ResourceView in KOrganizer wants to know this
+ // before it opens the resource :-( Make sure we are open
+ const_cast<ResourceKolab*>( this )->doOpen();
+
+ if ( mEventSubResources.contains( subresource ) )
+ return mEventSubResources[ subresource ].active();
+ if ( mTodoSubResources.contains( subresource ) )
+ return mTodoSubResources[ subresource ].active();
+ if ( mJournalSubResources.contains( subresource ) )
+ return mJournalSubResources[ subresource ].active();
+
+ // Safe default bet:
+ kdDebug(5650) << "subresourceActive( " << subresource << " ): Safe bet\n";
+
+ return true;
+}
+
+void ResourceKolab::setSubresourceActive( const TQString &subresource, bool v )
+{
+ ResourceMap *map = 0;
+ const char* mimeType = 0;
+ if ( mEventSubResources.contains( subresource ) ) {
+ map = &mEventSubResources;
+ mimeType = eventAttachmentMimeType;
+ }
+ if ( mTodoSubResources.contains( subresource ) ) {
+ map = &mTodoSubResources;
+ mimeType = todoAttachmentMimeType;
+ }
+ if ( mJournalSubResources.contains( subresource ) ) {
+ map = &mJournalSubResources;
+ mimeType = journalAttachmentMimeType;
+ }
+
+ if ( map && ( ( *map )[ subresource ].active() != v ) ) {
+ ( *map )[ subresource ].setActive( v );
+ if ( v ) {
+ loadSubResource( subresource, mimeType );
+ } else {
+ unloadSubResource( subresource );
+ }
+ mResourceChangedTimer.changeInterval( 100 );
+ }
+ TQTimer::singleShot( 0, this, TQT_SLOT(writeConfig()) );
+}
+
+bool ResourceKolab::subresourceWritable( const TQString& subresource ) const
+{
+ // Workaround: The ResourceView in KOrganizer wants to know this
+ // before it opens the resource :-( Make sure we are open
+ const_cast<ResourceKolab*>( this )->doOpen();
+
+ if ( mEventSubResources.contains( subresource ) )
+ return mEventSubResources[ subresource ].writable();
+ if ( mTodoSubResources.contains( subresource ) )
+ return mTodoSubResources[ subresource ].writable();
+ if ( mJournalSubResources.contains( subresource ) )
+ return mJournalSubResources[ subresource ].writable();
+
+ return false; //better a safe default
+}
+
+void ResourceKolab::slotEmitResourceChanged()
+{
+ kdDebug(5650) << "KCal Kolab resource: emitting resource changed " << endl;
+ mResourceChangedTimer.stop();
+ emit resourceChanged( this );
+}
+
+KABC::Lock* ResourceKolab::lock()
+{
+ return new KABC::LockNull( true );
+}
+
+Kolab::ResourceMap* ResourceKolab::subResourceMap( const TQString& contentsType )
+{
+ if ( contentsType == kmailCalendarContentsType ) {
+ return &mEventSubResources;
+ } else if ( contentsType == kmailTodoContentsType ) {
+ return &mTodoSubResources;
+ } else if ( contentsType == kmailJournalContentsType ) {
+ return &mJournalSubResources;
+ }
+ // Not ours
+ return 0;
+}
+
+
+/*virtual*/
+bool ResourceKolab::addSubresource( const TQString& resource, const TQString& parent )
+{
+ kdDebug(5650) << "KCal Kolab resource - adding subresource: " << resource << endl;
+ TQString contentsType = kmailCalendarContentsType;
+ if ( !parent.isEmpty() ) {
+ if ( mEventSubResources.contains( parent ) )
+ contentsType = kmailCalendarContentsType;
+ else if ( mTodoSubResources.contains( parent ) )
+ contentsType = kmailTodoContentsType;
+ else if ( mJournalSubResources.contains( parent ) )
+ contentsType = kmailJournalContentsType;
+ } else {
+ TQStringList contentTypeChoices;
+ contentTypeChoices << i18n("Calendar") << i18n("Tasks") << i18n("Journals");
+ const TQString caption = i18n("Which kind of subresource should this be?");
+ const TQString choice = KInputDialog::getItem( caption, TQString(), contentTypeChoices );
+ if ( choice == contentTypeChoices[0] )
+ contentsType = kmailCalendarContentsType;
+ else if ( choice == contentTypeChoices[1] )
+ contentsType = kmailTodoContentsType;
+ else if ( choice == contentTypeChoices[2] )
+ contentsType = kmailJournalContentsType;
+ }
+
+ return kmailAddSubresource( resource, parent, contentsType );
+}
+
+/*virtual*/
+bool ResourceKolab::removeSubresource( const TQString& resource )
+{
+ kdDebug(5650) << "KCal Kolab resource - removing subresource: " << resource << endl;
+ return kmailRemoveSubresource( resource );
+}
+
+/*virtual*/
+TQString ResourceKolab::subresourceIdentifier( Incidence *incidence )
+{
+ TQString uid = incidence->uid();
+ if ( mUidMap.contains( uid ) )
+ return mUidMap[ uid ].resource();
+ else
+ if ( mNewIncidencesMap.contains( uid ) )
+ return mNewIncidencesMap[ uid ];
+ else
+ return TQString();
+}
+
+
+bool ResourceKolab::unloadSubResource( const TQString& subResource )
+{
+ const bool silent = mSilent;
+ mSilent = true;
+ Kolab::UidMap::Iterator mapIt = mUidMap.begin();
+ TQPtrList<KCal::Incidence> incidences;
+ while ( mapIt != mUidMap.end() )
+ {
+ Kolab::UidMap::Iterator it = mapIt++;
+ const StorageReference ref = it.data();
+ if ( ref.resource() != subResource ) continue;
+ // FIXME incidence() is expensive
+ KCal::Incidence* incidence = mCalendar.incidence( it.key() );
+ if( incidence ) {
+ // register all observers first before actually deleting them
+ // in case of inter-incidence relations the other part will get
+ // the change notification otherwise
+ incidence->unRegisterObserver( this );
+ incidences.append( incidence );
+ }
+ mUidMap.remove( it );
+ }
+ TQPtrListIterator<KCal::Incidence> it( incidences );
+ for ( ; it.current(); ++it ) {
+ mCalendar.deleteIncidence( it.current() );
+ }
+ mSilent = silent;
+ return true;
+}
+
+TQString ResourceKolab::subresourceType( const TQString &resource )
+{
+ if ( mEventSubResources.contains( resource ) )
+ return "event";
+ if ( mTodoSubResources.contains( resource ) )
+ return "todo";
+ if ( mJournalSubResources.contains( resource ) )
+ return "journal";
+ return TQString();
+}
+
+void ResourceKolab::writeConfig()
+{
+ TDEConfig config( configFile() );
+ writeResourceConfig( config, mEventSubResources );
+ writeResourceConfig( config, mTodoSubResources );
+ writeResourceConfig( config, mJournalSubResources );
+}
+
+void ResourceKolab::beginAddingIncidences()
+{
+ mBatchAddingInProgress = true;
+}
+
+void ResourceKolab::endAddingIncidences()
+{
+ mBatchAddingInProgress = false;
+ mLastUsedResources.clear();
+}
+
+#include "resourcekolab.moc"
diff --git a/tderesources/kolab/kcal/resourcekolab.h b/tderesources/kolab/kcal/resourcekolab.h
new file mode 100644
index 000000000..fdf952cc3
--- /dev/null
+++ b/tderesources/kolab/kcal/resourcekolab.h
@@ -0,0 +1,284 @@
+/*
+ This file is part of the kolab resource - the implementation of the
+ Kolab storage format. See www.kolab.org for documentation on this.
+
+ Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
+ 2004 Till Adam <till@klaralvdalens-datakonsult.se>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ TQt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef KCAL_RESOURCEKOLAB_H
+#define KCAL_RESOURCEKOLAB_H
+
+#include <tqtimer.h>
+
+#include <tdepimmacros.h>
+#include <libkcal/calendarlocal.h>
+#include <libkcal/icalformat.h>
+#include <libkcal/resourcecalendar.h>
+#include "../shared/resourcekolabbase.h"
+
+namespace KCal {
+
+struct TemporarySilencer;
+
+class KDE_EXPORT ResourceKolab : public KCal::ResourceCalendar,
+ public KCal::IncidenceBase::Observer,
+ public Kolab::ResourceKolabBase
+{
+ Q_OBJECT
+
+ friend struct TemporarySilencer;
+
+public:
+ ResourceKolab( const TDEConfig* );
+ virtual ~ResourceKolab();
+
+ /// Load resource data.
+ bool doLoad();
+
+ /// Save resource data.
+ bool doSave();
+
+ /// Open the notes resource.
+ bool doOpen();
+ /// Close the notes resource.
+ void doClose();
+
+ // The libkcal functions. See the resource for descriptions
+ KDE_DEPRECATED bool addEvent( KCal::Event *event );
+ bool addEvent( KCal::Event *event, const TQString &subResource );
+ bool deleteEvent( KCal::Event * );
+ KCal::Event* event( const TQString &UniqueStr );
+ KCal::Event::List rawEvents( EventSortField sortField = EventSortUnsorted, SortDirection sortDirection = SortDirectionAscending );
+ KCal::Event::List rawEventsForDate(
+ const TQDate& date,
+ EventSortField sortField=EventSortUnsorted,
+ SortDirection sortDirection=SortDirectionAscending );
+ KCal::Event::List rawEventsForDate( const TQDateTime& qdt );
+ KCal::Event::List rawEvents( const TQDate& start, const TQDate& end,
+ bool inclusive = false );
+
+ KDE_DEPRECATED bool addTodo( KCal::Todo * todo );
+ bool addTodo( KCal::Todo *todo, const TQString &subResource );
+ bool deleteTodo( KCal::Todo * );
+ KCal::Todo* todo( const TQString &uid );
+ KCal::Todo::List rawTodos( TodoSortField sortField = TodoSortUnsorted, SortDirection sortDirection = SortDirectionAscending );
+ KCal::Todo::List rawTodosForDate( const TQDate& date );
+
+ KDE_DEPRECATED bool addJournal( KCal::Journal * );
+ bool addJournal( KCal::Journal *, const TQString &subResource );
+ bool deleteJournal( KCal::Journal * );
+ KCal::Journal* journal( const TQString &uid );
+ KCal::Journal::List rawJournals( JournalSortField sortField = JournalSortUnsorted, SortDirection sortDirection = SortDirectionAscending );
+ KCal::Journal::List rawJournalsForDate( const TQDate &date );
+
+ KCal::Alarm::List alarms( const TQDateTime& from, const TQDateTime& to );
+ KCal::Alarm::List alarmsTo( const TQDateTime& to );
+
+ void setTimeZoneId( const TQString& tzid );
+
+ bool deleteIncidence( KCal::Incidence* i );
+
+ /// The ResourceKolabBase methods called by KMail
+ bool fromKMailAddIncidence( const TQString& type, const TQString& subResource,
+ TQ_UINT32 sernum, int format, const TQString& data );
+ void fromKMailDelIncidence( const TQString& type, const TQString& subResource,
+ const TQString& uid );
+ void fromKMailRefresh( const TQString& type, const TQString& subResource );
+
+ /// Listen to KMail changes in the amount of sub resources
+ void fromKMailAddSubresource( const TQString& type, const TQString& subResource,
+ const TQString& label, bool writable,
+ bool alarmRelevant );
+ void fromKMailDelSubresource( const TQString& type, const TQString& subResource );
+
+ void fromKMailAsyncLoadResult( const TQMap<TQ_UINT32, TQString>& map,
+ const TQString& type,
+ const TQString& folder );
+
+ /** Return the list of subresources. */
+ TQStringList subresources() const;
+
+ bool canHaveSubresources() const { return true; }
+
+ /** Is this subresource active? */
+ bool subresourceActive( const TQString& ) const;
+ /** (De)activate the subresource */
+ virtual void setSubresourceActive( const TQString &, bool );
+
+ /** Is this subresource writable? */
+ bool subresourceWritable( const TQString& ) const;
+
+ /** What is the label for this subresource? */
+ virtual const TQString labelForSubresource( const TQString& resource ) const;
+
+ virtual TQString subresourceIdentifier( Incidence *incidence );
+
+ virtual bool addSubresource( const TQString& resource, const TQString& parent );
+ virtual bool removeSubresource( const TQString& resource );
+
+ virtual TQString subresourceType( const TQString &resource );
+
+ KABC::Lock* lock();
+
+ void beginAddingIncidences();
+
+ void endAddingIncidences();
+
+signals:
+ void useGlobalMode();
+protected slots:
+ void slotEmitResourceChanged();
+ void writeConfig();
+
+protected:
+ /**
+ * Return list of alarms which are relevant for the current user. These
+ * are the ones coming from folders which the user has "Administer" rights
+ * for, as per ACL */
+ KCal::Alarm::List relevantAlarms( const KCal::Alarm::List &alarms );
+
+private:
+ void removeIncidences( const TQCString& incidenceType );
+ void resolveConflict( KCal::Incidence*, const TQString& subresource, TQ_UINT32 sernum );
+ void addIncidence( const char* mimetype, const TQString& xml,
+ const TQString& subResource, TQ_UINT32 sernum );
+
+
+ /**
+ Caller guarantees i is not null.
+ */
+ bool addIncidence( KCal::Incidence *i, const TQString& subresource,
+ TQ_UINT32 sernum );
+
+ void addEvent( const TQString& xml, const TQString& subresource,
+ TQ_UINT32 sernum );
+ void addTodo( const TQString& xml, const TQString& subresource,
+ TQ_UINT32 sernum );
+ void addJournal( const TQString& xml, const TQString& subresource,
+ TQ_UINT32 sernum );
+
+
+ bool loadAllEvents();
+ bool loadAllTodos();
+ bool loadAllJournals();
+
+ bool doLoadAll( Kolab::ResourceMap& map, const char* mimetype );
+
+ /// Reimplemented from IncidenceBase::Observer to know when an incidence was changed
+ void incidenceUpdated( KCal::IncidenceBase* );
+ void incidenceUpdatedSilent( KCal::IncidenceBase* incidencebase);
+
+ bool openResource( TDEConfig& config, const char* contentType,
+ Kolab::ResourceMap& map );
+ void loadSubResourceConfig( TDEConfig& config, const TQString& name,
+ const TQString& label, bool writable,
+ bool alarmRelevant, Kolab::ResourceMap& subResource );
+ bool loadSubResource( const TQString& subResource, const char* mimetype );
+ bool unloadSubResource( const TQString& subResource );
+
+ TQString configFile() const {
+ return ResourceKolabBase::configFile( "kcal" );
+ }
+
+ Kolab::ResourceMap* subResourceMap( const TQString& contentsType );
+
+ bool sendKMailUpdate( KCal::IncidenceBase* incidence, const TQString& _subresource,
+ TQ_UINT32 sernum );
+
+
+ KCal::CalendarLocal mCalendar;
+
+ // The list of subresources
+ Kolab::ResourceMap mEventSubResources, mTodoSubResources, mJournalSubResources;
+
+ bool mOpen; // If the resource is open, this is true
+ TQDict<KCal::IncidenceBase> mPendingUpdates;
+ TQTimer mResourceChangedTimer;
+ ICalFormat mFormat;
+
+ /**
+ This map contains the association between a new added incidence
+ and the subresource it belongs to.
+ That's needed to return the correct mapping in subresourceIdentifier().
+
+ We can't trust on mUidMap here, because it contains only non-pending uids.
+ */
+ TQMap<TQString, TQString> mNewIncidencesMap;
+ int mProgressDialogIncidenceLimit;
+
+ /**
+ * If a user has a subresource for viewing another user's folder then it can happen
+ * that addIncidence(...) adds an incidence with an already existing UID.
+ *
+ * When this happens, addIncidence(...) sets a new random UID and stores the
+ * original UID using incidence->setSchedulingID(uid) because KCal doesn't
+ * allow two incidences to have the same UID.
+ *
+ * This map keeps track of the generated UIDs (which are local) so we can delete the
+ * right incidence inside fromKMailDelIncidence(...) whenever we sync.
+ *
+ * The key is originalUID,subResource and the value is the fake UID.
+ */
+ TQMap< TQPair<TQString, TQString>, TQString > mOriginalUID2fakeUID;
+
+ bool mBatchAddingInProgress;
+ TQMap<Kolab::ResourceType,TQString> mLastUsedResources;
+
+ /**
+ Indexed by uid, it holds the last known revision of an incidence.
+ If we receive an update where the incidence still has the same
+ revision as the last known, we ignore it and don't send it to kmail,
+ because shortly after, IncidenceChanger will increment the revision
+ and that will trigger another update.
+
+ If we didn't discard the first update, kmail would have been updated twice.
+ */
+ TQMap<TQString,int> mLastKnownRevisions;
+
+};
+
+struct TemporarySilencer {
+ TemporarySilencer( ResourceKolab *_resource )
+ {
+ resource = _resource;
+ oldValue = resource->mSilent;
+ resource->mSilent = true;
+ }
+ ~TemporarySilencer()
+ {
+ resource->mSilent = oldValue;
+ }
+ ResourceKolab *resource;
+ bool oldValue;
+};
+
+}
+
+#endif // KCAL_RESOURCEKOLAB_H
diff --git a/tderesources/kolab/kcal/resourcekolab_plugin.cpp b/tderesources/kolab/kcal/resourcekolab_plugin.cpp
new file mode 100644
index 000000000..eb56897ae
--- /dev/null
+++ b/tderesources/kolab/kcal/resourcekolab_plugin.cpp
@@ -0,0 +1,49 @@
+/*
+ This file is part of libkabc and/or kaddressbook.
+ Copyright (c) 2002 - 2004 Klarlvdalens Datakonsult AB
+ <info@klaralvdalens-datakonsult.se>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ TQt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "resourcekolab.h"
+
+class KolabFactory : public KRES::PluginFactoryBase
+{
+public:
+ KRES::Resource *resource( const TDEConfig *config )
+ {
+ return new KCal::ResourceKolab( config );
+ }
+
+ KRES::ConfigWidget *configWidget( TQWidget* )
+ {
+ return 0;
+ }
+};
+
+K_EXPORT_COMPONENT_FACTORY(kcal_kolab,KolabFactory)
diff --git a/tderesources/kolab/kcal/task.cpp b/tderesources/kolab/kcal/task.cpp
new file mode 100644
index 000000000..fe75845db
--- /dev/null
+++ b/tderesources/kolab/kcal/task.cpp
@@ -0,0 +1,461 @@
+/*
+ This file is part of the kolab resource - the implementation of the
+ Kolab storage format. See www.kolab.org for documentation on this.
+
+ Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ TQt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "task.h"
+
+#include <libkcal/todo.h>
+#include <kdebug.h>
+
+using namespace Kolab;
+
+// Kolab Storage Specification:
+// "The priority can be a number between 1 and 5, with 1 being the highest priority."
+// iCalendar (RFC 2445):
+// "The priority is specified as an integer in the range
+// zero to nine. A value of zero specifies an
+// undefined priority. A value of one is the
+// highest priority. A value of nine is the lowest
+// priority."
+
+static int kcalPriorityToKolab( const int kcalPriority )
+{
+ if ( kcalPriority >= 0 && kcalPriority <= 9 ) {
+ // We'll map undefined (0) to 3 (default)
+ // 0 1 2 3 4 5 6 7 8 9
+ static const int priorityMap[10] = { 3, 1, 1, 2, 2, 3, 3, 4, 4, 5 };
+ return priorityMap[kcalPriority];
+ }
+ else {
+ kdWarning() << "kcalPriorityToKolab(): Got invalid priority " << kcalPriority << endl;
+ return 3;
+ }
+}
+
+static int kolabPrioritytoKCal( const int kolabPriority )
+{
+ if ( kolabPriority >= 1 && kolabPriority <= 5 ) {
+ // 1 2 3 4 5
+ static const int priorityMap[5] = { 1, 3, 5, 7, 9 };
+ return priorityMap[kolabPriority - 1];
+ }
+ else {
+ kdWarning() << "kolabPrioritytoKCal(): Got invalid priority " << kolabPriority << endl;
+ return 5;
+ }
+}
+
+KCal::Todo* Task::xmlToTask( const TQString& xml, const TQString& tz, KCal::ResourceKolab *res,
+ const TQString& subResource, TQ_UINT32 sernum )
+{
+ Task task( res, subResource, sernum, tz );
+ task.load( xml );
+ KCal::Todo* todo = new KCal::Todo();
+ task.saveTo( todo );
+ return todo;
+}
+
+TQString Task::taskToXML( KCal::Todo* todo, const TQString& tz )
+{
+ Task task( 0, TQString(), 0, tz, todo );
+ return task.saveXML();
+}
+
+Task::Task( KCal::ResourceKolab *res, const TQString &subResource, TQ_UINT32 sernum,
+ const TQString& tz, KCal::Todo* task )
+ : Incidence( res, subResource, sernum, tz ),
+ mPriority( 5 ), mPercentCompleted( 0 ),
+ mStatus( KCal::Incidence::StatusNone ),
+ mHasStartDate( false ), mHasDueDate( false ),
+ mHasCompletedDate( false )
+{
+ if ( task )
+ setFields( task );
+}
+
+Task::~Task()
+{
+}
+
+void Task::setPriority( int priority )
+{
+ mPriority = priority;
+}
+
+int Task::priority() const
+{
+ return mPriority;
+}
+
+void Task::setPercentCompleted( int percent )
+{
+ mPercentCompleted = percent;
+}
+
+int Task::percentCompleted() const
+{
+ return mPercentCompleted;
+}
+
+void Task::setStatus( KCal::Incidence::Status status )
+{
+ mStatus = status;
+}
+
+KCal::Incidence::Status Task::status() const
+{
+ return mStatus;
+}
+
+void Task::setParent( const TQString& parentUid )
+{
+ mParent = parentUid;
+}
+
+TQString Task::parent() const
+{
+ return mParent;
+}
+
+void Task::setDueDate( const TQDateTime& date )
+{
+ mDueDate = date;
+ mHasDueDate = true;
+ mFloatingStatus = HasTime;
+}
+
+void Task::setDueDate( const TQDate &date )
+{
+ mDueDate = date;
+ mHasDueDate = true;
+ mFloatingStatus = AllDay;
+}
+
+
+void Task::setDueDate( const TQString &date )
+{
+ if ( date.length() > 10 ) {
+ // This is a date + time
+ setDueDate( stringToDateTime( date ) );
+ } else {
+ // This is only a date
+ setDueDate( stringToDate( date ) );
+ }
+}
+
+TQDateTime Task::dueDate() const
+{
+ return mDueDate;
+}
+
+void Task::setHasStartDate( bool v )
+{
+ mHasStartDate = v;
+}
+
+bool Task::hasStartDate() const
+{
+ return mHasStartDate;
+}
+
+bool Task::hasDueDate() const
+{
+ return mHasDueDate;
+}
+
+void Task::setCompletedDate( const TQDateTime& date )
+{
+ mCompletedDate = date;
+ mHasCompletedDate = true;
+}
+
+TQDateTime Task::completedDate() const
+{
+ return mCompletedDate;
+}
+
+bool Task::hasCompletedDate() const
+{
+ return mHasCompletedDate;
+}
+
+bool Task::loadAttribute( TQDomElement& element )
+{
+ TQString tagName = element.tagName();
+
+ if ( tagName == "priority" ) {
+ bool ok;
+ mKolabPriorityFromDom = element.text().toInt( &ok );
+ if ( !ok || mKolabPriorityFromDom < 1 || mKolabPriorityFromDom > 5 ) {
+ kdWarning() << "loadAttribute(): Invalid \"priority\" value: " << element.text() << endl;
+ mKolabPriorityFromDom = -1;
+ }
+ } else if ( tagName == "x-kcal-priority" ) {
+ bool ok;
+ mKCalPriorityFromDom = element.text().toInt( &ok );
+ if ( !ok || mKCalPriorityFromDom < 0 || mKCalPriorityFromDom > 9 ) {
+ kdWarning() << "loadAttribute(): Invalid \"x-kcal-priority\" value: " << element.text() << endl;
+ mKCalPriorityFromDom = -1;
+ }
+ } else if ( tagName == "completed" ) {
+ bool ok;
+ int percent = element.text().toInt( &ok );
+ if ( !ok || percent < 0 || percent > 100 )
+ percent = 0;
+ setPercentCompleted( percent );
+ } else if ( tagName == "status" ) {
+ if ( element.text() == "in-progress" )
+ setStatus( KCal::Incidence::StatusInProcess );
+ else if ( element.text() == "completed" )
+ setStatus( KCal::Incidence::StatusCompleted );
+ else if ( element.text() == "waiting-on-someone-else" )
+ setStatus( KCal::Incidence::StatusNeedsAction );
+ else if ( element.text() == "deferred" )
+ // Guessing a status here
+ setStatus( KCal::Incidence::StatusCanceled );
+ else
+ // Default
+ setStatus( KCal::Incidence::StatusNone );
+ } else if ( tagName == "due-date" ) {
+ setDueDate( element.text() );
+ } else if ( tagName == "parent" ) {
+ setParent( element.text() );
+ } else if ( tagName == "x-completed-date" ) {
+ setCompletedDate( stringToDateTime( element.text() ) );
+ } else if ( tagName == "start-date" ) {
+ setHasStartDate( true );
+ setStartDate( element.text() );
+ } else
+ return Incidence::loadAttribute( element );
+
+ // We handled this
+ return true;
+}
+
+bool Task::saveAttributes( TQDomElement& element ) const
+{
+ // Save the base class elements
+ Incidence::saveAttributes( element );
+
+ // We need to save x-kcal-priority as well, since the Kolab priority can only save values from
+ // 1 to 5, but we have values from 0 to 9, and do not want to loose them
+ writeString( element, "priority", TQString::number( kcalPriorityToKolab( priority() ) ) );
+ writeString( element, "x-kcal-priority", TQString::number( priority() ) );
+
+ writeString( element, "completed", TQString::number( percentCompleted() ) );
+
+ switch( status() ) {
+ case KCal::Incidence::StatusInProcess:
+ writeString( element, "status", "in-progress" );
+ break;
+ case KCal::Incidence::StatusCompleted:
+ writeString( element, "status", "completed" );
+ break;
+ case KCal::Incidence::StatusNeedsAction:
+ writeString( element, "status", "waiting-on-someone-else" );
+ break;
+ case KCal::Incidence::StatusCanceled:
+ writeString( element, "status", "deferred" );
+ break;
+ case KCal::Incidence::StatusNone:
+ writeString( element, "status", "not-started" );
+ break;
+ case KCal::Incidence::StatusTentative:
+ case KCal::Incidence::StatusConfirmed:
+ case KCal::Incidence::StatusDraft:
+ case KCal::Incidence::StatusFinal:
+ case KCal::Incidence::StatusX:
+ // All of these are saved as StatusNone.
+ writeString( element, "status", "not-started" );
+ break;
+ }
+
+ if ( hasDueDate() ) {
+ if ( mFloatingStatus == HasTime ) {
+ writeString( element, "due-date", dateTimeToString( dueDate() ) );
+ } else {
+ writeString( element, "due-date", dateToString( dueDate().date() ) );
+ }
+ }
+
+ if ( !parent().isNull() ) {
+ writeString( element, "parent", parent() );
+ }
+
+ if ( hasCompletedDate() && percentCompleted() == 100 ) {
+ writeString( element, "x-completed-date", dateTimeToString( completedDate() ) );
+ }
+
+ return true;
+}
+
+
+bool Task::loadXML( const TQDomDocument& document )
+{
+ mKolabPriorityFromDom = -1;
+ mKCalPriorityFromDom = -1;
+
+ TQDomElement top = document.documentElement();
+
+ if ( top.tagName() != "task" ) {
+ tqWarning( "XML error: Top tag was %s instead of the expected task",
+ top.tagName().ascii() );
+ return false;
+ }
+ setHasStartDate( false ); // todo's don't necessarily have one
+
+ for ( TQDomNode n = top.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ TQDomElement e = n.toElement();
+ if ( !loadAttribute( e ) )
+ // TODO: Unhandled tag - save for later storage
+ kdDebug() << "Warning: Unhandled tag " << e.tagName() << endl;
+ } else
+ kdDebug() << "Node is not a comment or an element???" << endl;
+ }
+
+ loadAttachments();
+ decideAndSetPriority();
+ return true;
+}
+
+TQString Task::saveXML() const
+{
+ TQDomDocument document = domTree();
+ TQDomElement element = document.createElement( "task" );
+ element.setAttribute( "version", "1.0" );
+ saveAttributes( element );
+ if ( !hasStartDate() && startDate().isValid() ) {
+ // events and journals always have a start date, but tasks don't.
+ // Remove the entry done by the inherited save above, because we
+ // don't have one.
+ TQDomNodeList l = element.elementsByTagName( "start-date" );
+ Q_ASSERT( l.count() == 1 );
+ element.removeChild( l.item( 0 ) );
+ }
+ document.appendChild( element );
+ return document.toString();
+}
+
+void Task::setFields( const KCal::Todo* task )
+{
+ Incidence::setFields( task );
+
+ setPriority( task->priority() );
+ setPercentCompleted( task->percentComplete() );
+ setStatus( task->status() );
+ setHasStartDate( task->hasStartDate() );
+
+ if ( task->hasDueDate() ) {
+ setDueDate( localToUTC( task->dtDue() ) );
+ if ( task->doesFloat() ) {
+ // This is a floating task. Don't timezone move this one
+ mFloatingStatus = AllDay;
+ setDueDate( task->dtDue().date() );
+ } else {
+ mFloatingStatus = HasTime;
+ setDueDate( localToUTC( task->dtDue() ) );
+ }
+ } else {
+ mHasDueDate = false;
+ }
+
+ if ( task->relatedTo() ) {
+ setParent( task->relatedTo()->uid() );
+ } else if ( !task->relatedToUid().isEmpty() ) {
+ setParent( task->relatedToUid( ) );
+ } else {
+ setParent( TQString() );
+ }
+
+ if ( task->hasCompletedDate() && task->percentComplete() == 100 ) {
+ setCompletedDate( localToUTC( task->completed() ) );
+ } else {
+ mHasCompletedDate = false;
+ }
+}
+
+void Task::decideAndSetPriority()
+{
+ // If we have both Kolab and KCal values in the XML, we prefer the KCal value, but only if the
+ // values are still in sync
+ if ( mKolabPriorityFromDom != -1 && mKCalPriorityFromDom != -1 ) {
+ const bool inSync = ( kcalPriorityToKolab( mKCalPriorityFromDom ) == mKolabPriorityFromDom );
+ if ( inSync ) {
+ setPriority( mKCalPriorityFromDom );
+ }
+ else {
+ // Out of sync, some other client changed the Kolab priority, so we have to ignore our
+ // KCal priority
+ setPriority( kolabPrioritytoKCal( mKolabPriorityFromDom ) );
+ }
+ }
+
+ // Only KCal priority set, use that.
+ else if ( mKolabPriorityFromDom == -1 && mKCalPriorityFromDom != -1 ) {
+ kdWarning() << "decideAndSetPriority(): No Kolab priority found, only the KCal priority!" << endl;
+ setPriority( mKCalPriorityFromDom );
+ }
+
+ // Only Kolab priority set, use that
+ else if ( mKolabPriorityFromDom != -1 && mKCalPriorityFromDom == -1 ) {
+ setPriority( kolabPrioritytoKCal( mKolabPriorityFromDom ) );
+ }
+
+ // No priority set, use the default
+ else {
+ // According the RFC 2445, we should use 0 here, for undefined priority, but AFAIK KOrganizer
+ // doesn't support that, so we'll use 5.
+ setPriority( 5 );
+ }
+}
+
+void Task::saveTo( KCal::Todo* task )
+{
+ Incidence::saveTo( task );
+
+ task->setPriority( priority() );
+ task->setPercentComplete( percentCompleted() );
+ task->setStatus( status() );
+ task->setHasStartDate( hasStartDate() );
+ task->setHasDueDate( hasDueDate() );
+ if ( hasDueDate() )
+ task->setDtDue( utcToLocal( dueDate() ) );
+
+ if ( !parent().isNull() )
+ task->setRelatedToUid( parent() );
+
+ if ( hasCompletedDate() && task->percentComplete() == 100 )
+ task->setCompleted( utcToLocal( mCompletedDate ) );
+}
diff --git a/tderesources/kolab/kcal/task.h b/tderesources/kolab/kcal/task.h
new file mode 100644
index 000000000..38a12a70e
--- /dev/null
+++ b/tderesources/kolab/kcal/task.h
@@ -0,0 +1,143 @@
+/*
+ This file is part of the kolab resource - the implementation of the
+ Kolab storage format. See www.kolab.org for documentation on this.
+
+ Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ TQt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef KOLAB_TASK_H
+#define KOLAB_TASK_H
+
+#include <incidence.h>
+
+#include <libkcal/incidence.h>
+
+class TQDomElement;
+
+namespace KCal {
+ class Todo;
+ class ResourceKolab;
+}
+
+namespace Kolab {
+
+/**
+ * This class represents a task, and knows how to load/save it
+ * from/to XML, and from/to a KCal::Todo.
+ * The instances of this class are temporary, only used to convert
+ * one to the other.
+ */
+class Task : public Incidence {
+public:
+ /// Use this to parse an xml string to a task entry
+ /// The caller is responsible for deleting the returned task
+ static KCal::Todo* xmlToTask( const TQString& xml, const TQString& tz, KCal::ResourceKolab *res = 0,
+ const TQString& subResource = TQString(), TQ_UINT32 sernum = 0 );
+
+ /// Use this to get an xml string describing this task entry
+ static TQString taskToXML( KCal::Todo*, const TQString& tz );
+
+ explicit Task( KCal::ResourceKolab *res, const TQString& subResource, TQ_UINT32 sernum,
+ const TQString& tz, KCal::Todo* todo = 0 );
+ virtual ~Task();
+
+ virtual TQString type() const { return "Task"; }
+
+ void saveTo( KCal::Todo* todo );
+
+ virtual void setPriority( int priority );
+ virtual int priority() const;
+
+ virtual void setPercentCompleted( int percent );
+ virtual int percentCompleted() const;
+
+ virtual void setStatus( KCal::Incidence::Status status );
+ virtual KCal::Incidence::Status status() const;
+
+ virtual void setParent( const TQString& parentUid );
+ virtual TQString parent() const;
+
+ virtual void setHasStartDate( bool );
+ virtual bool hasStartDate() const;
+
+ virtual void setDueDate( const TQDateTime &date );
+ virtual void setDueDate( const TQString &date );
+ virtual void setDueDate( const TQDate &date );
+ virtual TQDateTime dueDate() const;
+ virtual bool hasDueDate() const;
+
+ virtual void setCompletedDate( const TQDateTime& date );
+ virtual TQDateTime completedDate() const;
+ virtual bool hasCompletedDate() const;
+
+ // Load the attributes of this class
+ virtual bool loadAttribute( TQDomElement& );
+
+ // Save the attributes of this class
+ virtual bool saveAttributes( TQDomElement& ) const;
+
+ // Load this task by reading the XML file
+ virtual bool loadXML( const TQDomDocument& xml );
+
+ // Serialize this task to an XML string
+ virtual TQString saveXML() const;
+
+protected:
+ // Read all known fields from this ical todo
+ void setFields( const KCal::Todo* );
+
+ // This sets the priority of this task by looking at mKolabPriorityFromDom and
+ // mKCalPriorityFromDom.
+ void decideAndSetPriority();
+
+ // This is the KCal priority, not the Kolab priority.
+ // See kcalPriorityToKolab() and kolabPrioritytoKCal().
+ int mPriority;
+
+ // Those priority values are the raw values read by loadAttribute().
+ // They will be converted later in decideAndSetPriority().
+ int mKolabPriorityFromDom;
+ int mKCalPriorityFromDom;
+
+ int mPercentCompleted;
+ KCal::Incidence::Status mStatus;
+ TQString mParent;
+
+ bool mHasStartDate;
+
+ bool mHasDueDate;
+ TQDateTime mDueDate;
+
+ bool mHasCompletedDate;
+ TQDateTime mCompletedDate;
+};
+
+}
+
+#endif // KOLAB_TASK_H
diff --git a/tderesources/kolab/knotes/CMakeLists.txt b/tderesources/kolab/knotes/CMakeLists.txt
new file mode 100644
index 000000000..8e10f3e52
--- /dev/null
+++ b/tderesources/kolab/knotes/CMakeLists.txt
@@ -0,0 +1,55 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/../shared
+ ${CMAKE_SOURCE_DIR}
+ ${CMAKE_SOURCE_DIR}/knotes
+ ${CMAKE_SOURCE_DIR}/libtdepim
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install(
+ FILES kolabresource.desktop
+ DESTINATION ${SERVICES_INSTALL_DIR}/tderesources/knotes )
+
+install(
+ FILES ${CMAKE_CURRENT_SOURCE_DIR}/../uninstall.desktop
+ DESTINATION ${SERVICES_INSTALL_DIR}/tderesources/knotes
+ RENAME imap.desktop )
+
+
+##### knotes_kolab (module) #####################
+
+tde_add_kpart( knotes_kolab AUTOMOC
+ SOURCES resourcekolab_plugin.cpp
+ LINK knoteskolab-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
+
+
+##### knoteskolab (shared) ######################
+
+tde_add_library( knoteskolab SHARED AUTOMOC
+ SOURCES resourcekolab.cpp note.cpp
+ VERSION 0.0.0
+ LINK resourcekolabshared-static kgroupwarebase-shared knotes-shared
+ DESTINATION ${LIB_INSTALL_DIR}
+)
diff --git a/tderesources/kolab/knotes/Makefile.am b/tderesources/kolab/knotes/Makefile.am
new file mode 100644
index 000000000..54337ce89
--- /dev/null
+++ b/tderesources/kolab/knotes/Makefile.am
@@ -0,0 +1,29 @@
+METASOURCES = AUTO
+
+INCLUDES = -I$(top_srcdir)/tderesources/kolab/shared \
+ -I$(top_srcdir) -I$(top_srcdir)/knotes -I$(top_builddir)/libtdepim $(all_includes)
+
+# The kolab wizard links to this library too
+lib_LTLIBRARIES = libknoteskolab.la
+
+libknoteskolab_la_SOURCES = resourcekolab.cpp note.cpp
+libknoteskolab_la_LDFLAGS = $(all_libraries) -no-undefined
+libknoteskolab_la_LIBADD = \
+ $(top_builddir)/tderesources/kolab/shared/libresourcekolabshared.la \
+ $(top_builddir)/knotes/libknotesresources.la \
+ $(top_builddir)/libkcal/libkcal.la \
+ -ltderesources -ltdeprint
+
+kde_module_LTLIBRARIES = knotes_kolab.la
+
+knotes_kolab_la_SOURCES = resourcekolab_plugin.cpp
+knotes_kolab_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) -no-undefined
+knotes_kolab_la_LIBADD = libknoteskolab.la
+
+servicedir = $(kde_servicesdir)/tderesources/knotes
+service_DATA = kolabresource.desktop
+
+install-data-local: $(srcdir)/../uninstall.desktop
+ $(mkinstalldirs) $(DESTDIR)$(servicedir)
+ $(INSTALL_DATA) $(srcdir)/../uninstall.desktop $(DESTDIR)$(servicedir)/imap.desktop
+
diff --git a/tderesources/kolab/knotes/kolabresource.desktop b/tderesources/kolab/knotes/kolabresource.desktop
new file mode 100644
index 000000000..16f48e45a
--- /dev/null
+++ b/tderesources/kolab/knotes/kolabresource.desktop
@@ -0,0 +1,52 @@
+[Desktop Entry]
+Name=IMAP Server via KMail
+Name[af]=IMAP bediener via KMail
+Name[bg]=Сървър IMAP през KMail
+Name[br]=Servijer IMAP gant KMail
+Name[ca]=Servidor IMAP mitjançant KMail
+Name[cs]=IMAP server přes KMail
+Name[da]=IMAP-server via KMail
+Name[de]=IMAP-Server via KMail
+Name[el]=Εξυπηρετητής IMAP μέσω του KMail
+Name[es]=Servidor IMAP por medio de KMail
+Name[et]=IMAP-server (KMaili vahendusel)
+Name[eu]=IMAP zerbitzaria KMail-en bidez
+Name[fa]=کارساز IMAP از طریق KMail
+Name[fi]=IMAP-palvelin KMailin avulla
+Name[fr]=Serveur IMAP (via KMail)
+Name[fy]=IMAP-tsjinner fia KMail
+Name[ga]=Freastalaí IMAP via KMail
+Name[gl]=Servidor MAP mediante KMail
+Name[hu]=IMAP-kiszolgáló a KMailen keresztül
+Name[is]=IMAP þjónn gegnum KMail
+Name[it]=Server IMAP via KMail
+Name[ja]=KMail 経由 IMAP サーバ
+Name[kk]=KMail арқылы IMAP сервері
+Name[km]=ម៉ាស៊ីន​បម្រើ IMAP តាម​រយៈ KMail
+Name[lt]=IMAP serveris per KMail
+Name[mk]=IMAP-сервер преку КПошта
+Name[ms]=Pelayan IMAP melalui KMail
+Name[nb]=IMAP-tjener via KMail
+Name[nds]=IMAP-Server över KMail
+Name[ne]=केडीई मेल मार्फत IMAP सर्भर
+Name[nl]=IMAP-server via KMail
+Name[nn]=IMAP-tenar via KMail
+Name[pl]=Serwer IMAP za pośrednictwem KMail
+Name[pt]=Servidor IMAP via KMail
+Name[pt_BR]=Servidor IMAP via KMail
+Name[ru]=Доступ к серверу IMAP через KMail
+Name[sk]=IMAP-server pomocou KMail
+Name[sl]=Strežnik IMAP preko KMaila
+Name[sr]=IMAP сервер преко KMail-а
+Name[sr@Latn]=IMAP server preko KMail-a
+Name[sv]=IMAP-server via Kmail
+Name[ta]=IMAP சேவகன் மூலாம் கேஅஞ்சல்
+Name[tr]=KMail aracılığı ile IMAP Sunucu
+Name[uk]=Сервер IMAP через KMail
+Name[zh_CN]=通过 KMail 访问 IMAP 服务器
+Name[zh_TW]=透過 KMail 取得 IMAP 伺服器
+X-TDE-Library=knotes_kolab
+Type=Service
+ServiceTypes=KResources/Plugin
+X-TDE-ResourceFamily=notes
+X-TDE-ResourceType=imap
diff --git a/tderesources/kolab/knotes/note.cpp b/tderesources/kolab/knotes/note.cpp
new file mode 100644
index 000000000..7df5b26b3
--- /dev/null
+++ b/tderesources/kolab/knotes/note.cpp
@@ -0,0 +1,229 @@
+/*
+ This file is part of the kolab resource - the implementation of the
+ Kolab storage format. See www.kolab.org for documentation on this.
+
+ Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ TQt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "note.h"
+
+#include <libkcal/journal.h>
+#include <knotes/version.h>
+#include <kdebug.h>
+
+using namespace Kolab;
+
+
+KCal::Journal* Note::xmlToJournal( const TQString& xml )
+{
+ Note note;
+ note.load( xml );
+ KCal::Journal* journal = new KCal::Journal();
+ note.saveTo( journal );
+ return journal;
+}
+
+TQString Note::journalToXML( KCal::Journal* journal )
+{
+ Note note( journal );
+ return note.saveXML();
+}
+
+Note::Note( KCal::Journal* journal ) : mRichText( false )
+{
+ if ( journal )
+ setFields( journal );
+}
+
+Note::~Note()
+{
+}
+
+void Note::setSummary( const TQString& summary )
+{
+ mSummary = summary;
+}
+
+TQString Note::summary() const
+{
+ return mSummary;
+}
+
+void Note::setBackgroundColor( const TQColor& bgColor )
+{
+ mBackgroundColor = bgColor;
+}
+
+TQColor Note::backgroundColor() const
+{
+ return mBackgroundColor;
+}
+
+void Note::setForegroundColor( const TQColor& fgColor )
+{
+ mForegroundColor = fgColor;
+}
+
+TQColor Note::foregroundColor() const
+{
+ return mForegroundColor;
+}
+
+void Note::setRichText( bool richText )
+{
+ mRichText = richText;
+}
+
+bool Note::richText() const
+{
+ return mRichText;
+}
+
+bool Note::loadAttribute( TQDomElement& element )
+{
+ TQString tagName = element.tagName();
+ if ( tagName == "summary" )
+ setSummary( element.text() );
+ else if ( tagName == "foreground-color" )
+ setForegroundColor( stringToColor( element.text() ) );
+ else if ( tagName == "background-color" )
+ setBackgroundColor( stringToColor( element.text() ) );
+ else if ( tagName == "knotes-richtext" )
+ mRichText = ( element.text() == "true" );
+ else
+ return KolabBase::loadAttribute( element );
+
+ // We handled this
+ return true;
+}
+
+bool Note::saveAttributes( TQDomElement& element ) const
+{
+ // Save the base class elements
+ KolabBase::saveAttributes( element );
+
+ // Save the elements
+#if 0
+ TQDomComment c = element.ownerDocument().createComment( "Note specific attributes" );
+ element.appendChild( c );
+#endif
+
+ writeString( element, "summary", summary() );
+ if ( foregroundColor().isValid() )
+ writeString( element, "foreground-color", colorToString( foregroundColor() ) );
+ if ( backgroundColor().isValid() )
+ writeString( element, "background-color", colorToString( backgroundColor() ) );
+ writeString( element, "knotes-richtext", mRichText ? "true" : "false" );
+
+ return true;
+}
+
+
+bool Note::loadXML( const TQDomDocument& document )
+{
+ TQDomElement top = document.documentElement();
+
+ if ( top.tagName() != "note" ) {
+ tqWarning( "XML error: Top tag was %s instead of the expected note",
+ top.tagName().ascii() );
+ return false;
+ }
+
+ for ( TQDomNode n = top.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ TQDomElement e = n.toElement();
+ if ( !loadAttribute( e ) )
+ // TODO: Unhandled tag - save for later storage
+ kdDebug() << "Warning: Unhandled tag " << e.tagName() << endl;
+ } else
+ kdDebug() << "Node is not a comment or an element???" << endl;
+ }
+
+ return true;
+}
+
+TQString Note::saveXML() const
+{
+ TQDomDocument document = domTree();
+ TQDomElement element = document.createElement( "note" );
+ element.setAttribute( "version", "1.0" );
+ saveAttributes( element );
+ document.appendChild( element );
+ return document.toString();
+}
+
+void Note::setFields( const KCal::Journal* journal )
+{
+ KolabBase::setFields( journal );
+
+ setSummary( journal->summary() );
+
+ TQString property = journal->customProperty( "KNotes", "BgColor" );
+ if ( !property.isNull() ) {
+ setBackgroundColor( property );
+ } else {
+ setBackgroundColor( "yellow" );
+ }
+ property = journal->customProperty( "KNotes", "FgColor" );
+ if ( !property.isNull() ) {
+ setForegroundColor( property );
+ } else {
+ setForegroundColor( "black" );
+ }
+
+ property = journal->customProperty( "KNotes", "RichText" );
+ if ( !property.isNull() ) {
+ setRichText( property == "true" ? true : false );
+ } else {
+ setRichText( "false" );
+ }
+}
+
+void Note::saveTo( KCal::Journal* journal )
+{
+ KolabBase::saveTo( journal );
+
+ // TODO: background and foreground
+ journal->setSummary( summary() );
+ if ( foregroundColor().isValid() )
+ journal->setCustomProperty( "KNotes", "FgColor",
+ colorToString( foregroundColor() ) );
+ if ( backgroundColor().isValid() )
+ journal->setCustomProperty( "KNotes", "BgColor",
+ colorToString( backgroundColor() ) );
+ journal->setCustomProperty( "KNotes", "RichText",
+ richText() ? "true" : "false" );
+}
+
+TQString Note::productID() const
+{
+ return TQString( "KNotes %1, Kolab resource" ).arg( KNOTES_VERSION );
+}
diff --git a/tderesources/kolab/knotes/note.h b/tderesources/kolab/knotes/note.h
new file mode 100644
index 000000000..d61a2009e
--- /dev/null
+++ b/tderesources/kolab/knotes/note.h
@@ -0,0 +1,111 @@
+/*
+ This file is part of the kolab resource - the implementation of the
+ Kolab storage format. See www.kolab.org for documentation on this.
+
+ Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ TQt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef KOLAB_NOTE_H
+#define KOLAB_NOTE_H
+
+#include <kolabbase.h>
+
+class TQDomElement;
+
+namespace KCal {
+ class Journal;
+}
+
+namespace Kolab {
+
+/**
+ * This class represents a note, and knows how to load/save it
+ * from/to XML, and from/to a KCal::Journal.
+ * The instances of this class are temporary, only used to convert
+ * one to the other.
+ */
+class Note : public KolabBase {
+public:
+ /// Use this to parse an xml string to a journal entry
+ /// The caller is responsible for deleting the returned journal
+ static KCal::Journal* xmlToJournal( const TQString& xml );
+
+ /// Use this to get an xml string describing this journal entry
+ static TQString journalToXML( KCal::Journal* );
+
+ /// Create a note object and
+ explicit Note( KCal::Journal* journal = 0 );
+ virtual ~Note();
+
+ void saveTo( KCal::Journal* journal );
+
+ virtual TQString type() const { return "Note"; }
+
+ virtual void setSummary( const TQString& summary );
+ virtual TQString summary() const;
+
+ virtual void setBackgroundColor( const TQColor& bgColor );
+ virtual TQColor backgroundColor() const;
+
+ virtual void setForegroundColor( const TQColor& fgColor );
+ virtual TQColor foregroundColor() const;
+
+ virtual void setRichText( bool richText );
+ virtual bool richText() const;
+
+ // Load the attributes of this class
+ virtual bool loadAttribute( TQDomElement& );
+
+ // Save the attributes of this class
+ virtual bool saveAttributes( TQDomElement& ) const;
+
+ // Load this note by reading the XML file
+ virtual bool loadXML( const TQDomDocument& xml );
+
+ // Serialize this note to an XML string
+ virtual TQString saveXML() const;
+
+protected:
+ // Read all known fields from this ical incidence
+ void setFields( const KCal::Journal* );
+
+ // Save all known fields into this ical incidence
+ void saveTo( KCal::Incidence* ) const;
+
+ TQString productID() const;
+
+ TQString mSummary;
+ TQColor mBackgroundColor;
+ TQColor mForegroundColor;
+ bool mRichText;
+};
+
+}
+
+#endif // KOLAB_NOTE_H
diff --git a/tderesources/kolab/knotes/resourcekolab.cpp b/tderesources/kolab/knotes/resourcekolab.cpp
new file mode 100644
index 000000000..a28a51b27
--- /dev/null
+++ b/tderesources/kolab/knotes/resourcekolab.cpp
@@ -0,0 +1,463 @@
+/*
+ This file is part of the kolab resource - the implementation of the
+ Kolab storage format. See www.kolab.org for documentation on this.
+
+ Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
+ Copyright (c) 2004 Till Adam <adam@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ TQt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "resourcekolab.h"
+#include "note.h"
+
+#include <knotes/resourcemanager.h>
+
+#include <libkcal/icalformat.h>
+
+#include <kdebug.h>
+#include <kglobal.h>
+#include <klocale.h>
+
+using namespace Kolab;
+
+static const char* configGroupName = "Note";
+static const char* kmailContentsType = "Note";
+static const char* attachmentMimeType = "application/x-vnd.kolab.note";
+static const char* inlineMimeType = "text/calendar";
+
+ResourceKolab::ResourceKolab( const TDEConfig *config )
+ : ResourceNotes( config ), ResourceKolabBase( "ResourceKolab-KNotes" ),
+ mCalendar( TQString::fromLatin1("UTC") )
+{
+ if ( !config ) {
+ setResourceName( i18n( "Kolab Server" ) );
+ }
+ setType( "imap" );
+}
+
+ResourceKolab::~ResourceKolab()
+{
+}
+
+bool ResourceKolab::doOpen()
+{
+ TDEConfig config( configFile() );
+ config.setGroup( configGroupName );
+
+ // Get the list of Notes folders from KMail
+ TQValueList<KMailICalIface::SubResource> subResources;
+ if ( !kmailSubresources( subResources, kmailContentsType ) )
+ return false;
+
+ // Make the resource map from the folder list
+ TQValueList<KMailICalIface::SubResource>::ConstIterator it;
+ mSubResources.clear();
+ for ( it = subResources.constBegin(); it != subResources.constEnd(); ++it ) {
+ const TQString subResource = (*it).location;
+ const bool active = config.readBoolEntry( subResource, true );
+ mSubResources[ subResource ] = Kolab::SubResource( active, (*it).writable, (*it).label );
+ }
+
+ return true;
+}
+
+void ResourceKolab::doClose()
+{
+ TDEConfig config( configFile() );
+ config.setGroup( configGroupName );
+ Kolab::ResourceMap::ConstIterator it;
+ for ( it = mSubResources.constBegin(); it != mSubResources.constEnd(); ++it )
+ config.writeEntry( it.key(), it.data().active() );
+}
+
+bool ResourceKolab::loadSubResource( const TQString& subResource,
+ const TQString &mimetype )
+{
+ // Get the list of journals
+ int count = 0;
+ if ( !kmailIncidencesCount( count, mimetype, subResource ) ) {
+ kdError() << "Communication problem in ResourceKolab::load()\n";
+ return false;
+ }
+
+ TQMap<TQ_UINT32, TQString> lst;
+ if( !kmailIncidences( lst, mimetype, subResource, 0, count ) ) {
+ kdError(5500) << "Communication problem in "
+ << "ResourceKolab::getIncidenceList()\n";
+ return false;
+ }
+
+ kdDebug(5500) << "Notes kolab resource: got " << lst.count() << " notes in " << subResource << endl;
+
+ // Populate with the new entries
+ const bool silent = mSilent;
+ mSilent = true;
+ TQMap<TQ_UINT32, TQString>::ConstIterator it;
+ for ( it = lst.constBegin(); it != lst.constEnd(); ++it ) {
+ KCal::Journal* journal = addNote( it.data(), subResource, it.key(), mimetype );
+ if ( !journal )
+ kdDebug(5500) << "loading note " << it.key() << " failed" << endl;
+ else
+ manager()->registerNote( this, journal );
+ }
+ mSilent = silent;
+
+ return true;
+}
+
+bool ResourceKolab::load()
+{
+ // We get a fresh list of events, so clean out the old ones
+ mCalendar.deleteAllEvents();
+ mUidMap.clear();
+
+ bool rc = true;
+ Kolab::ResourceMap::ConstIterator itR;
+ for ( itR = mSubResources.constBegin(); itR != mSubResources.constEnd(); ++itR ) {
+ if ( !itR.data().active() )
+ // This subResource is disabled
+ continue;
+
+ TQString mimetype = inlineMimeType;
+ rc &= loadSubResource( itR.key(), mimetype );
+ mimetype = attachmentMimeType;
+ rc &= loadSubResource( itR.key(), mimetype );
+ }
+
+ return rc;
+}
+
+bool ResourceKolab::save()
+{
+ // Nothing to do here, we save everything in incidenceUpdated()
+ return true;
+}
+
+bool ResourceKolab::addNote( KCal::Journal* journal )
+{
+ return addNote( journal, TQString(), 0 );
+}
+
+KCal::Journal* ResourceKolab::addNote( const TQString& data, const TQString& subresource,
+ TQ_UINT32 sernum, const TQString &mimetype )
+{
+ KCal::Journal *journal = 0;
+
+ // FIXME: This does not take into account the time zone!
+ KCal::ICalFormat formatter;
+ if ( mimetype == attachmentMimeType ) {
+ journal = Note::xmlToJournal( data );
+ } else {
+ journal = static_cast<KCal::Journal*>( formatter.fromString( data ) );
+ }
+ Q_ASSERT( journal );
+
+ bool addedOk = journal &&
+ !mUidMap.contains( journal->uid() ) &&
+ addNote( journal, subresource, sernum );
+
+ // for debugging
+ if ( journal && mUidMap.contains( journal->uid() ) ) {
+ kdDebug(5500) << "mUidMap already contains " << journal->uid() << endl;
+ }
+
+ if ( !addedOk ) {
+ delete journal;
+ journal = 0;
+ }
+
+ return journal;
+}
+
+bool ResourceKolab::addNote( KCal::Journal *journal, const TQString &subresource, TQ_UINT32 sernum )
+{
+ kdDebug(5500) << "ResourceKolab::addNote( KCal::Journal*, '" << subresource << "', " << sernum << " )\n";
+
+ journal->registerObserver( this );
+
+ // Find out if this note was previously stored in KMail
+ bool newNote = subresource.isEmpty();
+ if ( !mCalendar.addJournal( journal ) ) {
+ return false;
+ }
+
+ TQString resource = newNote ? findWritableResource( Kolab::Notes, mSubResources ) : subresource;
+ if ( resource.isEmpty() ) {
+ // canceled
+ return false;
+ }
+
+ if ( !mSilent ) {
+ TQString xml = Note::journalToXML( journal );
+ kdDebug(5500) << k_funcinfo << "XML string:\n" << xml << endl;
+
+ if( !kmailUpdate( resource, sernum, xml, attachmentMimeType, journal->uid() ) ) {
+ kdError(5500) << "Communication problem in ResourceKolab::addNote()\n";
+ return false;
+ }
+ }
+
+ if ( !resource.isEmpty() && sernum != 0 ) {
+ mUidMap[ journal->uid() ] = StorageReference( resource, sernum );
+ return true;
+ }
+ return false;
+}
+
+bool ResourceKolab::deleteNote( KCal::Journal* journal )
+{
+ const TQString uid = journal->uid();
+ if ( !mUidMap.contains( uid ) )
+ // Odd
+ return false;
+
+ if ( !mSilent ) {
+ kmailDeleteIncidence( mUidMap[ uid ].resource(),
+ mUidMap[ uid ].serialNumber() );
+ }
+ mUidMap.remove( uid );
+ return mCalendar.deleteJournal( journal );
+}
+
+KCal::Alarm::List ResourceKolab::alarms( const TQDateTime& from, const TQDateTime& to )
+{
+ KCal::Alarm::List alarms;
+ KCal::Journal::List notes = mCalendar.journals();
+ KCal::Journal::List::ConstIterator note;
+ for ( note = notes.begin(); note != notes.end(); ++note )
+ {
+ TQDateTime preTime = from.addSecs( -1 );
+ KCal::Alarm::List::ConstIterator it;
+ for( it = (*note)->alarms().constBegin(); it != (*note)->alarms().constEnd(); ++it )
+ {
+ if ( (*it)->enabled() )
+ {
+ TQDateTime dt = (*it)->nextRepetition( preTime );
+ if ( dt.isValid() && dt <= to )
+ alarms.append( *it );
+ }
+ }
+ }
+
+ return alarms;
+}
+
+void ResourceKolab::incidenceUpdated( KCal::IncidenceBase* i )
+{
+ TQString subResource;
+ TQ_UINT32 sernum;
+ if ( mUidMap.contains( i->uid() ) ) {
+ subResource = mUidMap[ i->uid() ].resource();
+ sernum = mUidMap[ i->uid() ].serialNumber();
+ } else { // can this happen?
+ subResource = findWritableResource( Kolab::Notes, mSubResources );
+ if ( subResource.isEmpty() ) // canceled
+ return;
+ sernum = 0;
+ }
+
+ KCal::Journal* journal = dynamic_cast<KCal::Journal*>( i );
+ TQString xml = Note::journalToXML( journal );
+ if( !xml.isEmpty() && kmailUpdate( subResource, sernum, xml, attachmentMimeType, journal->uid() ) )
+ mUidMap[ i->uid() ] = StorageReference( subResource, sernum );
+}
+
+/*
+ * These are the DCOP slots that KMail call to notify when something
+ * changed.
+ */
+bool ResourceKolab::fromKMailAddIncidence( const TQString& type,
+ const TQString& subResource,
+ TQ_UINT32 sernum,
+ int format,
+ const TQString& note )
+{
+ // Check if this is a note
+ if( type != kmailContentsType ) return false;
+
+ const bool silent = mSilent;
+ mSilent = true;
+ TQString mimetype;
+ if ( format == KMailICalIface::StorageXML )
+ mimetype = attachmentMimeType;
+ else
+ mimetype = inlineMimeType;
+ KCal::Journal* journal = addNote( note, subResource, sernum, mimetype );
+ if ( journal )
+ manager()->registerNote( this, journal );
+ mSilent = silent;
+ return true;
+}
+
+void ResourceKolab::fromKMailDelIncidence( const TQString& type,
+ const TQString& /*subResource*/,
+ const TQString& uid )
+{
+ // Check if this is a note
+ if( type != kmailContentsType ) return;
+
+ kdDebug(5500) << "ResourceKolab::fromKMailDelIncidence( " << type << ", " << uid
+ << " )" << endl;
+
+ const bool silent = mSilent;
+ mSilent = true;
+ KCal::Journal* j = mCalendar.journal( uid );
+ if ( j ) {
+ if ( deleteNote( j ) ) {
+ manager()->deleteNote( j );
+ }
+ }
+ mSilent = silent;
+}
+
+void ResourceKolab::fromKMailRefresh( const TQString& type,
+ const TQString& /*subResource*/ )
+{
+ if ( type == kmailContentsType )
+ load(); // ### should call loadSubResource(subResource) probably
+}
+
+void ResourceKolab::fromKMailAddSubresource( const TQString& type,
+ const TQString& subResource,
+ const TQString& /*label*/,
+ bool writable,
+ bool /*alarmRelevant*/ )
+{
+ if ( type != kmailContentsType )
+ // Not ours
+ return;
+
+ if ( mSubResources.contains( subResource ) )
+ // Already registered
+ return;
+
+ TDEConfig config( configFile() );
+ config.setGroup( configGroupName );
+
+ bool active = config.readBoolEntry( subResource, true );
+ mSubResources[ subResource ] = Kolab::SubResource( active, writable, subResource );
+ loadSubResource( subResource, attachmentMimeType );
+ emit signalSubresourceAdded( this, type, subResource );
+}
+
+void ResourceKolab::fromKMailDelSubresource( const TQString& type,
+ const TQString& subResource )
+{
+ if ( type != configGroupName )
+ // Not ours
+ return;
+
+ if ( !mSubResources.contains( subResource ) )
+ // Not registered
+ return;
+
+ // Ok, it's our job, and we have it here
+ mSubResources.erase( subResource );
+
+ TDEConfig config( configFile() );
+ config.setGroup( configGroupName );
+ config.deleteEntry( subResource );
+ config.sync();
+
+ // Make a list of all uids to remove
+ Kolab::UidMap::ConstIterator mapIt;
+ TQStringList uids;
+ for ( mapIt = mUidMap.constBegin(); mapIt != mUidMap.constEnd(); ++mapIt )
+ if ( mapIt.data().resource() == subResource )
+ // We have a match
+ uids << mapIt.key();
+
+ // Finally delete all the incidences
+ if ( !uids.isEmpty() ) {
+ const bool silent = mSilent;
+ mSilent = true;
+ TQStringList::ConstIterator it;
+ for ( it = uids.constBegin(); it != uids.constEnd(); ++it ) {
+ KCal::Journal* j = mCalendar.journal( *it );
+ if( j )
+ deleteNote( j );
+ }
+ mSilent = silent;
+ }
+
+ emit signalSubresourceRemoved( this, type, subResource );
+}
+
+void ResourceKolab::fromKMailAsyncLoadResult( const TQMap<TQ_UINT32, TQString>& map,
+ const TQString& type,
+ const TQString& folder )
+{
+ // We are only interested in notes
+ if ( ( type != attachmentMimeType ) && ( type != inlineMimeType ) ) return;
+ // Populate with the new entries
+ const bool silent = mSilent;
+ mSilent = true;
+ TQString mimetype;
+ if ( kmailStorageFormat( folder ) == KMailICalIface::StorageXML )
+ mimetype = attachmentMimeType;
+ else
+ mimetype = inlineMimeType;
+ for( TQMap<TQ_UINT32, TQString>::ConstIterator it = map.constBegin(); it != map.constEnd(); ++it ) {
+ KCal::Journal* journal = addNote( it.data(), folder, it.key(), mimetype );
+ if ( !journal )
+ kdDebug(5500) << "loading note " << it.key() << " failed" << endl;
+ else
+ manager()->registerNote( this, journal );
+ }
+ mSilent = silent;
+}
+
+
+TQStringList ResourceKolab::subresources() const
+{
+ return mSubResources.keys();
+}
+
+bool ResourceKolab::subresourceActive( const TQString& res ) const
+{
+ if ( mSubResources.contains( res ) ) {
+ return mSubResources[ res ].active();
+ }
+
+ // Safe default bet:
+ kdDebug(5650) << "subresourceActive( " << res << " ): Safe bet\n";
+
+ return true;
+}
+
+bool ResourceKolab::subresourceWritable( const TQString& res ) const
+{
+ if ( mSubResources.contains( res ) ) {
+ return mSubResources[ res ].writable();
+ }
+
+ // Safe default bet:
+ return false;
+}
+
+#include "resourcekolab.moc"
diff --git a/tderesources/kolab/knotes/resourcekolab.h b/tderesources/kolab/knotes/resourcekolab.h
new file mode 100644
index 000000000..fb0d191b9
--- /dev/null
+++ b/tderesources/kolab/knotes/resourcekolab.h
@@ -0,0 +1,133 @@
+/*
+ This file is part of the kolab resource - the implementation of the
+ Kolab storage format. See www.kolab.org for documentation on this.
+
+ Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ TQt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef KNOTES_RESOURCEKOLAB_H
+#define KNOTES_RESOURCEKOLAB_H
+
+#include <resourcenotes.h>
+#include <libkcal/incidencebase.h>
+#include <libkcal/calendarlocal.h>
+#include "../shared/resourcekolabbase.h"
+#include "../shared/subresource.h"
+#include <tdepimmacros.h>
+
+
+namespace Kolab {
+
+/**
+ * This class implements a KNotes resource that keeps its
+ * addresses in an IMAP folder in KMail (or other conforming email
+ * clients).
+ */
+class KDE_EXPORT ResourceKolab : public ResourceNotes,
+ public KCal::IncidenceBase::Observer,
+ public ResourceKolabBase
+{
+ Q_OBJECT
+
+
+public:
+ ResourceKolab( const TDEConfig* );
+ virtual ~ResourceKolab();
+
+ /// Load resource data.
+ bool load();
+
+ /// Save resource data.
+ bool save();
+
+ /// Open the notes resource.
+ bool doOpen();
+ /// Close the notes resource.
+ void doClose();
+
+ bool addNote( KCal::Journal* );
+
+ bool deleteNote( KCal::Journal* );
+
+ KCal::Alarm::List alarms( const TQDateTime& from, const TQDateTime& to );
+
+ /// Reimplemented from IncidenceBase::Observer to know when a note was changed
+ void incidenceUpdated( KCal::IncidenceBase* );
+
+ /// The ResourceKolabBase methods called by KMail
+ bool fromKMailAddIncidence( const TQString& type, const TQString& resource,
+ TQ_UINT32 sernum, int format, const TQString& note );
+ void fromKMailDelIncidence( const TQString& type, const TQString& resource,
+ const TQString& uid );
+ void fromKMailRefresh( const TQString& type, const TQString& resource );
+
+ /// Listen to KMail changes in the amount of sub resources
+ void fromKMailAddSubresource( const TQString& type, const TQString& resource,
+ const TQString& label, bool writable,
+ bool alarmRelevant );
+ void fromKMailDelSubresource( const TQString& type, const TQString& resource );
+
+ void fromKMailAsyncLoadResult( const TQMap<TQ_UINT32, TQString>& map,
+ const TQString& type,
+ const TQString& folder );
+
+ /** Return the list of subresources. */
+ TQStringList subresources() const;
+
+ /** Is this subresource active? */
+ bool subresourceActive( const TQString& ) const;
+
+ /** Is this subresource writable? */
+ bool subresourceWritable( const TQString& ) const;
+
+signals:
+ void signalSubresourceAdded( Resource*, const TQString&, const TQString& );
+ void signalSubresourceRemoved( Resource*, const TQString&, const TQString& );
+
+private:
+ bool addNote( KCal::Journal* journal, const TQString& resource,
+ TQ_UINT32 sernum );
+ KCal::Journal* addNote( const TQString& data, const TQString& subresource,
+ TQ_UINT32 sernum, const TQString &mimetype );
+
+ bool loadSubResource( const TQString& resource, const TQString& mimetype );
+
+ TQString configFile() const {
+ return ResourceKolabBase::configFile( "knotes" );
+ }
+
+ KCal::CalendarLocal mCalendar;
+
+ // The list of subresources
+ Kolab::ResourceMap mSubResources;
+};
+
+}
+
+#endif // KNOTES_RESOURCEKOLAB_H
diff --git a/tderesources/kolab/knotes/resourcekolab_plugin.cpp b/tderesources/kolab/knotes/resourcekolab_plugin.cpp
new file mode 100644
index 000000000..f589986cb
--- /dev/null
+++ b/tderesources/kolab/knotes/resourcekolab_plugin.cpp
@@ -0,0 +1,50 @@
+/*
+ This file is part of libkabc and/or kaddressbook.
+ Copyright (c) 2002 - 2004 Klarlvdalens Datakonsult AB
+ <info@klaralvdalens-datakonsult.se>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ TQt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "resourcekolab.h"
+
+class KolabFactory : public KRES::PluginFactoryBase
+{
+public:
+ KRES::Resource *resource( const TDEConfig *config )
+ {
+ return new Kolab::ResourceKolab( config );
+ }
+
+ KRES::ConfigWidget *configWidget( TQWidget* )
+ {
+ return 0;
+ }
+};
+
+K_EXPORT_COMPONENT_FACTORY(knotes_kolab,KolabFactory())
+
diff --git a/tderesources/kolab/kolab-resource.upd b/tderesources/kolab/kolab-resource.upd
new file mode 100644
index 000000000..8f456f4ab
--- /dev/null
+++ b/tderesources/kolab/kolab-resource.upd
@@ -0,0 +1,12 @@
+# Update the name of the resource
+Id=kolab-calendar-resource-rename
+File=tderesources/calendar/stdrc
+Script=upgrade-resourcetype.pl,perl
+
+Id=kolab-contact-resource-rename
+File=tderesources/contact/stdrc
+Script=upgrade-resourcetype.pl,perl
+
+Id=kolab-notes-resource-rename
+File=tderesources/notes/stdrc
+Script=upgrade-resourcetype.pl,perl
diff --git a/tderesources/kolab/shared/CMakeLists.txt b/tderesources/kolab/shared/CMakeLists.txt
new file mode 100644
index 000000000..1509deb1a
--- /dev/null
+++ b/tderesources/kolab/shared/CMakeLists.txt
@@ -0,0 +1,30 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}
+ ${CMAKE_SOURCE_DIR}/tderesources/lib
+ ${CMAKE_SOURCE_DIR}/libtdepim
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### resourcekolabshared (static) ##############
+
+set( KDE3_DCOPIDL_EXECUTABLE ${KDE3_DCOPIDLNG_EXECUTABLE} )
+
+tde_add_library( resourcekolabshared STATIC_PIC AUTOMOC
+ SOURCES
+ resourcekolabbase.cpp kmailconnection.cpp kolabbase.cpp subresource.cpp
+ kmailconnection.skel ${CMAKE_SOURCE_DIR}/kmail/kmailicalIface.stub
+)
diff --git a/tderesources/kolab/shared/Makefile.am b/tderesources/kolab/shared/Makefile.am
new file mode 100644
index 000000000..287620330
--- /dev/null
+++ b/tderesources/kolab/shared/Makefile.am
@@ -0,0 +1,17 @@
+INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/tderesources/lib $(all_includes)
+
+noinst_HEADERS = resourcekolabbase.h kolabbase.h subresource.h
+
+noinst_LTLIBRARIES = libresourcekolabshared.la
+
+libresourcekolabshared_la_SOURCES = \
+ resourcekolabbase.cpp kmailconnection.cpp kolabbase.cpp \
+ subresource.cpp \
+ kmailconnection.skel kmailicalIface.stub
+libresourcekolabshared_la_METASOURCES = AUTO
+libresourcekolabshared_la_LIBADD = $(top_builddir)/libkcal/libkcal.la $(top_builddir)/libtdepim/libtdepim.la ../../lib/libkgroupwarebase.la
+libresourcekolabshared_la_LDFLAGS = -no-undefined
+
+kmailicalIface_DCOPIDLNG = true
+
+kmailicalIface_DIR = $(top_srcdir)/kmail
diff --git a/tderesources/kolab/shared/kmailconnection.cpp b/tderesources/kolab/shared/kmailconnection.cpp
new file mode 100644
index 000000000..e82102a34
--- /dev/null
+++ b/tderesources/kolab/shared/kmailconnection.cpp
@@ -0,0 +1,339 @@
+/*
+ This file is part of the kolab resource - the implementation of the
+ Kolab storage format. See www.kolab.org for documentation on this.
+
+ Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ TQt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "kmailconnection.h"
+#include "resourcekolabbase.h"
+
+#include <kdebug.h>
+#include <dcopclient.h>
+#include <kapplication.h>
+#include <kdcopservicestarter.h>
+#include <klocale.h>
+
+#include "kmailicalIface_stub.h"
+
+
+using namespace Kolab;
+
+
+KMailConnection::KMailConnection( ResourceKolabBase* resource,
+ const TQCString& objId )
+ : DCOPObject( objId ), mResource( resource ), mKMailIcalIfaceStub( 0 )
+{
+ // Make the connection to KMail ready
+ mDCOPClient = new DCOPClient();
+ mDCOPClient->attach();
+ mDCOPClient->registerAs( objId, true );
+
+ kapp->dcopClient()->setNotifications( true );
+ connect( kapp->dcopClient(), TQT_SIGNAL( applicationRemoved( const TQCString& ) ),
+ this, TQT_SLOT( unregisteredFromDCOP( const TQCString& ) ) );
+}
+
+KMailConnection::~KMailConnection()
+{
+ kapp->dcopClient()->setNotifications( false );
+ delete mKMailIcalIfaceStub;
+ mKMailIcalIfaceStub = 0;
+ delete mDCOPClient;
+ mDCOPClient = 0;
+}
+
+static const TQCString dcopObjectId = "KMailICalIface";
+bool KMailConnection::connectToKMail()
+{
+ if ( !mKMailIcalIfaceStub ) {
+ TQCString dcopService;
+
+ // if we are kmail (and probably kontact as well) ourselves, don't try to start us again
+ // this prevents a DCOP deadlock when launching the kmail while kontact is the IMAP backend
+ // provider (and probably vice versa)
+ if ( kapp->instanceName() == "kmail" ) {
+ // someone, probably ourselves, already offers the interface, if not stop here
+ const QCStringList services = kapp->dcopClient()->registeredApplications();
+ for ( uint i = 0; i < services.count(); ++i ) {
+ if ( services[i].find( "anonymous" ) == 0 ) // querying anonymous-XXXXX deadlocks as well, what are those anyway?
+ continue;
+ const QCStringList objs = kapp->dcopClient()->remoteObjects( services[i] );
+ if ( objs.contains( dcopObjectId ) ) {
+ dcopService = services[i];
+ break;
+ }
+ }
+ if ( dcopService.isEmpty() ) {
+ kdError(5650) << k_funcinfo << "Not connecting to KMail to prevent DCOP deadlock" << endl;
+ return false;
+ }
+ } else {
+ TQString error;
+ int result = KDCOPServiceStarter::self()->
+ findServiceFor( "DCOP/ResourceBackend/IMAP", TQString(),
+ TQString(), &error, &dcopService );
+ if ( result != 0 ) {
+ kdError(5650) << "Couldn't connect to the IMAP resource backend\n";
+ // TODO: You might want to show "error" (if not empty) here,
+ // using e.g. KMessageBox
+ return false;
+ }
+ }
+
+ mKMailIcalIfaceStub = new KMailICalIface_stub( kapp->dcopClient(),
+ dcopService, dcopObjectId );
+
+ // Attach to the KMail signals
+ if ( !connectKMailSignal( "incidenceAdded(TQString,TQString,TQ_UINT32,int,TQString)",
+ "fromKMailAddIncidence(TQString,TQString,TQ_UINT32,int,TQString)" ) )
+ kdError(5650) << "DCOP connection to incidenceAdded failed" << endl;
+ if ( !connectKMailSignal( "incidenceDeleted(TQString,TQString,TQString)",
+ "fromKMailDelIncidence(TQString,TQString,TQString)" ) )
+ kdError(5650) << "DCOP connection to incidenceDeleted failed" << endl;
+ if ( !connectKMailSignal( "signalRefresh(TQString,TQString)",
+ "fromKMailRefresh(TQString,TQString)" ) )
+ kdError(5650) << "DCOP connection to signalRefresh failed" << endl;
+ if ( !connectKMailSignal( "subresourceAdded( TQString, TQString, TQString, bool, bool )",
+ "fromKMailAddSubresource( TQString, TQString, TQString, bool, bool )" ) )
+ kdError(5650) << "DCOP connection to subresourceAdded failed" << endl;
+ if ( !connectKMailSignal( "subresourceDeleted(TQString,TQString)",
+ "fromKMailDelSubresource(TQString,TQString)" ) )
+ kdError(5650) << "DCOP connection to subresourceDeleted failed" << endl;
+ if ( !connectKMailSignal( "asyncLoadResult(TQMap<TQ_UINT32, TQString>, TQString, TQString)",
+ "fromKMailAsyncLoadResult(TQMap<TQ_UINT32, TQString>, TQString, TQString)" ) )
+ kdError(5650) << "DCOP connection to asyncLoadResult failed" << endl;
+ }
+
+ return ( mKMailIcalIfaceStub != 0 );
+}
+
+bool KMailConnection::fromKMailAddIncidence( const TQString& type,
+ const TQString& folder,
+ TQ_UINT32 sernum,
+ int format,
+ const TQString& data )
+{
+ if ( format != KMailICalIface::StorageXML
+ && format != KMailICalIface::StorageIcalVcard )
+ return false;
+// kdDebug(5650) << "KMailConnection::fromKMailAddIncidence( " << type << ", "
+// << folder << " ). iCal:\n" << ical << endl;
+ return mResource->fromKMailAddIncidence( type, folder, sernum, format, data );
+}
+
+void KMailConnection::fromKMailDelIncidence( const TQString& type,
+ const TQString& folder,
+ const TQString& xml )
+{
+// kdDebug(5650) << "KMailConnection::fromKMailDelIncidence( " << type << ", "
+// << folder << ", " << uid << " )\n";
+ mResource->fromKMailDelIncidence( type, folder, xml );
+}
+
+void KMailConnection::fromKMailRefresh( const TQString& type, const TQString& folder )
+{
+// kdDebug(5650) << "KMailConnection::fromKMailRefresh( " << type << ", "
+// << folder << " )\n";
+ mResource->fromKMailRefresh( type, folder );
+}
+
+void KMailConnection::fromKMailAddSubresource( const TQString& type,
+ const TQString& resource,
+ const TQString& label,
+ bool writable,
+ bool alarmRelevant )
+{
+// kdDebug(5650) << "KMailConnection::fromKMailAddSubresource( " << type << ", "
+// << resource << " )\n";
+ mResource->fromKMailAddSubresource( type, resource, label,
+ writable, alarmRelevant );
+}
+
+void KMailConnection::fromKMailDelSubresource( const TQString& type,
+ const TQString& resource )
+{
+// kdDebug(5650) << "KMailConnection::fromKMailDelSubresource( " << type << ", "
+// << resource << " )\n";
+ mResource->fromKMailDelSubresource( type, resource );
+}
+
+void KMailConnection::fromKMailAsyncLoadResult( const TQMap<TQ_UINT32, TQString>& map,
+ const TQString& type,
+ const TQString& folder )
+{
+ mResource->fromKMailAsyncLoadResult( map, type, folder );
+}
+
+bool KMailConnection::connectKMailSignal( const TQCString& signal,
+ const TQCString& method )
+{
+ return connectDCOPSignal( "kmail", dcopObjectId, signal, method, false )
+ && connectDCOPSignal( "kontact", dcopObjectId, signal, method, false );
+}
+
+bool KMailConnection::kmailSubresources( TQValueList<KMailICalIface::SubResource>& lst,
+ const TQString& contentsType )
+{
+ if ( !connectToKMail() )
+ return false;
+
+ lst = mKMailIcalIfaceStub->subresourcesKolab( contentsType );
+ return mKMailIcalIfaceStub->ok();
+}
+
+bool KMailConnection::kmailIncidencesCount( int& count,
+ const TQString& mimetype,
+ const TQString& resource )
+{
+ if ( !connectToKMail() )
+ return false;
+
+ count = mKMailIcalIfaceStub->incidencesKolabCount( mimetype, resource );
+ return mKMailIcalIfaceStub->ok();
+}
+
+bool KMailConnection::kmailIncidences( TQMap<TQ_UINT32, TQString>& lst,
+ const TQString& mimetype,
+ const TQString& resource,
+ int startIndex,
+ int nbMessages )
+{
+ if ( !connectToKMail() )
+ return false;
+
+ lst = mKMailIcalIfaceStub->incidencesKolab( mimetype, resource, startIndex, nbMessages );
+ return mKMailIcalIfaceStub->ok();
+}
+
+
+bool KMailConnection::kmailGetAttachment( KURL& url,
+ const TQString& resource,
+ TQ_UINT32 sernum,
+ const TQString& filename )
+{
+ if ( !connectToKMail() )
+ return false;
+
+ url = mKMailIcalIfaceStub->getAttachment( resource, sernum, filename );
+ return mKMailIcalIfaceStub->ok();
+}
+
+bool KMailConnection::kmailAttachmentMimetype( TQString & mimeType,
+ const TQString & resource,
+ TQ_UINT32 sernum,
+ const TQString & filename )
+{
+ if ( !connectToKMail() )
+ return false;
+ mimeType = mKMailIcalIfaceStub->attachmentMimetype( resource, sernum, filename );
+ return mKMailIcalIfaceStub->ok();
+}
+
+bool KMailConnection::kmailListAttachments(TQStringList &list,
+ const TQString & resource, TQ_UINT32 sernum)
+{
+ if ( !connectToKMail() )
+ return false;
+
+ list = mKMailIcalIfaceStub->listAttachments( resource, sernum );
+ return mKMailIcalIfaceStub->ok();
+}
+
+bool KMailConnection::kmailDeleteIncidence( const TQString& resource,
+ TQ_UINT32 sernum )
+{
+ return connectToKMail()
+ && mKMailIcalIfaceStub->deleteIncidenceKolab( resource, sernum )
+ && mKMailIcalIfaceStub->ok();
+}
+
+bool KMailConnection::kmailUpdate( const TQString& resource,
+ TQ_UINT32& sernum,
+ const TQString& subject,
+ const TQString& plainTextBody,
+ const TQMap<TQCString, TQString>& customHeaders,
+ const TQStringList& attachmentURLs,
+ const TQStringList& attachmentMimetypes,
+ const TQStringList& attachmentNames,
+ const TQStringList& deletedAttachments )
+{
+ //kdDebug(5006) << kdBacktrace() << endl;
+ if ( connectToKMail() ) {
+ sernum = mKMailIcalIfaceStub->update( resource, sernum, subject, plainTextBody, customHeaders,
+ attachmentURLs, attachmentMimetypes, attachmentNames,
+ deletedAttachments );
+ return sernum && mKMailIcalIfaceStub->ok();
+ } else
+ return false;
+}
+
+bool KMailConnection::kmailAddSubresource( const TQString& resource,
+ const TQString& parent,
+ const TQString& contentsType )
+{
+ return connectToKMail()
+ && mKMailIcalIfaceStub->addSubresource( resource, parent, contentsType )
+ && mKMailIcalIfaceStub->ok();
+}
+
+bool KMailConnection::kmailRemoveSubresource( const TQString& resource )
+{
+ return connectToKMail()
+ && mKMailIcalIfaceStub->removeSubresource( resource )
+ && mKMailIcalIfaceStub->ok();
+}
+
+
+bool KMailConnection::kmailStorageFormat( KMailICalIface::StorageFormat& type,
+ const TQString& folder )
+{
+ bool ok = connectToKMail();
+ type = mKMailIcalIfaceStub->storageFormat( folder );
+ return ok && mKMailIcalIfaceStub->ok();
+}
+
+
+bool KMailConnection::kmailTriggerSync( const TQString &contentsType )
+{
+ bool ok = connectToKMail();
+ return ok && mKMailIcalIfaceStub->triggerSync( contentsType );
+}
+
+void KMailConnection::unregisteredFromDCOP( const TQCString& appId )
+{
+ if ( mKMailIcalIfaceStub && mKMailIcalIfaceStub->app() == appId ) {
+ // Delete the stub so that the next time we need to talk to kmail,
+ // we'll know that we need to start a new one.
+ delete mKMailIcalIfaceStub;
+ mKMailIcalIfaceStub = 0;
+ }
+}
+
+#include "kmailconnection.moc"
diff --git a/tderesources/kolab/shared/kmailconnection.h b/tderesources/kolab/shared/kmailconnection.h
new file mode 100644
index 000000000..62003b5f9
--- /dev/null
+++ b/tderesources/kolab/shared/kmailconnection.h
@@ -0,0 +1,129 @@
+/*
+ This file is part of the kolab resource - the implementation of the
+ Kolab storage format. See www.kolab.org for documentation on this.
+
+ Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ TQt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef KMAILCONNECTION_H
+#define KMAILCONNECTION_H
+
+#include <dcopobject.h>
+#include <kmail/kmailicalIface.h>
+
+class KURL;
+class DCOPClient;
+class KMailICalIface_stub;
+
+namespace Kolab {
+
+class ResourceKolabBase;
+
+/**
+ This class provides the kmail connectivity for IMAP resources.
+*/
+class KMailConnection : public TQObject, public DCOPObject {
+ Q_OBJECT
+//
+ K_DCOP
+
+ // These are the methods called by KMail when the resource changes
+k_dcop:
+ bool fromKMailAddIncidence( const TQString& type, const TQString& resource,
+ TQ_UINT32 sernum, int format, const TQString& xml );
+ void fromKMailDelIncidence( const TQString& type, const TQString& resource,
+ const TQString& xml );
+ void fromKMailRefresh( const TQString& type, const TQString& resource );
+ void fromKMailAddSubresource( const TQString& type, const TQString& resource,
+ const TQString& label, bool writable,
+ bool alarmRelevant );
+ void fromKMailDelSubresource( const TQString& type, const TQString& resource );
+ void fromKMailAsyncLoadResult( const TQMap<TQ_UINT32, TQString>& map, const TQString& type,
+ const TQString& folder );
+
+public:
+ KMailConnection( ResourceKolabBase* resource, const TQCString& objId );
+ virtual ~KMailConnection();
+
+ /**
+ * Do the connection to KMail.
+ */
+ bool connectToKMail();
+
+ // Call the DCOP methods
+ bool kmailSubresources( TQValueList<KMailICalIface::SubResource>& lst,
+ const TQString& contentsType );
+ bool kmailIncidencesCount( int& count,
+ const TQString& mimetype,
+ const TQString& resource );
+ bool kmailIncidences( TQMap<TQ_UINT32, TQString>& lst, const TQString& mimetype,
+ const TQString& resource,
+ int startIndex,
+ int nbMessages );
+
+ bool kmailGetAttachment( KURL& url, const TQString& resource, TQ_UINT32 sernum,
+ const TQString& filename );
+ bool kmailAttachmentMimetype( TQString &mimeType, const TQString &resource,
+ TQ_UINT32 sernum, const TQString &filename );
+ bool kmailListAttachments( TQStringList &list, const TQString &resource,
+ TQ_UINT32 sernum );
+ bool kmailDeleteIncidence( const TQString& resource, TQ_UINT32 sernum );
+ bool kmailUpdate( const TQString& resource,
+ TQ_UINT32& sernum,
+ const TQString& subject,
+ const TQString& plainTextBody,
+ const TQMap<TQCString, TQString>& customHeaders,
+ const TQStringList& attachmentURLs,
+ const TQStringList& attachmentMimetypes,
+ const TQStringList& attachmentNames,
+ const TQStringList& deletedAttachments );
+
+ bool kmailStorageFormat( KMailICalIface::StorageFormat& type, const TQString& folder);
+
+ bool kmailTriggerSync( const TQString& contentsType );
+ bool kmailAddSubresource( const TQString& resource,
+ const TQString& parent,
+ const TQString& contentsType );
+ bool kmailRemoveSubresource( const TQString& resource );
+
+private slots:
+ virtual void unregisteredFromDCOP( const TQCString& );
+
+private:
+ /** Connect a signal from KMail to a local slot. */
+ bool connectKMailSignal( const TQCString&, const TQCString& );
+
+ ResourceKolabBase* mResource;
+ DCOPClient* mDCOPClient;
+ KMailICalIface_stub* mKMailIcalIfaceStub;
+};
+
+}
+
+#endif // KMAILCONNECTION_H
diff --git a/tderesources/kolab/shared/kolabbase.cpp b/tderesources/kolab/shared/kolabbase.cpp
new file mode 100644
index 000000000..167f2566a
--- /dev/null
+++ b/tderesources/kolab/shared/kolabbase.cpp
@@ -0,0 +1,487 @@
+/*
+ This file is part of the kolab resource - the implementation of the
+ Kolab storage format. See www.kolab.org for documentation on this.
+
+ Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ TQt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "kolabbase.h"
+
+#include <kabc/addressee.h>
+#include <libkcal/journal.h>
+#include <libtdepim/kpimprefs.h>
+#include <libemailfunctions/email.h>
+#include <kdebug.h>
+#include <tqfile.h>
+
+using namespace Kolab;
+
+
+KolabBase::KolabBase( const TQString& tz )
+ : mCreationDate( TQDateTime::currentDateTime() ),
+ mLastModified( TQDateTime::currentDateTime() ),
+ mSensitivity( Public ), mTimeZoneId( tz ),
+ mHasPilotSyncId( false ), mHasPilotSyncStatus( false )
+{
+}
+
+KolabBase::~KolabBase()
+{
+}
+
+void KolabBase::setFields( const KCal::Incidence* incidence )
+{
+ // So far unhandled KCal::IncidenceBase fields:
+ // mPilotID, mSyncStatus, mFloats
+
+ setUid( incidence->uid() );
+ setBody( incidence->description() );
+ setCategories( incidence->categoriesStr() );
+ setCreationDate( localToUTC( incidence->created() ) );
+ setLastModified( localToUTC( incidence->lastModified() ) );
+ setSensitivity( static_cast<Sensitivity>( incidence->secrecy() ) );
+ // TODO: Attachments
+}
+
+void KolabBase::saveTo( KCal::Incidence* incidence ) const
+{
+ incidence->setUid( uid() );
+ incidence->setDescription( body() );
+ incidence->setCategories( categories() );
+ incidence->setCreated( utcToLocal( creationDate() ) );
+ incidence->setLastModified( utcToLocal( lastModified() ) );
+ incidence->setSecrecy( sensitivity() );
+ // TODO: Attachments
+}
+
+void KolabBase::setFields( const KABC::Addressee* addressee )
+{
+ // An addressee does not have a creation date, so somehow we should
+ // make one, if this is a new entry
+
+ setUid( addressee->uid() );
+ setBody( addressee->note() );
+ setCategories( addressee->categories().join( "," ) );
+
+ // Set creation-time and last-modification-time
+ const TQString creationString = addressee->custom( "KOLAB", "CreationDate" );
+ kdDebug(5006) << "Creation time string: " << creationString << endl;
+ TQDateTime creationDate;
+ if ( creationString.isEmpty() ) {
+ creationDate = TQDateTime::currentDateTime();
+ kdDebug(5006) << "Creation date set to current time\n";
+ }
+ else {
+ creationDate = stringToDateTime( creationString );
+ kdDebug(5006) << "Creation date loaded\n";
+ }
+ TQDateTime modified = addressee->revision();
+ if ( !modified.isValid() )
+ modified = TQDateTime::currentDateTime();
+ setLastModified( modified );
+ if ( modified < creationDate ) {
+ // It's not possible that the modification date is earlier than creation
+ creationDate = modified;
+ kdDebug(5006) << "Creation date set to modification date\n";
+ }
+ setCreationDate( creationDate );
+ const TQString newCreationDate = dateTimeToString( creationDate );
+ if ( creationString != newCreationDate ) {
+ // We modified the creation date, so store it for future reference
+ const_cast<KABC::Addressee*>( addressee )
+ ->insertCustom( "KOLAB", "CreationDate", newCreationDate );
+ kdDebug(5006) << "Creation date modified. New one: " << newCreationDate << endl;
+ }
+
+ switch( addressee->secrecy().type() ) {
+ case KABC::Secrecy::Private:
+ setSensitivity( Private );
+ break;
+ case KABC::Secrecy::Confidential:
+ setSensitivity( Confidential );
+ break;
+ default:
+ setSensitivity( Public );
+ }
+
+ // TODO: Attachments
+}
+
+void KolabBase::saveTo( KABC::Addressee* addressee ) const
+{
+ addressee->setUid( uid() );
+ addressee->setNote( body() );
+ addressee->setCategories( TQStringList::split( ',', categories() ) );
+ addressee->setRevision( lastModified() );
+ addressee->insertCustom( "KOLAB", "CreationDate",
+ dateTimeToString( creationDate() ) );
+
+ switch( sensitivity() ) {
+ case Private:
+ addressee->setSecrecy( KABC::Secrecy( KABC::Secrecy::Private ) );
+ break;
+ case Confidential:
+ addressee->setSecrecy( KABC::Secrecy( KABC::Secrecy::Confidential ) );
+ break;
+ default:
+ addressee->setSecrecy( KABC::Secrecy( KABC::Secrecy::Public ) );
+ break;
+ }
+
+ // TODO: Attachments
+}
+
+void KolabBase::setUid( const TQString& uid )
+{
+ mUid = uid;
+}
+
+TQString KolabBase::uid() const
+{
+ return mUid;
+}
+
+void KolabBase::setBody( const TQString& body )
+{
+ mBody = body;
+}
+
+TQString KolabBase::body() const
+{
+ return mBody;
+}
+
+void KolabBase::setCategories( const TQString& categories )
+{
+ mCategories = categories;
+}
+
+TQString KolabBase::categories() const
+{
+ return mCategories;
+}
+
+void KolabBase::setCreationDate( const TQDateTime& date )
+{
+ mCreationDate = date;
+}
+
+TQDateTime KolabBase::creationDate() const
+{
+ return mCreationDate;
+}
+
+void KolabBase::setLastModified( const TQDateTime& date )
+{
+ mLastModified = date;
+}
+
+TQDateTime KolabBase::lastModified() const
+{
+ return mLastModified;
+}
+
+void KolabBase::setSensitivity( Sensitivity sensitivity )
+{
+ mSensitivity = sensitivity;
+}
+
+KolabBase::Sensitivity KolabBase::sensitivity() const
+{
+ return mSensitivity;
+}
+
+void KolabBase::setPilotSyncId( unsigned long id )
+{
+ mHasPilotSyncId = true;
+ mPilotSyncId = id;
+}
+
+bool KolabBase::hasPilotSyncId() const
+{
+ return mHasPilotSyncId;
+}
+
+unsigned long KolabBase::pilotSyncId() const
+{
+ return mPilotSyncId;
+}
+
+void KolabBase::setPilotSyncStatus( int status )
+{
+ mHasPilotSyncStatus = true;
+ mPilotSyncStatus = status;
+}
+
+bool KolabBase::hasPilotSyncStatus() const
+{
+ return mHasPilotSyncStatus;
+}
+
+int KolabBase::pilotSyncStatus() const
+{
+ return mPilotSyncStatus;
+}
+
+bool KolabBase::loadEmailAttribute( TQDomElement& element, Email& email )
+{
+ for ( TQDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ TQDomElement e = n.toElement();
+ const TQString tagName = e.tagName();
+
+ if ( tagName == "display-name" ) {
+ // Quote the text in case it contains commas or other quotable chars.
+ TQString tusername = KPIM::quoteNameIfNecessary( e.text() );
+
+ TQString tname, temail;
+ // ignore the return value because it will always be false since
+ // tusername does not contain "@domain".
+ KPIM::getNameAndMail( tusername, tname, temail );
+ email.displayName = tname;
+ }
+ else if ( tagName == "smtp-address" )
+ email.smtpAddress = e.text();
+ else
+ // TODO: Unhandled tag - save for later storage
+ kdDebug() << "Warning: Unhandled tag " << e.tagName() << endl;
+ } else
+ kdDebug() << "Node is not a comment or an element???" << endl;
+ }
+
+ return true;
+}
+
+void KolabBase::saveEmailAttribute( TQDomElement& element, const Email& email,
+ const TQString& tagName ) const
+{
+ TQDomElement e = element.ownerDocument().createElement( tagName );
+ element.appendChild( e );
+ writeString( e, "display-name", email.displayName );
+ writeString( e, "smtp-address", email.smtpAddress );
+}
+
+bool KolabBase::loadAttribute( TQDomElement& element )
+{
+ const TQString tagName = element.tagName();
+ switch ( tagName[0].latin1() ) {
+ case 'u':
+ if ( tagName == "uid" ) {
+ setUid( element.text() );
+ return true;
+ }
+ break;
+ case 'b':
+ if ( tagName == "body" ) {
+ setBody( element.text() );
+ return true;
+ }
+ break;
+ case 'c':
+ if ( tagName == "categories" ) {
+ setCategories( element.text() );
+ return true;
+ }
+ if ( tagName == "creation-date" ) {
+ setCreationDate( stringToDateTime( element.text() ) );
+ return true;
+ }
+ break;
+ case 'l':
+ if ( tagName == "last-modification-date" ) {
+ setLastModified( stringToDateTime( element.text() ) );
+ return true;
+ }
+ break;
+ case 's':
+ if ( tagName == "sensitivity" ) {
+ setSensitivity( stringToSensitivity( element.text() ) );
+ return true;
+ }
+ break;
+ case 'p':
+ if ( tagName == "product-id" )
+ return true; // ignore this field
+ if ( tagName == "pilot-sync-id" ) {
+ setPilotSyncId( element.text().toULong() );
+ return true;
+ }
+ if ( tagName == "pilot-sync-status" ) {
+ setPilotSyncStatus( element.text().toInt() );
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
+bool KolabBase::saveAttributes( TQDomElement& element ) const
+{
+ writeString( element, "product-id", productID() );
+ writeString( element, "uid", uid() );
+ writeString( element, "body", body() );
+ writeString( element, "categories", categories() );
+ writeString( element, "creation-date", dateTimeToString( creationDate() ) );
+ writeString( element, "last-modification-date",
+ dateTimeToString( lastModified() ) );
+ writeString( element, "sensitivity", sensitivityToString( sensitivity() ) );
+ if ( hasPilotSyncId() )
+ writeString( element, "pilot-sync-id", TQString::number( pilotSyncId() ) );
+ if ( hasPilotSyncStatus() )
+ writeString( element, "pilot-sync-status", TQString::number( pilotSyncStatus() ) );
+ return true;
+}
+
+bool KolabBase::load( const TQString& xml )
+{
+ TQString errorMsg;
+ int errorLine, errorColumn;
+ TQDomDocument document;
+ bool ok = document.setContent( xml, &errorMsg, &errorLine, &errorColumn );
+
+ if ( !ok ) {
+ tqWarning( "Error loading document: %s, line %d, column %d",
+ errorMsg.latin1(), errorLine, errorColumn );
+ return false;
+ }
+
+ // XML file loaded into tree. Now parse it
+ return loadXML( document );
+}
+
+bool KolabBase::load( TQFile& xml )
+{
+ TQString errorMsg;
+ int errorLine, errorColumn;
+ TQDomDocument document;
+ bool ok = document.setContent( &xml, &errorMsg, &errorLine, &errorColumn );
+
+ if ( !ok ) {
+ tqWarning( "Error loading document: %s, line %d, column %d",
+ errorMsg.latin1(), errorLine, errorColumn );
+ return false;
+ }
+
+ // XML file loaded into tree. Now parse it
+ return loadXML( document );
+}
+
+TQDomDocument KolabBase::domTree()
+{
+ TQDomDocument document;
+
+ TQString p = "version=\"1.0\" encoding=\"UTF-8\"";
+ document.appendChild(document.createProcessingInstruction( "xml", p ) );
+
+ return document;
+}
+
+
+TQString KolabBase::dateTimeToString( const TQDateTime& time )
+{
+ return time.toString( Qt::ISODate ) + 'Z';
+}
+
+TQString KolabBase::dateToString( const TQDate& date )
+{
+ return date.toString( Qt::ISODate );
+}
+
+TQDateTime KolabBase::stringToDateTime( const TQString& _date )
+{
+ TQString date( _date );
+ //Deal with data from some clients that always append a Z to dates.
+ if ( date.endsWith( "ZZ" ) )
+ date.truncate( date.length() - 2 );
+ //In TQt3, Qt::ISODate cannot handle a trailing Z for UTC, so remove if found.
+ else if ( date.endsWith( "Z" ) )
+ date.truncate( date.length() - 1 );
+ return TQDateTime::fromString( date, Qt::ISODate );
+}
+
+TQDate KolabBase::stringToDate( const TQString& date )
+{
+ return TQDate::fromString( date, Qt::ISODate );
+}
+
+TQString KolabBase::sensitivityToString( Sensitivity s )
+{
+ switch( s ) {
+ case Private: return "private";
+ case Confidential: return "confidential";
+ case Public: return "public";
+ }
+
+ return "What what what???";
+}
+
+KolabBase::Sensitivity KolabBase::stringToSensitivity( const TQString& s )
+{
+ if ( s == "private" )
+ return Private;
+ if ( s == "confidential" )
+ return Confidential;
+ return Public;
+}
+
+TQString KolabBase::colorToString( const TQColor& color )
+{
+ // Color is in the format "#RRGGBB"
+ return color.name();
+}
+
+TQColor KolabBase::stringToColor( const TQString& s )
+{
+ return TQColor( s );
+}
+
+void KolabBase::writeString( TQDomElement& element, const TQString& tag,
+ const TQString& tagString )
+{
+ if ( !tagString.isEmpty() ) {
+ TQDomElement e = element.ownerDocument().createElement( tag );
+ TQDomText t = element.ownerDocument().createTextNode( tagString );
+ e.appendChild( t );
+ element.appendChild( e );
+ }
+}
+
+TQDateTime KolabBase::localToUTC( const TQDateTime& time ) const
+{
+ return KPimPrefs::localTimeToUtc( time, mTimeZoneId );
+}
+
+TQDateTime KolabBase::utcToLocal( const TQDateTime& time ) const
+{
+ return KPimPrefs::utcToLocalTime( time, mTimeZoneId );
+}
diff --git a/tderesources/kolab/shared/kolabbase.h b/tderesources/kolab/shared/kolabbase.h
new file mode 100644
index 000000000..294a7d81b
--- /dev/null
+++ b/tderesources/kolab/shared/kolabbase.h
@@ -0,0 +1,177 @@
+/*
+ This file is part of the kolab resource - the implementation of the
+ Kolab storage format. See www.kolab.org for documentation on this.
+
+ Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ TQt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef KOLABBASE_H
+#define KOLABBASE_H
+
+#include <tqdom.h>
+#include <tqdatetime.h>
+#include <tqcolor.h>
+
+class TQFile;
+
+namespace KCal {
+ class Incidence;
+}
+
+namespace KABC {
+ class Addressee;
+}
+
+namespace Kolab {
+
+class KolabBase {
+public:
+ struct Email {
+ public:
+ Email( const TQString& name = TQString(),
+ const TQString& email = TQString() )
+ : displayName( name ), smtpAddress( email )
+ {
+ }
+
+ TQString displayName;
+ TQString smtpAddress;
+ };
+
+ enum Sensitivity { Public = 0, Private = 1, Confidential = 2 };
+
+ explicit KolabBase( const TQString& timezone = TQString() );
+ virtual ~KolabBase();
+
+ // Return a string identifying this type
+ virtual TQString type() const = 0;
+
+ virtual void setUid( const TQString& uid );
+ virtual TQString uid() const;
+
+ virtual void setBody( const TQString& body );
+ virtual TQString body() const;
+
+ virtual void setCategories( const TQString& categories );
+ virtual TQString categories() const;
+
+ virtual void setCreationDate( const TQDateTime& date );
+ virtual TQDateTime creationDate() const;
+
+ virtual void setLastModified( const TQDateTime& date );
+ virtual TQDateTime lastModified() const;
+
+ virtual void setSensitivity( Sensitivity sensitivity );
+ virtual Sensitivity sensitivity() const;
+
+ virtual void setPilotSyncId( unsigned long id );
+ virtual bool hasPilotSyncId() const;
+ virtual unsigned long pilotSyncId() const;
+
+ virtual void setPilotSyncStatus( int status );
+ virtual bool hasPilotSyncStatus() const;
+ virtual int pilotSyncStatus() const;
+
+ // String - Date conversion methods
+ static TQString dateTimeToString( const TQDateTime& time );
+ static TQString dateToString( const TQDate& date );
+ static TQDateTime stringToDateTime( const TQString& time );
+ static TQDate stringToDate( const TQString& date );
+
+ // String - Sensitivity conversion methods
+ static TQString sensitivityToString( Sensitivity );
+ static Sensitivity stringToSensitivity( const TQString& );
+
+ // String - Color conversion methods
+ static TQString colorToString( const TQColor& );
+ static TQColor stringToColor( const TQString& );
+
+ // Load this object by reading the XML file
+ bool load( const TQString& xml );
+ bool load( TQFile& xml );
+
+ // Load this TQDomDocument
+ virtual bool loadXML( const TQDomDocument& xml ) = 0;
+
+ // Serialize this object to an XML string
+ virtual TQString saveXML() const = 0;
+
+protected:
+ /// Read all known fields from this ical incidence
+ void setFields( const KCal::Incidence* );
+
+ /// Save all known fields into this ical incidence
+ void saveTo( KCal::Incidence* ) const;
+
+ /// Read all known fields from this contact
+ void setFields( const KABC::Addressee* );
+
+ /// Save all known fields into this contact
+ void saveTo( KABC::Addressee* ) const;
+
+ // This just makes the initial dom tree with version and doctype
+ static TQDomDocument domTree();
+
+ bool loadEmailAttribute( TQDomElement& element, Email& email );
+
+ void saveEmailAttribute( TQDomElement& element, const Email& email,
+ const TQString& tagName = "email" ) const;
+
+ // Load the attributes of this class
+ virtual bool loadAttribute( TQDomElement& );
+
+ // Save the attributes of this class
+ virtual bool saveAttributes( TQDomElement& ) const;
+
+ // Return the product ID
+ virtual TQString productID() const = 0;
+
+ // Write a string tag
+ static void writeString( TQDomElement&, const TQString&, const TQString& );
+
+ TQDateTime localToUTC( const TQDateTime& time ) const;
+ TQDateTime utcToLocal( const TQDateTime& time ) const;
+
+ TQString mUid;
+ TQString mBody;
+ TQString mCategories;
+ TQDateTime mCreationDate;
+ TQDateTime mLastModified;
+ Sensitivity mSensitivity;
+ TQString mTimeZoneId;
+
+ // KPilot synchronization stuff
+ bool mHasPilotSyncId, mHasPilotSyncStatus;
+ unsigned long mPilotSyncId;
+ int mPilotSyncStatus;
+};
+
+}
+
+#endif // KOLABBASE_H
diff --git a/tderesources/kolab/shared/resourcekolabbase.cpp b/tderesources/kolab/shared/resourcekolabbase.cpp
new file mode 100644
index 000000000..a56538a67
--- /dev/null
+++ b/tderesources/kolab/shared/resourcekolabbase.cpp
@@ -0,0 +1,287 @@
+/*
+ This file is part of the kolab resource - the implementation of the
+ Kolab storage format. See www.kolab.org for documentation on this.
+
+ Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ TQt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "resourcekolabbase.h"
+#include "kmailconnection.h"
+
+#include <folderselectdialog.h>
+
+#include <klocale.h>
+#include <kstandarddirs.h>
+#include <kinputdialog.h>
+#include <kurl.h>
+#include <ktempfile.h>
+#include <kmessagebox.h>
+#include <tqtextstream.h>
+#include <kdebug.h>
+
+using namespace Kolab;
+
+static unsigned int uniquifier = 0;
+
+ResourceKolabBase::ResourceKolabBase( const TQCString& objId )
+ : mSilent( false )
+{
+ TDEGlobal::locale()->insertCatalogue( "kres_kolab" );
+ TDEGlobal::locale()->insertCatalogue( "libkcal" );
+ TQString uniqueObjId = TQString( objId ) + TQString::number( uniquifier++ );
+ mConnection = new KMailConnection( this, uniqueObjId.utf8() );
+}
+
+ResourceKolabBase::~ResourceKolabBase()
+{
+ delete mConnection;
+}
+
+
+bool ResourceKolabBase::kmailSubresources( TQValueList<KMailICalIface::SubResource>& lst,
+ const TQString& contentsType ) const
+{
+ return mConnection->kmailSubresources( lst, contentsType );
+}
+
+bool ResourceKolabBase::kmailTriggerSync( const TQString& contentsType ) const
+{
+ return mConnection->kmailTriggerSync( contentsType );
+}
+
+
+bool ResourceKolabBase::kmailIncidencesCount( int &count,
+ const TQString& mimetype,
+ const TQString& resource ) const
+{
+ return mConnection->kmailIncidencesCount( count, mimetype, resource );
+}
+
+bool ResourceKolabBase::kmailIncidences( TQMap<TQ_UINT32, TQString>& lst,
+ const TQString& mimetype,
+ const TQString& resource,
+ int startIndex,
+ int nbMessages ) const
+{
+ return mConnection->kmailIncidences( lst, mimetype, resource, startIndex, nbMessages );
+}
+
+bool ResourceKolabBase::kmailGetAttachment( KURL& url, const TQString& resource,
+ TQ_UINT32 sernum,
+ const TQString& filename ) const
+{
+ return mConnection->kmailGetAttachment( url, resource, sernum, filename );
+}
+
+bool ResourceKolabBase::kmailAttachmentMimetype( TQString & mimeType, TQString & resource,
+ TQ_UINT32 sernum, const TQString & filename ) const
+{
+ return mConnection->kmailAttachmentMimetype( mimeType, resource, sernum, filename );
+}
+
+bool ResourceKolabBase::kmailListAttachments( TQStringList &list,
+ const TQString & resource,
+ TQ_UINT32 sernum ) const
+{
+ return mConnection->kmailListAttachments( list, resource, sernum );
+}
+
+bool ResourceKolabBase::kmailDeleteIncidence( const TQString& resource,
+ TQ_UINT32 sernum )
+{
+ return mSilent || mConnection->kmailDeleteIncidence( resource, sernum );
+}
+
+static TQString plainTextBody()
+{
+ const char * firstPartTextToTranslate = I18N_NOOP(
+ "This is a Kolab Groupware object.\nTo view this object you"
+ " will need an email client that can understand the Kolab"
+ " Groupware format.\nFor a list of such email clients please"
+ " visit\n%1" );
+ const char * url = "http://www.kolab.org/kolab2-clients.html";
+ TQString firstPartTextUntranslated = TQString::fromLatin1( firstPartTextToTranslate ).arg( url );
+ TQString firstPartText = i18n( firstPartTextToTranslate ).arg( url );
+ if ( firstPartText != firstPartTextUntranslated ) {
+ firstPartText.append("\n\n-----------------------------------------------------\n\n");
+ firstPartText.append( firstPartTextUntranslated );
+ }
+ return firstPartText;
+}
+
+bool ResourceKolabBase::kmailUpdate( const TQString& resource,
+ TQ_UINT32& sernum,
+ const TQString& xml,
+ const TQString& mimetype,
+ const TQString& subject,
+ const CustomHeaderMap& _customHeaders,
+ const TQStringList& _attachmentURLs,
+ const TQStringList& _attachmentMimetypes,
+ const TQStringList& _attachmentNames,
+ const TQStringList& deletedAttachments )
+{
+ if ( mSilent )
+ return true;
+
+ TQString subj = subject;
+ if ( subj.isEmpty() )
+ subj = i18n("Internal kolab data: Do not delete this mail.");
+
+ if ( mimetype.startsWith( "application/x-vnd.kolab" ) ) {
+
+ // Save the xml file. Will be deleted at the end of this method
+ KTempFile file;
+ file.setAutoDelete( true );
+ TQTextStream* stream = file.textStream();
+ stream->setEncoding( TQTextStream::UnicodeUTF8 );
+ *stream << xml;
+ file.close();
+
+ // Add the xml file as an attachment
+ TQStringList attachmentURLs = _attachmentURLs;
+ TQStringList attachmentMimeTypes = _attachmentMimetypes;
+ TQStringList attachmentNames = _attachmentNames;
+ KURL url;
+ url.setPath( file.name() );
+ url.setFileEncoding( "UTF-8" );
+ attachmentURLs.prepend( url.url() );
+ attachmentMimeTypes.prepend( mimetype );
+ attachmentNames.prepend( "kolab.xml" );
+
+ CustomHeaderMap customHeaders( _customHeaders );
+ customHeaders.insert( "X-Kolab-Type", mimetype );
+
+ return mConnection->kmailUpdate( resource, sernum, subj, plainTextBody(), customHeaders,
+ attachmentURLs, attachmentMimeTypes, attachmentNames,
+ deletedAttachments );
+ } else {
+ // ical style, simply put the data inline
+ return mConnection->kmailUpdate( resource, sernum, subj, xml, _customHeaders,
+ _attachmentURLs, _attachmentMimetypes, _attachmentNames, deletedAttachments );
+ }
+}
+
+TQString ResourceKolabBase::configFile( const TQString& type ) const
+{
+ return locateLocal( "config",
+ TQString( "tderesources/kolab/%1rc" ).arg( type ) );
+}
+
+bool ResourceKolabBase::connectToKMail() const
+{
+ return mConnection->connectToKMail();
+}
+
+bool ResourceKolabBase::kmailAddSubresource( const TQString& resource,
+ const TQString& parent,
+ const TQString& contentsType )
+{
+ return mConnection->kmailAddSubresource( resource, parent, contentsType );
+}
+
+bool ResourceKolabBase::kmailRemoveSubresource( const TQString& resource )
+{
+ return mConnection->kmailRemoveSubresource( resource );
+}
+
+TQString ResourceKolabBase::findWritableResource( const ResourceType &type,
+ const ResourceMap& resources,
+ const TQString& text )
+{
+ mErrorCode = NoError;
+
+ // I have to use the label (shown in the dialog) as key here. But given how the
+ // label is made up, it should be unique. If it's not, well the dialog would suck anyway...
+ TQMap<TQString, TQString> possible;
+ TQStringList labels;
+ ResourceMap::ConstIterator it;
+ for ( it = resources.begin(); it != resources.end(); ++it ) {
+ if ( it.data().writable() && it.data().active() ) {
+ // Writable and active possibility
+ possible[ it.data().label() ] = it.key();
+ }
+ }
+
+ if ( possible.isEmpty() ) { // None found!!
+ kdWarning(5650) << "No writable resource found!" << endl;
+
+ TQString errorText;
+ switch( type ) {
+ case Events:
+ errorText = i18n( "You have no writable event folders so saving will not be possible.\n"
+ "Please create or activate at least one writable event folder and try again." );
+ break;
+ case Tasks:
+ errorText = i18n( "You have no writable task folders so saving will not be possible.\n"
+ "Please create or activate at least one writable task folder and try again." );
+ break;
+ case Incidences:
+ errorText = i18n( "You have no writable calendar folder so saving will not be possible.\n"
+ "Please create or activate at least one writable calendar folder and try again." );
+ break;
+ case Notes:
+ errorText = i18n( "You have no writable notes folders so saving will not be possible.\n"
+ "Please create or activate at least one writable notes folder and try again." );
+ break;
+ case Contacts:
+ errorText = i18n( "You have no writable addressbook folder so saving will not be possible.\n"
+ "Please create or activate at least one writable addressbook folder and try again." );
+ break;
+ }
+
+ KMessageBox::error( 0, errorText );
+ mErrorCode = NoWritableFound;
+ return TQString();
+ }
+ if ( possible.count() == 1 )
+ // Just one found
+ return possible.begin().data(); // yes this is the subresource key, i.e. location
+
+ TQString t = text;
+ if ( t.isEmpty() )
+ i18n( "You have more than one writable resource folder. "
+ "Please select the one you want to write to." );
+
+ // Several found, ask the user
+ TQString chosenLabel = KPIM::FolderSelectDialog::getItem( i18n( "Select Resource Folder" ),
+ t, possible.keys() );
+ if ( chosenLabel.isEmpty() ) {
+ // cancelled
+ mErrorCode = UserCancel;
+ return TQString();
+ }
+ return possible[chosenLabel];
+}
+
+KMailICalIface::StorageFormat ResourceKolabBase::kmailStorageFormat( const TQString &folder ) const
+{
+ KMailICalIface::StorageFormat format = (KMailICalIface::StorageFormat) 3;
+ mConnection->kmailStorageFormat( format, folder );
+ return format;
+}
diff --git a/tderesources/kolab/shared/resourcekolabbase.h b/tderesources/kolab/shared/resourcekolabbase.h
new file mode 100644
index 000000000..f32c151fd
--- /dev/null
+++ b/tderesources/kolab/shared/resourcekolabbase.h
@@ -0,0 +1,205 @@
+/*
+ This file is part of the kolab resource - the implementation of the
+ Kolab storage format. See www.kolab.org for documentation on this.
+
+ Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ TQt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef RESOURCEKOLABBASE_H
+#define RESOURCEKOLABBASE_H
+
+#include <tqstring.h>
+#include <tqmap.h>
+#include <tqstringlist.h>
+
+#include "subresource.h"
+#include <kmail/kmailicalIface.h>
+
+class TQCString;
+class KURL;
+
+namespace Kolab {
+
+enum ResourceType { Tasks, Events, Incidences, Contacts, Notes };
+
+class KMailConnection;
+
+/**
+ This class provides the kmail connectivity for IMAP resources.
+
+ The main methods are:
+
+ fromKMail...() : calls made _by_ KMail to add/delete data representation in the resource.
+
+ kmail...() : calls _into_ KMail made by the resource.
+
+ e.g. fromKMailAddIncidence() is called by KMail
+ when a new iCard is there after an IMAP sync.
+
+ By calling fromKMailAddIncidence() KMail notifies
+ the resource about the new incidence, so in the
+ addressbook a new address will appear like magic.
+
+ e.g. kmailAddIncidence() is called by the resource when
+ iCard must be stored by KMail because the user has added
+ an address in the addressbook.
+
+ By calling kmailAddIncidence() the resource causes
+ KMail to store the new address in the (IMAP) folder.
+*/
+class ResourceKolabBase {
+public:
+ ResourceKolabBase( const TQCString& objId );
+ virtual ~ResourceKolabBase();
+
+ // These are the methods called by KMail when the resource changes
+ virtual bool fromKMailAddIncidence( const TQString& type,
+ const TQString& resource,
+ TQ_UINT32 sernum,
+ int format,
+ const TQString& data ) = 0;
+ virtual void fromKMailDelIncidence( const TQString& type,
+ const TQString& resource,
+ const TQString& xml ) = 0;
+ virtual void fromKMailRefresh( const TQString& type,
+ const TQString& resource ) = 0;
+ virtual void fromKMailAddSubresource( const TQString& type,
+ const TQString& resource,
+ const TQString& label,
+ bool writable,
+ bool alarmRelevant ) = 0;
+ virtual void fromKMailDelSubresource( const TQString& type,
+ const TQString& resource ) = 0;
+
+ virtual void fromKMailAsyncLoadResult( const TQMap<TQ_UINT32, TQString>& map,
+ const TQString& type,
+ const TQString& folder ) = 0;
+protected:
+ /// Do the connection to KMail.
+ bool connectToKMail() const;
+
+ // These are the KMail dcop function connections. The docs here say
+ // "Get", which here means that the first argument is the return arg
+
+ /// List all folders with a certain contentsType. Returns a TQMap with
+ /// resourcename/writable pairs
+ bool kmailSubresources( TQValueList<KMailICalIface::SubResource>& lst,
+ const TQString& contentsType ) const;
+
+ /// Get the number of messages in this folder.
+ /// Used to iterate over kmailIncidences by chunks
+ bool kmailIncidencesCount( int& count, const TQString& mimetype,
+ const TQString& resource ) const;
+
+ /// Get the mimetype attachments from a chunk of messages from this folder.
+ /// Returns a TQMap with serialNumber/attachment pairs.
+ bool kmailIncidences( TQMap<TQ_UINT32, TQString>& lst, const TQString& mimetype,
+ const TQString& resource,
+ int startIndex,
+ int nbMessages ) const;
+
+ bool kmailTriggerSync( const TQString& contentType ) const;
+
+public: // for Contact
+ /// Get an attachment from a mail. Returns a URL to it. This can
+ /// be called by the resource after obtaining the incidence.
+ /// The resource must delete the temp file.
+ bool kmailGetAttachment( KURL& url, const TQString& resource,
+ TQ_UINT32 sernum,
+ const TQString& filename ) const;
+
+ /** Get the mimetype of the specified attachment. */
+ bool kmailAttachmentMimetype( TQString &mimeType, TQString &resource,
+ TQ_UINT32 sernum, const TQString &filename ) const;
+
+ /// List all attachments of a mail.
+ bool kmailListAttachments( TQStringList &list, const TQString &resource,
+ TQ_UINT32 sernum ) const;
+
+protected:
+ /// Delete an incidence.
+ bool kmailDeleteIncidence( const TQString& resource, TQ_UINT32 sernum );
+
+ KMailICalIface::StorageFormat kmailStorageFormat( const TQString& folder ) const;
+
+ typedef TQMap<TQCString, TQString> CustomHeaderMap;
+
+ /// Update an incidence. The list of attachments are URLs.
+ /// The parameter sernum is updated with the right KMail serial number
+ bool kmailUpdate( const TQString& resource, TQ_UINT32& sernum,
+ const TQString& xml,
+ const TQString& mimetype,
+ const TQString& subject,
+ const CustomHeaderMap& customHeaders = CustomHeaderMap(),
+ const TQStringList& attachmentURLs = TQStringList(),
+ const TQStringList& attachmentMimetypes = TQStringList(),
+ const TQStringList& attachmentNames = TQStringList(),
+ const TQStringList& deletedAttachments = TQStringList() );
+
+ bool kmailAddSubresource( const TQString& resource, const TQString& parent,
+ const TQString& contentsType );
+ bool kmailRemoveSubresource( const TQString& resource );
+
+ /// Get the full path of the config file.
+ TQString configFile( const TQString& type ) const;
+
+ /// If only one of these is writable, return that. Otherwise return null.
+ TQString findWritableResource( const ResourceType &type,
+ const ResourceMap& resources,
+ const TQString& text = TQString() );
+
+ enum ErrorCode {
+ NoError,
+ NoWritableFound, /**< No writable resource is available */
+ UserCancel /**< User canceled the operation */
+ };
+ ErrorCode mErrorCode;
+
+ bool mSilent;
+
+ /**
+ * This is used to store a mapping from the XML UID to the KMail
+ * serial number of the mail it's stored in. That provides a quick way
+ * to access the storage in KMail.
+ */
+ UidMap mUidMap;
+
+ /// This is used to distinguish operations triggered by the user,
+ /// from operations triggered by KMail
+ TQStringList mUidsPendingAdding;
+ TQStringList mUidsPendingDeletion;
+ TQStringList mUidsPendingUpdate;
+
+private:
+ mutable KMailConnection* mConnection;
+};
+
+}
+
+#endif // RESOURCEKOLABBASE_H
diff --git a/tderesources/kolab/shared/subresource.cpp b/tderesources/kolab/shared/subresource.cpp
new file mode 100644
index 000000000..7520d275a
--- /dev/null
+++ b/tderesources/kolab/shared/subresource.cpp
@@ -0,0 +1,133 @@
+/*
+ This file is part of libkabc and/or kaddressbook.
+ Copyright (c) 2004 Klarälvdalens Datakonsult AB
+ <info@klaralvdalens-datakonsult.se>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ TQt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "subresource.h"
+
+using namespace Kolab;
+
+SubResource::SubResource( bool active, bool writable,
+ bool alarmRelevant, const TQString& label,
+ int completionWeight )
+ : mActive( active ), mWritable( writable ), mAlarmRelevant( alarmRelevant ),
+ mLabel( label ), mCompletionWeight( completionWeight )
+{
+}
+
+SubResource::SubResource( bool active, bool writable,
+ const TQString& label, int completionWeight )
+ : mActive( active ), mWritable( writable ), mAlarmRelevant( false ),
+ mLabel( label ), mCompletionWeight( completionWeight )
+{
+}
+
+SubResource::~SubResource()
+{
+}
+
+void SubResource::setActive( bool active )
+{
+ mActive = active;
+}
+
+bool SubResource::active() const
+{
+ return mActive;
+}
+
+void SubResource::setAlarmRelevant( bool active )
+{
+ mAlarmRelevant = active;
+}
+
+bool SubResource::alarmRelevant() const
+{
+ return mAlarmRelevant;
+}
+
+void SubResource::setWritable( bool writable )
+{
+ mWritable = writable;
+}
+
+bool SubResource::writable() const
+{
+ return mWritable;
+}
+
+void SubResource::setLabel( const TQString& label )
+{
+ mLabel = label;
+}
+
+TQString SubResource::label() const
+{
+ return mLabel;
+}
+
+void SubResource::setCompletionWeight( int completionWeight )
+{
+ mCompletionWeight = completionWeight;
+}
+
+int SubResource::completionWeight() const
+{
+ return mCompletionWeight;
+}
+
+StorageReference::StorageReference( const TQString& resource, TQ_UINT32 sernum )
+ : mResource( resource ), mSerialNumber( sernum )
+{
+}
+
+StorageReference::~StorageReference()
+{
+}
+
+void StorageReference::setResource( const TQString& resource )
+{
+ mResource = resource;
+}
+
+TQString StorageReference::resource() const
+{
+ return mResource;
+}
+
+void StorageReference::setSerialNumber( TQ_UINT32 serialNumber )
+{
+ mSerialNumber = serialNumber;
+}
+
+TQ_UINT32 StorageReference::serialNumber() const
+{
+ return mSerialNumber;
+}
diff --git a/tderesources/kolab/shared/subresource.h b/tderesources/kolab/shared/subresource.h
new file mode 100644
index 000000000..79104a747
--- /dev/null
+++ b/tderesources/kolab/shared/subresource.h
@@ -0,0 +1,117 @@
+/*
+ This file is part of libkabc and/or kaddressbook.
+ Copyright (c) 2004 Klarälvdalens Datakonsult AB
+ <info@klaralvdalens-datakonsult.se>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ TQt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef SUBRESOURCE_H
+#define SUBRESOURCE_H
+
+#include <tqstring.h>
+#include <tqmap.h>
+
+
+namespace Kolab {
+
+/**
+ * This class is used to store in a map from resource id to this, providing
+ * a lookup of the subresource settings.
+ */
+class SubResource {
+public:
+ // This is just for TQMap
+ SubResource() {}
+
+ SubResource( bool active, bool writable, const TQString& label,
+ int completionWeight = 100 );
+
+ SubResource( bool active, bool writable, bool alarmRelevant,
+ const TQString& label, int completionWeight = 100 );
+ virtual ~SubResource();
+
+ virtual void setActive( bool active );
+ virtual bool active() const;
+
+ virtual void setWritable( bool writable );
+ virtual bool writable() const;
+
+ virtual void setAlarmRelevant( bool active );
+ virtual bool alarmRelevant() const;
+
+ virtual void setLabel( const TQString& label );
+ virtual TQString label() const;
+
+ virtual void setCompletionWeight( int completionWeight );
+ virtual int completionWeight() const;
+
+private:
+ bool mActive; // Controlled by the applications
+ bool mWritable; // Set if the KMail folder is writable
+ bool mAlarmRelevant; // Set if the alarms from this resource are of
+ // interest to the user, as per folder acls
+ TQString mLabel; // The GUI name of this resource
+
+ // This is just for the abc plugin. But as long as only this is here,
+ // it's just as cheap to have it in here as making a d-pointer that
+ // subclasses could add to. If more are added, then we should refactor
+ // to a d-pointer instead.
+ int mCompletionWeight;
+};
+
+typedef TQMap<TQString, SubResource> ResourceMap;
+
+/**
+ * This class is used to store a mapping from the XML UID to the KMail
+ * serial number of the mail it's stored in and the resource. That provides
+ * a quick way to access the storage in KMail.
+ */
+class StorageReference {
+public:
+ // Just for TQMap
+ StorageReference() {}
+
+ StorageReference( const TQString& resource, TQ_UINT32 sernum );
+ virtual ~StorageReference();
+
+ virtual void setResource( const TQString& resource );
+ virtual TQString resource() const;
+
+ virtual void setSerialNumber( TQ_UINT32 serialNumber );
+ virtual TQ_UINT32 serialNumber() const;
+
+private:
+ TQString mResource;
+ TQ_UINT32 mSerialNumber;
+};
+
+typedef TQMap<TQString, StorageReference> UidMap;
+
+}
+
+#endif // SUBRESOURCE_H
diff --git a/tderesources/kolab/uninstall.desktop b/tderesources/kolab/uninstall.desktop
new file mode 100644
index 000000000..e1e3e1732
--- /dev/null
+++ b/tderesources/kolab/uninstall.desktop
@@ -0,0 +1,2 @@
+[Desktop Entry]
+Hidden=true
diff --git a/tderesources/kolab/upgrade-resourcetype.pl b/tderesources/kolab/upgrade-resourcetype.pl
new file mode 100644
index 000000000..98337a88d
--- /dev/null
+++ b/tderesources/kolab/upgrade-resourcetype.pl
@@ -0,0 +1,24 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+# This script updates some configuration keys
+
+# read the whole config file
+my $currentGroup = "";
+my %configFile;
+while ( <> ) {
+ chomp; # eat the trailing '\n'
+ next if ( /^$/ ); # skip empty lines
+ next if ( /^\#/ ); # skip comments
+ if ( /^\[(.+)\]$/ ) { # group begin
+ $currentGroup = $1;
+ next;
+ } elsif ( $currentGroup =~ /^Resource/ ) {
+ my ($key,$value) = split /=/;
+ if ( $key eq "ResourceType" and $value eq "kolab" ) {
+ print "# DELETE [$currentGroup]$key\n";
+ print "[$currentGroup]\nResourceType=imap\n";
+ }
+ }
+}