diff options
Diffstat (limited to 'tderesources/kolab/kabc')
-rw-r--r-- | tderesources/kolab/kabc/CMakeLists.txt | 54 | ||||
-rw-r--r-- | tderesources/kolab/kabc/Makefile.am | 27 | ||||
-rw-r--r-- | tderesources/kolab/kabc/contact.cpp | 1326 | ||||
-rw-r--r-- | tderesources/kolab/kabc/contact.h | 286 | ||||
-rw-r--r-- | tderesources/kolab/kabc/kolab.desktop | 52 | ||||
-rw-r--r-- | tderesources/kolab/kabc/resourcekolab.cpp | 694 | ||||
-rw-r--r-- | tderesources/kolab/kabc/resourcekolab.h | 179 | ||||
-rw-r--r-- | tderesources/kolab/kabc/resourcekolab_plugin.cpp | 52 |
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) + |