summaryrefslogtreecommitdiffstats
path: root/tderesources/kolab/kabc
diff options
context:
space:
mode:
Diffstat (limited to 'tderesources/kolab/kabc')
-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
8 files changed, 2670 insertions, 0 deletions
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)
+