Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117755807
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
160 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/kolabformatV2/contact.cpp b/kolabformatV2/contact.cpp
new file mode 100644
index 0000000..e421629
--- /dev/null
+++ b/kolabformatV2/contact.cpp
@@ -0,0 +1,1208 @@
+/*
+ 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 Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), 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
+ Qt. 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 <kabc/addressee.h>
+#include <kcalcore/freebusyurlstore.h>
+#include <kio/netaccess.h>
+#include <kdebug.h>
+#include <QFile>
+#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 QString& xml )
+ : mHasGeo( false )
+{
+ load( xml );
+}
+
+Contact::~Contact()
+{
+}
+
+void Contact::setGivenName( const QString& name )
+{
+ mGivenName = name;
+}
+
+QString Contact::givenName() const
+{
+ return mGivenName;
+}
+
+void Contact::setMiddleNames( const QString& names )
+{
+ mMiddleNames = names;
+}
+
+QString Contact::middleNames() const
+{
+ return mMiddleNames;
+}
+
+void Contact::setLastName( const QString& name )
+{
+ mLastName = name;
+}
+
+QString Contact::lastName() const
+{
+ return mLastName;
+}
+
+void Contact::setFullName( const QString& name )
+{
+ mFullName = name;
+}
+
+QString Contact::fullName() const
+{
+ return mFullName;
+}
+
+void Contact::setInitials( const QString& initials )
+{
+ mInitials = initials;
+}
+
+QString Contact::initials() const
+{
+ return mInitials;
+}
+
+void Contact::setPrefix( const QString& prefix )
+{
+ mPrefix = prefix;
+}
+
+QString Contact::prefix() const
+{
+ return mPrefix;
+}
+
+void Contact::setSuffix( const QString& suffix )
+{
+ mSuffix = suffix;
+}
+
+QString Contact::suffix() const
+{
+ return mSuffix;
+}
+
+void Contact::setRole( const QString& role )
+{
+ mRole = role;
+}
+
+QString Contact::role() const
+{
+ return mRole;
+}
+
+void Contact::setFreeBusyUrl( const QString& fbUrl )
+{
+ mFreeBusyUrl = fbUrl;
+}
+
+QString Contact::freeBusyUrl() const
+{
+ return mFreeBusyUrl;
+}
+
+void Contact::setOrganization( const QString& organization )
+{
+ mOrganization = organization;
+}
+
+QString Contact::organization() const
+{
+ return mOrganization;
+}
+
+void Contact::setWebPage( const QString& url )
+{
+ mWebPage = url;
+}
+
+QString Contact::webPage() const
+{
+ return mWebPage;
+}
+
+void Contact::setIMAddress( const QString& imAddress )
+{
+ mIMAddress = imAddress;
+}
+
+QString Contact::imAddress() const
+{
+ return mIMAddress;
+}
+
+void Contact::setDepartment( const QString& department )
+{
+ mDepartment = department;
+}
+
+QString Contact::department() const
+{
+ return mDepartment;
+}
+
+void Contact::setOfficeLocation( const QString& location )
+{
+ mOfficeLocation = location;
+}
+
+QString Contact::officeLocation() const
+{
+ return mOfficeLocation;
+}
+
+void Contact::setProfession( const QString& profession )
+{
+ mProfession = profession;
+}
+
+QString Contact::profession() const
+{
+ return mProfession;
+}
+
+void Contact::setTitle( const QString& title )
+{
+ mTitle = title;
+}
+
+QString Contact::title() const
+{
+ return mTitle;
+}
+
+void Contact::setManagerName( const QString& name )
+{
+ mManagerName = name;
+}
+
+QString Contact::managerName() const
+{
+ return mManagerName;
+}
+
+void Contact::setAssistant( const QString& name )
+{
+ mAssistant = name;
+}
+
+QString Contact::assistant() const
+{
+ return mAssistant;
+}
+
+void Contact::setNickName( const QString& name )
+{
+ mNickName = name;
+}
+
+QString Contact::nickName() const
+{
+ return mNickName;
+}
+
+void Contact::setSpouseName( const QString& name )
+{
+ mSpouseName = name;
+}
+
+QString Contact::spouseName() const
+{
+ return mSpouseName;
+}
+
+void Contact::setBirthday( const QDate& date )
+{
+ mBirthday = date;
+}
+
+QDate Contact::birthday() const
+{
+ return mBirthday;
+}
+
+void Contact::setAnniversary( const QDate& date )
+{
+ mAnniversary = date;
+}
+
+QDate Contact::anniversary() const
+{
+ return mAnniversary;
+}
+
+void Contact::setChildren( const QString& children )
+{
+ mChildren = children;
+}
+
+QString Contact::children() const
+{
+ return mChildren;
+}
+
+void Contact::setGender( const QString& gender )
+{
+ mGender = gender;
+}
+
+QString Contact::gender() const
+{
+ return mGender;
+}
+
+void Contact::setLanguage( const QString& language )
+{
+ mLanguage = language;
+}
+
+QString Contact::language() const
+{
+ return mLanguage;
+}
+
+void Contact::addPhoneNumber( const PhoneNumber& number )
+{
+ mPhoneNumbers.append( number );
+}
+
+QList<Contact::PhoneNumber>& Contact::phoneNumbers()
+{
+ return mPhoneNumbers;
+}
+
+const QList<Contact::PhoneNumber>& Contact::phoneNumbers() const
+{
+ return mPhoneNumbers;
+}
+
+void Contact::addEmail( const Email& email )
+{
+ mEmails.append( email );
+}
+
+QList<Contact::Email>& Contact::emails()
+{
+ return mEmails;
+}
+
+QString Contact::fullEmail() const
+{
+ return mFullEmail;
+}
+
+const QList<Contact::Email>& Contact::emails() const
+{
+ return mEmails;
+}
+
+void Contact::addAddress( const Contact::Address& address )
+{
+ mAddresses.append( address );
+}
+
+QList<Contact::Address>& Contact::addresses()
+{
+ return mAddresses;
+}
+
+const QList<Contact::Address>& Contact::addresses() const
+{
+ return mAddresses;
+}
+
+void Contact::setPreferredAddress( const QString& address )
+{
+ mPreferredAddress = address;
+}
+
+QString Contact::preferredAddress() const
+{
+ return mPreferredAddress;
+}
+
+bool Contact::loadNameAttribute( QDomElement& element )
+{
+ for ( QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ QDomElement e = n.toElement();
+ QString 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
+ kDebug() <<"Warning: Unhandled tag" << e.tagName();
+ } else
+ kDebug() <<"Node is not a comment or an element???";
+ }
+
+ return true;
+}
+
+void Contact::saveNameAttribute( QDomElement& element ) const
+{
+ QDomElement 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( QDomElement& element )
+{
+ PhoneNumber number;
+ for ( QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ QDomElement e = n.toElement();
+ QString 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
+ kDebug() <<"Warning: Unhandled tag" << e.tagName();
+ } else
+ kDebug() <<"Node is not a comment or an element???";
+ }
+
+ addPhoneNumber( number );
+ return true;
+}
+
+void Contact::savePhoneAttributes( QDomElement& element ) const
+{
+ QList<PhoneNumber>::ConstIterator it = mPhoneNumbers.constBegin();
+ for ( ; it != mPhoneNumbers.constEnd(); ++it ) {
+ QDomElement 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( QDomElement& element ) const
+{
+ QList<Email>::ConstIterator it = mEmails.constBegin();
+ for ( ; it != mEmails.constEnd(); ++it )
+ saveEmailAttribute( element, *it );
+}
+
+void Contact::loadCustomAttributes( QDomElement& element )
+{
+ Custom custom;
+ custom.app = element.attribute( "app" );
+ custom.name = element.attribute( "name" );
+ custom.value = element.attribute( "value" );
+ mCustomList.append( custom );
+}
+
+void Contact::saveCustomAttributes( QDomElement& element ) const
+{
+ QList<Custom>::ConstIterator it = mCustomList.constBegin();
+ for ( ; it != mCustomList.constEnd(); ++it ) {
+ Q_ASSERT( !(*it).name.isEmpty() );
+ if ( (*it).app == s_unhandledTagAppName ) {
+ writeString( element, (*it).name, (*it).value );
+ } else {
+ // Let's use attributes so that other tag-preserving-code doesn't need sub-elements
+ QDomElement 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( QDomElement& element )
+{
+ Address address;
+
+ for ( QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ QDomElement e = n.toElement();
+ QString 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
+ kDebug() <<"Warning: Unhandled tag" << e.tagName();
+ } else
+ kDebug() <<"Node is not a comment or an element???";
+ }
+
+ addAddress( address );
+ return true;
+}
+
+void Contact::saveAddressAttributes( QDomElement& element ) const
+{
+ QList<Address>::ConstIterator it = mAddresses.constBegin();
+ for ( ; it != mAddresses.constEnd(); ++it ) {
+ QDomElement e = element.ownerDocument().createElement( "address" );
+ element.appendChild( e );
+ const Address& a = *it;
+ writeString( e, "type", a.type );
+ writeString( e, "x-kde-type", QString::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 );
+ }
+}
+
+bool Contact::loadAttribute( QDomElement& element )
+{
+ const QString tagName = element.tagName();
+ switch ( tagName[0].toLatin1() ) {
+ 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;
+ }
+ 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
+ setTitle( 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;
+ }
+ 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;
+ }
+ if ( tagName == "x-title" ) {
+ setTitle( element.text() );
+ return true;
+ }
+ break;
+ case 'w':
+ if ( tagName == "web-page" ) {
+ setWebPage( element.text() );
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+ return KolabBase::loadAttribute( element );
+}
+
+bool Contact::saveAttributes( QDomElement& element ) const
+{
+ // Save the base class elements
+ KolabBase::saveAttributes( element );
+ 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", title() );
+ 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", QString::number( latitude(), 'g', DBL_DIG ) );
+ writeString( element, "longitude", QString::number( longitude(), 'g', DBL_DIG ) );
+ }
+ saveCustomAttributes( element );
+
+ return true;
+}
+
+bool Contact::loadXML( const QDomDocument& document )
+{
+ QDomElement top = document.documentElement();
+
+ if ( top.tagName() != "contact" ) {
+ qWarning( "XML error: Top tag was %s instead of the expected contact",
+ top.tagName().toAscii().data() );
+ return false;
+ }
+
+ for ( QDomNode n = top.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ QDomElement e = n.toElement();
+ if ( !loadAttribute( e ) ) {
+ // Unhandled tag - save for later storage
+ //kDebug() <<"Saving unhandled tag" << e.tagName();
+ Custom c;
+ c.app = s_unhandledTagAppName;
+ c.name = e.tagName();
+ c.value = e.text();
+ mCustomList.append( c );
+ }
+ } else
+ kDebug() <<"Node is not a comment or an element???";
+ }
+
+ return true;
+}
+
+QString Contact::saveXML() const
+{
+ QDomDocument document = domTree();
+ QDomElement element = document.createElement("contact" );
+ element.setAttribute( "version", "1.0" );
+ saveAttributes( element );
+ document.appendChild( element );
+ return document.toString();
+}
+
+static QString 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 QString& 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 QStringList phoneTypeToString( KABC::PhoneNumber::Type 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.
+ QStringList 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 home1
+ if ( ( type & KABC::PhoneNumber::Home ) && ( type & KABC::PhoneNumber::Pref ) )
+ {
+ types << "home1";
+ type = type & ~KABC::PhoneNumber::Home;
+ type = type & ~KABC::PhoneNumber::Pref;
+ }
+ // To support both "business1" and "business2", map Work+Pref to business1
+ if ( ( type & KABC::PhoneNumber::Work ) && ( type & KABC::PhoneNumber::Pref ) )
+ {
+ types << "business1";
+ type = type & ~KABC::PhoneNumber::Work;
+ type = type & ~KABC::PhoneNumber::Pref;
+ }
+
+
+ if ( type & KABC::PhoneNumber::Home )
+ types << "home2";
+ if ( type & KABC::PhoneNumber::Msg ) // Msg==messaging
+ types << "company";
+ if ( type & KABC::PhoneNumber::Work )
+ types << "business2";
+ 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 KABC::PhoneNumber::Type phoneTypeFromString( const QString& type )
+{
+ if ( type == "homefax" )
+ return KABC::PhoneNumber::Home | KABC::PhoneNumber::Fax;
+ if ( type == "businessfax" )
+ return KABC::PhoneNumber::Work | KABC::PhoneNumber::Fax;
+ if ( type == "business1" )
+ return KABC::PhoneNumber::Work | KABC::PhoneNumber::Pref;
+ if ( type == "business2" )
+ return KABC::PhoneNumber::Work;
+ if ( type == "home1" )
+ return KABC::PhoneNumber::Home | KABC::PhoneNumber::Pref;
+ if ( type == "home2" )
+ 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-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 );
+
+ 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" ) );
+ setDepartment( addressee->department());
+ setOfficeLocation( addressee->custom( "KADDRESSBOOK", "X-Office" ) );
+ setProfession( addressee->custom( "KADDRESSBOOK", "X-Profession" ) );
+ setRole( addressee->role() );
+ setTitle( 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 QString& anniversary = addressee->custom( "KADDRESSBOOK", "X-Anniversary" );
+ if ( !anniversary.isEmpty() )
+ setAnniversary( stringToDate( anniversary ) );
+
+ const QStringList 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 ( QStringList::ConstIterator it = emails.constBegin(); it != emails.constEnd(); ++it ) {
+ Email email;
+ email.displayName = fullName();
+ email.smtpAddress = *it;
+ addEmail( email );
+ }
+
+ // save formatted full email for later usage
+ mFullEmail = addressee->fullEmail();
+
+ // Now the real-world addresses
+ QString preferredAddress = "home";
+ const KABC::Address::List addresses = addressee->addresses();
+ for ( KABC::Address::List::ConstIterator it = addresses.constBegin() ; it != addresses.constEnd(); ++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.constBegin(); it != phones.constEnd(); ++it ) {
+ // Create a tag per phone type set in the bitfield
+ QStringList types = phoneTypeToString( (*it).type() );
+ for( QStringList::ConstIterator typit = types.constBegin(); typit != types.constEnd(); ++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)
+ QStringList knownCustoms;
+ for ( const char** p = s_knownCustomFields; *p; ++p )
+ knownCustoms << QString::fromLatin1( *p );
+ QStringList customs = addressee->customs();
+ for( QStringList::ConstIterator it = customs.constBegin(); it != customs.constEnd(); ++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).indexOf( '-' );
+ if ( pos == -1 ) continue;
+ QString app = (*it).left( pos );
+ if ( app == "KOLAB" ) continue;
+ QString name = (*it).mid( pos + 1 );
+ pos = name.indexOf( ':' );
+ if ( pos == -1 ) continue;
+ QString value = name.mid( pos + 1 );
+ name = name.left( pos );
+ if ( !knownCustoms.contains( name ) ) {
+ //kDebug() <<"app=" << app <<" name=" << name <<" value=" << value;
+ Custom c;
+ if ( app != "KADDRESSBOOK" ) // that's the default
+ c.app = app;
+ c.name = name;
+ c.value = value;
+ mCustomList.append( c );
+ }
+ }
+
+ QString url = KCalCore::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 );
+
+ addressee->setGivenName( givenName() );
+ addressee->setAdditionalName( middleNames() );
+ addressee->setFamilyName( lastName() );
+ addressee->setFormattedName( fullName() );
+ addressee->setPrefix( prefix() );
+ addressee->setSuffix( suffix() );
+ addressee->setOrganization( organization() );
+ addressee->setUrl( webPage() );
+ addressee->insertCustom( "KADDRESSBOOK", "X-IMAddress", imAddress() );
+ addressee->setDepartment( department() );
+ addressee->insertCustom( "KADDRESSBOOK", "X-Office", officeLocation() );
+ addressee->insertCustom( "KADDRESSBOOK", "X-Profession", profession() );
+ addressee->setRole( role() );
+ addressee->setTitle( title() );
+ 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( QDateTime( 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 ) );
+
+ QStringList emailAddresses;
+ for ( QList<Email>::ConstIterator it = mEmails.constBegin(); it != mEmails.constEnd(); ++it ) {
+ // we can't do anything with (*it).displayName
+ emailAddresses.append( (*it).smtpAddress );
+ }
+ addressee->setEmails( emailAddresses );
+
+ for ( QList<Address>::ConstIterator it = mAddresses.constBegin(); it != mAddresses.constEnd(); ++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( static_cast<KABC::Address::Type>(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 ( QList<PhoneNumber>::ConstIterator it = mPhoneNumbers.constBegin(); it != mPhoneNumbers.constEnd(); ++it ) {
+ KABC::PhoneNumber number;
+ number.setType( phoneTypeFromString( (*it).type ) );
+ number.setNumber( (*it).number );
+ addressee->insertPhoneNumber( number );
+ }
+
+ for( QList<Custom>::ConstIterator it = mCustomList.constBegin(); it != mCustomList.constEnd(); ++it ) {
+ QString app = (*it).app.isEmpty() ? QString::fromLatin1( "KADDRESSBOOK" ) : (*it).app;
+ addressee->insertCustom( app, (*it).name, (*it).value );
+ }
+ //kDebug() << addressee->customs();
+}
+
+QImage Contact::loadPictureFromAddressee( const KABC::Picture& picture )
+{
+ QImage img;
+ if ( !picture.isIntern() && !picture.url().isEmpty() ) {
+ QString tmpFile;
+ if ( KIO::NetAccess::download( picture.url(), tmpFile, 0 /*no widget known*/ ) ) {
+ img.load( tmpFile );
+ KIO::NetAccess::removeTempFile( tmpFile );
+ }
+ } else
+ img = picture.data();
+ return img;
+}
+
+QByteArray Kolab::Contact::loadSoundFromAddressee( const KABC::Sound& sound )
+{
+ QByteArray data;
+ if ( !sound.isIntern() && !sound.url().isEmpty() ) {
+ QString tmpFile;
+ if ( KIO::NetAccess::download( sound.url(), tmpFile, 0 /*no widget known*/ ) ) {
+ QFile f( tmpFile );
+ if ( f.open( QIODevice::ReadOnly ) ) {
+ data = f.readAll();
+ f.close();
+ }
+ KIO::NetAccess::removeTempFile( tmpFile );
+ }
+ } else
+ data = sound.data();
+ return data;
+}
+
+QString 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/kolabformatV2/contact.h b/kolabformatV2/contact.h
new file mode 100644
index 0000000..ba88a77
--- /dev/null
+++ b/kolabformatV2/contact.h
@@ -0,0 +1,274 @@
+/*
+ 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 Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), 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
+ Qt. 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 <qimage.h>
+
+namespace KABC {
+ class Addressee;
+ class Picture;
+ class Sound;
+}
+
+namespace Kolab {
+
+class Contact : public KolabBase {
+public:
+ struct PhoneNumber {
+ public:
+ QString type;
+ QString number;
+ };
+
+ struct Address {
+ public:
+ Address() : kdeAddressType( -1 )
+ {
+ }
+ int kdeAddressType; // KABC::Address::Type
+ QString type; // kolab-compliant address type: home, work or other
+ QString street;
+ QString pobox;
+ QString locality;
+ QString region;
+ QString postalCode;
+ QString country;
+ };
+
+ explicit Contact( const KABC::Addressee* address );
+ Contact( const QString& xml );
+ ~Contact();
+
+ void saveTo( KABC::Addressee* address );
+
+ QString type() const { return "Contact"; }
+
+ void setGivenName( const QString& name );
+ QString givenName() const;
+
+ void setMiddleNames( const QString& names );
+ QString middleNames() const;
+
+ void setLastName( const QString& name );
+ QString lastName() const;
+
+ void setFullName( const QString& name );
+ QString fullName() const;
+
+ void setInitials( const QString& initials );
+ QString initials() const;
+
+ void setPrefix( const QString& prefix );
+ QString prefix() const;
+
+ void setSuffix( const QString& suffix );
+ QString suffix() const;
+
+ void setRole( const QString& role );
+ QString role() const;
+
+ void setFreeBusyUrl( const QString& fbUrl );
+ QString freeBusyUrl() const;
+
+ void setOrganization( const QString& organization );
+ QString organization() const;
+
+ void setWebPage( const QString& url );
+ QString webPage() const;
+
+ void setIMAddress( const QString& imAddress );
+ QString imAddress() const;
+
+ void setDepartment( const QString& department );
+ QString department() const;
+
+ void setOfficeLocation( const QString& location );
+ QString officeLocation() const;
+
+ void setProfession( const QString& profession );
+ QString profession() const;
+
+ void setTitle( const QString& title );
+ QString title() const;
+
+ void setManagerName( const QString& name );
+ QString managerName() const;
+
+ void setAssistant( const QString& name );
+ QString assistant() const;
+
+ void setNickName( const QString& name );
+ QString nickName() const;
+
+ void setSpouseName( const QString& name );
+ QString spouseName() const;
+
+ void setBirthday( const QDate& date );
+ QDate birthday() const;
+
+ void setAnniversary( const QDate& date );
+ QDate anniversary() const;
+
+ void setPicture( const QImage& image) { mPicture = image; }
+ QString pictureAttachmentName() const { return mPictureAttachmentName; }
+ QImage picture() const { return mPicture; }
+
+ void setLogo( const QImage& image ) { mLogo = image; }
+ QString logoAttachmentName() const { return mLogoAttachmentName; }
+ QImage logo() const { return mLogo; }
+
+ void setSound( const QByteArray& sound ) { mSound = sound; }
+ QString soundAttachmentName() const { return mSoundAttachmentName; }
+ QByteArray sound() const { return mSound; }
+
+ void setChildren( const QString& children );
+ QString children() const;
+
+ void setGender( const QString& gender );
+ QString gender() const;
+
+ void setLanguage( const QString& language );
+ QString language() const;
+
+ void addPhoneNumber( const PhoneNumber& number );
+ QList<PhoneNumber>& phoneNumbers();
+ const QList<PhoneNumber>& phoneNumbers() const;
+
+ void addEmail( const Email& email );
+ QList<Email>& emails();
+ const QList<Email>& emails() const;
+
+ QString fullEmail() const;
+
+ void addAddress( const Address& address );
+ QList<Address>& addresses();
+ const QList<Address>& addresses() const;
+
+ // which address is preferred: home or business or other
+ void setPreferredAddress( const QString& address );
+ QString 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( QDomElement& );
+
+ // Save the attributes of this class
+ bool saveAttributes( QDomElement& ) const;
+
+ // Load this note by reading the XML file
+ bool loadXML( const QDomDocument& xml );
+
+ // Serialize this note to an XML string
+ QString saveXML() const;
+
+protected:
+ void setFields( const KABC::Addressee* );
+
+private:
+ bool loadNameAttribute( QDomElement& element );
+ void saveNameAttribute( QDomElement& element ) const;
+
+ bool loadPhoneAttribute( QDomElement& element );
+ void savePhoneAttributes( QDomElement& element ) const;
+
+ void saveEmailAttributes( QDomElement& element ) const;
+
+ bool loadAddressAttribute( QDomElement& element );
+ void saveAddressAttributes( QDomElement& element ) const;
+
+ void loadCustomAttributes( QDomElement& element );
+ void saveCustomAttributes( QDomElement& element ) const;
+
+ QImage loadPictureFromAddressee( const KABC::Picture& picture );
+
+ QByteArray loadSoundFromAddressee( const KABC::Sound& sound );
+
+ QString productID() const;
+
+ QString mGivenName;
+ QString mMiddleNames;
+ QString mLastName;
+ QString mFullName;
+ QString mInitials;
+ QString mPrefix;
+ QString mSuffix;
+ QString mRole;
+ QString mFreeBusyUrl;
+ QString mOrganization;
+ QString mWebPage;
+ QString mIMAddress;
+ QString mDepartment;
+ QString mOfficeLocation;
+ QString mProfession;
+ QString mTitle;
+ QString mManagerName;
+ QString mAssistant;
+ QString mNickName;
+ QString mSpouseName;
+ QDate mBirthday;
+ QDate mAnniversary;
+ QImage mPicture;
+ QImage mLogo;
+ QByteArray mSound;
+ QString mPictureAttachmentName;
+ QString mLogoAttachmentName;
+ QString mSoundAttachmentName;
+ QString mChildren;
+ QString mGender;
+ QString mLanguage;
+ QList<PhoneNumber> mPhoneNumbers;
+ QList<Email> mEmails;
+ QString mFullEmail;
+ QList<Address> mAddresses;
+ QString mPreferredAddress;
+ float mLatitude;
+ float mLongitude;
+ bool mHasGeo;
+ struct Custom {
+ QString app;
+ QString name;
+ QString value;
+ };
+ QList<Custom> mCustomList;
+};
+
+}
+
+#endif // KOLABCONTACT_H
diff --git a/kolabformatV2/distributionlist.cpp b/kolabformatV2/distributionlist.cpp
new file mode 100644
index 0000000..840c5a8
--- /dev/null
+++ b/kolabformatV2/distributionlist.cpp
@@ -0,0 +1,242 @@
+/*
+ This file is part of Akonadi KolabProxy.
+ Copyright (c) 2009 Kevin Krammer <kevin.krammer@gmx.at>
+
+ 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 Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), 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
+ Qt. 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 "distributionlist.h"
+
+#include <akonadi/itemfetchjob.h>
+#include <akonadi/itemfetchscope.h>
+#include <kabc/addressee.h>
+#include <kabc/contactgroup.h>
+#include <kdebug.h>
+
+using namespace Kolab;
+
+static const char* s_unhandledTagAppName = "KOLABUNHANDLED"; // no hyphens in appnames!
+
+// saving (contactgroup->xml)
+DistributionList::DistributionList( const KABC::ContactGroup* contactGroup )
+{
+ setFields( contactGroup );
+}
+
+// loading (xml->contactgroup)
+DistributionList::DistributionList( const QString& xml )
+{
+ load( xml );
+}
+
+DistributionList::~DistributionList()
+{
+}
+
+void DistributionList::setName( const QString& name )
+{
+ mName = name;
+}
+
+QString DistributionList::name() const
+{
+ return mName;
+}
+
+void Kolab::DistributionList::loadDistrListMember( const QDomElement& element )
+{
+ Member member;
+ for ( QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ QDomElement e = n.toElement();
+ QString tagName = e.tagName();
+ if ( tagName == "display-name" )
+ member.displayName = e.text();
+ else if ( tagName == "smtp-address" )
+ member.email = e.text();
+ }
+ }
+ mDistrListMembers.append( member );
+}
+
+void DistributionList::saveDistrListMembers( QDomElement& element ) const
+{
+ QList<Member>::ConstIterator it = mDistrListMembers.constBegin();
+ for( ; it != mDistrListMembers.constEnd(); ++it ) {
+ QDomElement 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 DistributionList::loadAttribute( QDomElement& element )
+{
+ const QString tagName = element.tagName();
+ switch ( tagName[0].toLatin1() ) {
+ case 'd':
+ if ( tagName == "display-name" ) {
+ setName( element.text() );
+ return true;
+ }
+ break;
+ case 'm':
+ if ( tagName == "member" ) {
+ loadDistrListMember( element );
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+ return KolabBase::loadAttribute( element );
+}
+
+bool DistributionList::saveAttributes( QDomElement& element ) const
+{
+ // Save the base class elements
+ KolabBase::saveAttributes( element );
+ writeString( element, "display-name", name() );
+ saveDistrListMembers( element );
+
+ return true;
+}
+
+bool DistributionList::loadXML( const QDomDocument& document )
+{
+ QDomElement top = document.documentElement();
+
+ if ( top.tagName() != "distribution-list" ) {
+ qWarning( "XML error: Top tag was %s instead of the expected distribution-list",
+ top.tagName().toAscii().data() );
+ return false;
+ }
+
+
+ for ( QDomNode n = top.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ QDomElement e = n.toElement();
+ if ( !loadAttribute( e ) ) {
+ // Unhandled tag - save for later storage
+ //kDebug() <<"Saving unhandled tag" << e.tagName();
+ Custom c;
+ c.app = s_unhandledTagAppName;
+ c.name = e.tagName();
+ c.value = e.text();
+ mCustomList.append( c );
+ }
+ } else
+ kDebug() <<"Node is not a comment or an element???";
+ }
+
+ return true;
+}
+
+QString DistributionList::saveXML() const
+{
+ QDomDocument document = domTree();
+ QDomElement element = document.createElement( "distribution-list" );
+ element.setAttribute( "version", "1.0" );
+ saveAttributes( element );
+ document.appendChild( element );
+ return document.toString();
+}
+
+QString DistributionList::productID() const
+{
+ // TODO should we get name/version from desktop file?
+ return QLatin1String( "Akonadi Kolab Proxy" );
+}
+
+// The saving is contactgroup -> DistributionList -> xml, this is the first part
+void DistributionList::setFields( const KABC::ContactGroup* contactGroup )
+{
+ KolabBase::setFields( contactGroup );
+
+ setName( contactGroup->name() );
+
+ // explicit contact data
+ for ( uint index = 0; index < contactGroup->dataCount(); ++index ) {
+ const KABC::ContactGroup::Data& data = contactGroup->data( index );
+
+ Member m;
+ m.displayName = data.name();
+ m.email = data.email();
+
+ mDistrListMembers.append( m );
+ }
+
+ // Hopefully all resources are available during saving, so we can look up
+ // in the addressbook to get name+email from the UID.
+ // TODO proxy should at least know the addressees it created
+ for ( uint index = 0; index < contactGroup->contactReferenceCount(); ++index ) {
+ const KABC::ContactGroup::ContactReference& reference = contactGroup->contactReference( index );
+
+ const Akonadi::Item item( reference.uid().toLongLong() );
+ Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob( item );
+ job->fetchScope().fetchFullPayload();
+ if ( !job->exec() )
+ continue;
+
+ const Akonadi::Item::List items = job->items();
+ if ( items.count() != 1 )
+ continue;
+
+ const KABC::Addressee addressee = job->items().first().payload<KABC::Addressee>();
+
+ if ( !addressee.isEmpty() ) {
+ Member m;
+ m.displayName = addressee.formattedName();
+ m.email = reference.preferredEmail();
+ if ( m.email.isEmpty() )
+ m.email = addressee.preferredEmail();
+
+ mDistrListMembers.append( m );
+ }
+ }
+}
+
+// The loading is: xml -> DistributionList -> contactgroup, this is the second part
+void DistributionList::saveTo( KABC::ContactGroup* contactGroup )
+{
+ KolabBase::saveTo( contactGroup );
+
+ contactGroup->setName( name() );
+
+ QList<Member>::ConstIterator mit = mDistrListMembers.constBegin();
+ for ( ; mit != mDistrListMembers.constEnd(); ++mit ) {
+ const KABC::ContactGroup::Data data( (*mit).displayName, (*mit).email );
+ contactGroup->append( data );
+ }
+}
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/kolabformatV2/distributionlist.h b/kolabformatV2/distributionlist.h
new file mode 100644
index 0000000..33dc61d
--- /dev/null
+++ b/kolabformatV2/distributionlist.h
@@ -0,0 +1,96 @@
+/*
+ This file is part of Akonadi KolabProxy
+ Copyright (c) 2009 <kevin.krammer@gmx.at>
+
+ 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 Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), 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
+ Qt. 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 KOLABDISTRIBUTIONLIST_H
+#define KOLABDISTRIBUTIONLIST_H
+
+#include "kolabbase.h"
+
+namespace KABC {
+ class ContactGroup;
+}
+
+namespace Kolab {
+
+class DistributionList : public KolabBase {
+public:
+ explicit DistributionList( const KABC::ContactGroup* contactGroup );
+ DistributionList( const QString& xml );
+ ~DistributionList();
+
+ void saveTo( KABC::ContactGroup* contactGroup );
+
+ QString type() const { return "DistributionList"; }
+
+ void setName( const QString& name );
+ QString name() const;
+
+ // Load the attributes of this class
+ bool loadAttribute( QDomElement& );
+
+ // Save the attributes of this class
+ bool saveAttributes( QDomElement& ) const;
+
+ // Load this note by reading the XML file
+ bool loadXML( const QDomDocument& xml );
+
+ // Serialize this note to an XML string
+ QString saveXML() const;
+
+ QString productID() const;
+
+protected:
+ void setFields( const KABC::ContactGroup* );
+
+private:
+ void loadDistrListMember( const QDomElement& element );
+ void saveDistrListMembers( QDomElement& element ) const;
+
+ QString mName;
+
+ struct Custom {
+ QString app;
+ QString name;
+ QString value;
+ };
+ QList<Custom> mCustomList;
+
+ struct Member {
+ QString displayName;
+ QString email;
+ };
+ QList<Member> mDistrListMembers;
+};
+
+}
+
+#endif // KOLABDISTRIBUTIONLIST_H
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/kolabformatV2/event.cpp b/kolabformatV2/event.cpp
new file mode 100644
index 0000000..103ced3
--- /dev/null
+++ b/kolabformatV2/event.cpp
@@ -0,0 +1,221 @@
+/*
+ This file is part of the kolab resource - the implementation of the
+ Kolab storage format. See www.kolab.org for documentation on this.
+
+ Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), 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
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "event.h"
+
+#include <kcalcore/event.h>
+#include <kdebug.h>
+
+using namespace Kolab;
+
+
+KCalCore::Event::Ptr Event::fromXml( const QDomDocument& xmlDoc, const QString& tz)
+{
+ Event event( tz );
+ event.loadXML( xmlDoc );
+ KCalCore::Event::Ptr kcalEvent( new KCalCore::Event() );
+ event.saveTo( kcalEvent );
+ return kcalEvent;
+}
+
+QString Event::eventToXML( const KCalCore::Event::Ptr &kcalEvent, const QString& tz )
+{
+ Event event( tz, kcalEvent );
+ return event.saveXML();
+}
+
+Event::Event( const QString& tz, const KCalCore::Event::Ptr &event )
+ : Incidence( tz, event ),
+ mShowTimeAs( KCalCore::Event::Opaque ), mHasEndDate( false )
+{
+ if ( event ) {
+ setFields( event );
+ }
+}
+
+Event::~Event()
+{
+}
+
+void Event::setTransparency( KCalCore::Event::Transparency transparency )
+{
+ mShowTimeAs = transparency;
+}
+
+KCalCore::Event::Transparency Event::transparency() const
+{
+ return mShowTimeAs;
+}
+
+void Event::setEndDate( const KDateTime& date )
+{
+ mEndDate = date;
+ mHasEndDate = true;
+ if ( mFloatingStatus == AllDay )
+ kDebug() <<"ERROR: Time on end date but no time on the event";
+ mFloatingStatus = HasTime;
+}
+
+void Event::setEndDate( const QDate& date )
+{
+ mEndDate = KDateTime( date );
+ mHasEndDate = true;
+ if ( mFloatingStatus == HasTime )
+ kDebug() <<"ERROR: No time on end date but time on the event";
+ mFloatingStatus = AllDay;
+}
+
+void Event::setEndDate( const QString& endDate )
+{
+ if ( endDate.length() > 10 )
+ // This is a date + time
+ setEndDate( stringToDateTime( endDate ) );
+ else
+ // This is only a date
+ setEndDate( stringToDate( endDate ) );
+}
+
+KDateTime Event::endDate() const
+{
+ return mEndDate;
+}
+
+bool Event::loadAttribute( QDomElement& element )
+{
+ // This method doesn't handle the color-label tag yet
+ QString tagName = element.tagName();
+
+ if ( tagName == "show-time-as" ) {
+ // TODO: Support tentative and outofoffice
+ if ( element.text() == "free" )
+ setTransparency( KCalCore::Event::Transparent );
+ else
+ setTransparency( KCalCore::Event::Opaque );
+ } else if ( tagName == "end-date" )
+ setEndDate( element.text() );
+ else
+ return Incidence::loadAttribute( element );
+
+ // We handled this
+ return true;
+}
+
+bool Event::saveAttributes( QDomElement& element ) const
+{
+ // Save the base class elements
+ Incidence::saveAttributes( element );
+
+ // TODO: Support tentative and outofoffice
+ if ( transparency() == KCalCore::Event::Transparent )
+ writeString( element, "show-time-as", "free" );
+ else
+ writeString( element, "show-time-as", "busy" );
+ if ( mHasEndDate ) {
+ if ( mFloatingStatus == HasTime )
+ writeString( element, "end-date", dateTimeToString( endDate() ) );
+ else
+ writeString( element, "end-date", dateToString( endDate().date() ) );
+ }
+
+ return true;
+}
+
+
+bool Event::loadXML( const QDomDocument& document )
+{
+ QDomElement top = document.documentElement();
+
+ if ( top.tagName() != "event" ) {
+ qWarning( "XML error: Top tag was %s instead of the expected event",
+ top.tagName().toAscii().data() );
+ return false;
+ }
+
+ for ( QDomNode n = top.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ QDomElement e = n.toElement();
+ loadAttribute( e );
+ } else
+ kDebug() <<"Node is not a comment or an element???";
+ }
+
+ return true;
+}
+
+QString Event::saveXML() const
+{
+ QDomDocument document = domTree();
+ QDomElement element = document.createElement( "event" );
+ element.setAttribute( "version", "1.0" );
+ saveAttributes( element );
+ document.appendChild( element );
+ return document.toString();
+}
+
+void Event::setFields( const KCalCore::Event::Ptr &event )
+{
+ Incidence::setFields( event );
+
+ // note: if hasEndDate() is false and hasDuration() is true
+ // dtEnd() returns start+duration
+ if ( event->hasEndDate() || event->hasDuration() ) {
+ if ( event->allDay() ) {
+ // This is an all-day event. Don't timezone move this one
+ mFloatingStatus = AllDay;
+ setEndDate( event->dtEnd().date() );
+ } else {
+ mFloatingStatus = HasTime;
+ setEndDate( localToUTC( event->dtEnd() ) );
+ }
+ } else {
+ mHasEndDate = false;
+ }
+ setTransparency( event->transparency() );
+}
+
+void Event::saveTo( const KCalCore::Event::Ptr &event )
+{
+ Incidence::saveTo( event );
+
+ event->setHasEndDate( mHasEndDate );
+ if ( mHasEndDate ) {
+ if ( mFloatingStatus == AllDay )
+ // This is an all-day event. Don't timezone move this one
+ event->setDtEnd( endDate() );
+ else
+ event->setDtEnd( utcToLocal( endDate() ) );
+ }
+ event->setTransparency( transparency() );
+}
diff --git a/kolabformatV2/event.h b/kolabformatV2/event.h
new file mode 100644
index 0000000..acc327b
--- /dev/null
+++ b/kolabformatV2/event.h
@@ -0,0 +1,101 @@
+/*
+ This file is part of the kolab resource - the implementation of the
+ Kolab storage format. See www.kolab.org for documentation on this.
+
+ Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), 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
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef KOLAB_EVENT_H
+#define KOLAB_EVENT_H
+
+#include "incidence.h"
+
+#include <kcalcore/event.h>
+
+class QDomElement;
+
+
+namespace Kolab {
+
+/**
+ * This class represents an event, and knows how to load/save it
+ * from/to XML, and from/to a KCalCore::Event.
+ * The instances of this class are temporary, only used to convert
+ * one to the other.
+ */
+class Event : public Incidence {
+public:
+ /// Use this to parse an xml string to a event entry
+ /// The caller is responsible for deleting the returned event
+ static KCalCore::Event::Ptr fromXml( const QDomDocument& xmlDoc, const QString& tz);
+
+ /// Use this to get an xml string describing this event entry
+ static QString eventToXML( const KCalCore::Event::Ptr &, const QString& tz );
+
+ /// Create a event object and
+ explicit Event( const QString& tz,
+ const KCalCore::Event::Ptr &event = KCalCore::Event::Ptr() );
+ virtual ~Event();
+
+ void saveTo( const KCalCore::Event::Ptr &event );
+
+ virtual QString type() const { return "Event"; }
+
+ virtual void setTransparency( KCalCore::Event::Transparency transparency );
+ virtual KCalCore::Event::Transparency transparency() const;
+
+ virtual void setEndDate( const KDateTime& date );
+ virtual void setEndDate( const QDate& date );
+ virtual void setEndDate( const QString& date );
+ virtual KDateTime endDate() const;
+
+ // Load the attributes of this class
+ virtual bool loadAttribute( QDomElement& );
+
+ // Save the attributes of this class
+ virtual bool saveAttributes( QDomElement& ) const;
+
+ // Load this event by reading the XML file
+ virtual bool loadXML( const QDomDocument& xml );
+
+ // Serialize this event to an XML string
+ virtual QString saveXML() const;
+
+protected:
+ // Read all known fields from this ical incidence
+ void setFields( const KCalCore::Event::Ptr & );
+
+ KCalCore::Event::Transparency mShowTimeAs;
+ KDateTime mEndDate;
+ bool mHasEndDate;
+};
+
+}
+
+#endif // KOLAB_EVENT_H
diff --git a/kolabformatV2/incidence.cpp b/kolabformatV2/incidence.cpp
new file mode 100644
index 0000000..9f4323f
--- /dev/null
+++ b/kolabformatV2/incidence.cpp
@@ -0,0 +1,976 @@
+/*
+ This file is part of the kolab resource - the implementation of the
+ Kolab storage format. See www.kolab.org for documentation on this.
+
+ Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), 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
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "incidence.h"
+#include "akonadi-version.h"
+
+#include <QList>
+
+#include <kcalcore/journal.h>
+#include <kdebug.h>
+#include <kurl.h>
+#include <kio/netaccess.h>
+
+#include <QBitArray>
+
+using namespace Kolab;
+
+
+Incidence::Incidence( const QString& tz, const KCalCore::Incidence::Ptr &incidence )
+ : KolabBase( tz ), mFloatingStatus( Unset ), mHasAlarm( false )
+{
+ Q_UNUSED( incidence );
+}
+
+Incidence::~Incidence()
+{
+}
+
+void Incidence::setSummary( const QString& summary )
+{
+ mSummary = summary;
+}
+
+QString Incidence::summary() const
+{
+ return mSummary;
+}
+
+void Incidence::setLocation( const QString& location )
+{
+ mLocation = location;
+}
+
+QString Incidence::location() const
+{
+ return mLocation;
+}
+
+void Incidence::setOrganizer( const Email& organizer )
+{
+ mOrganizer = organizer;
+}
+
+KolabBase::Email Incidence::organizer() const
+{
+ return mOrganizer;
+}
+
+void Incidence::setStartDate( const KDateTime& startDate )
+{
+ mStartDate = startDate;
+ if ( mFloatingStatus == AllDay )
+ kDebug() <<"ERROR: Time on start date but no time on the event";
+ mFloatingStatus = HasTime;
+}
+
+void Incidence::setStartDate( const QDate& startDate )
+{
+ mStartDate = KDateTime( startDate );
+ if ( mFloatingStatus == HasTime )
+ kDebug() <<"ERROR: No time on start date but time on the event";
+ mFloatingStatus = AllDay;
+}
+
+void Incidence::setStartDate( const QString& startDate )
+{
+ if ( startDate.length() > 10 )
+ // This is a date + time
+ setStartDate( stringToDateTime( startDate ) );
+ else
+ // This is only a date
+ setStartDate( stringToDate( startDate ) );
+}
+
+KDateTime Incidence::startDate() const
+{
+ return mStartDate;
+}
+
+void Incidence::setAlarm( float alarm )
+{
+ mAlarm = alarm;
+ mHasAlarm = true;
+}
+
+float Incidence::alarm() const
+{
+ return mAlarm;
+}
+
+Incidence::Recurrence Incidence::recurrence() const
+{
+ return mRecurrence;
+}
+
+void Incidence::addAttendee( const Attendee& attendee )
+{
+ mAttendees.append( attendee );
+}
+
+QList<Incidence::Attendee>& Incidence::attendees()
+{
+ return mAttendees;
+}
+
+const QList<Incidence::Attendee>& Incidence::attendees() const
+{
+ return mAttendees;
+}
+
+void Incidence::setInternalUID( const QString& iuid )
+{
+ mInternalUID = iuid;
+}
+
+QString Incidence::internalUID() const
+{
+ return mInternalUID;
+}
+
+bool Incidence::loadAttendeeAttribute( QDomElement& element,
+ Attendee& attendee )
+{
+ for ( QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ QDomElement e = n.toElement();
+ QString tagName = e.tagName();
+
+ if ( tagName == "display-name" )
+ attendee.displayName = e.text();
+ else if ( tagName == "smtp-address" )
+ attendee.smtpAddress = e.text();
+ else if ( tagName == "status" )
+ attendee.status = e.text();
+ else if ( tagName == "request-response" )
+ // This sets reqResp to false, if the text is "false". Otherwise it
+ // sets it to true. This means the default setting is true.
+ attendee.requestResponse = ( e.text().toLower() != "false" );
+ else if ( tagName == "invitation-sent" )
+ // Like above, only this defaults to false
+ attendee.invitationSent = ( e.text().toLower() != "true" );
+ else if ( tagName == "role" )
+ attendee.role = e.text();
+ else if ( tagName == "delegated-to" )
+ attendee.delegate = e.text();
+ else if ( tagName == "delegated-from" )
+ attendee.delegator = e.text();
+ else
+ // TODO: Unhandled tag - save for later storage
+ kDebug() <<"Warning: Unhandled tag" << e.tagName();
+ } else
+ kDebug() <<"Node is not a comment or an element???";
+ }
+
+ return true;
+}
+
+void Incidence::saveAttendeeAttribute( QDomElement& element,
+ const Attendee& attendee ) const
+{
+ QDomElement e = element.ownerDocument().createElement( "attendee" );
+ element.appendChild( e );
+ writeString( e, "display-name", attendee.displayName );
+ writeString( e, "smtp-address", attendee.smtpAddress );
+ writeString( e, "status", attendee.status );
+ writeString( e, "request-response",
+ ( attendee.requestResponse ? "true" : "false" ) );
+ writeString( e, "invitation-sent",
+ ( attendee.invitationSent ? "true" : "false" ) );
+ writeString( e, "role", attendee.role );
+ writeString( e, "delegated-to", attendee.delegate );
+ writeString( e, "delegated-from", attendee.delegator );
+}
+
+void Incidence::saveAttendees( QDomElement& element ) const
+{
+ foreach ( const Attendee& attendee, mAttendees )
+ saveAttendeeAttribute( element, attendee );
+}
+
+void Incidence::saveAttachments( QDomElement& element ) const
+{
+ foreach ( KCalCore::Attachment::Ptr a, mAttachments ) {
+ if ( a->isUri() ) {
+ writeString( element, "link-attachment", a->uri() );
+ } else if ( a->isBinary() ) {
+ writeString( element, "inline-attachment", a->label() );
+ }
+ }
+}
+
+void Incidence::saveAlarms( QDomElement& element ) const
+{
+ if ( mAlarms.isEmpty() ) return;
+
+ QDomElement list = element.ownerDocument().createElement( "advanced-alarms" );
+ element.appendChild( list );
+ foreach ( KCalCore::Alarm::Ptr a, mAlarms ) {
+ QDomElement e = list.ownerDocument().createElement( "alarm" );
+ list.appendChild( e );
+
+ writeString( e, "enabled", a->enabled() ? "1" : "0" );
+ if ( a->hasStartOffset() ) {
+ writeString( e, "start-offset", QString::number( a->startOffset().asSeconds()/60 ) );
+ }
+ if ( a->hasEndOffset() ) {
+ writeString( e, "end-offset", QString::number( a->endOffset().asSeconds()/60 ) );
+ }
+ if ( a->repeatCount() ) {
+ writeString( e, "repeat-count", QString::number( a->repeatCount() ) );
+ writeString( e, "repeat-interval", QString::number( a->snoozeTime().asSeconds() ) );
+ }
+
+ switch ( a->type() ) {
+ case KCalCore::Alarm::Invalid:
+ break;
+ case KCalCore::Alarm::Display:
+ e.setAttribute( "type", "display" );
+ writeString( e, "text", a->text() );
+ break;
+ case KCalCore::Alarm::Procedure:
+ e.setAttribute( "type", "procedure" );
+ writeString( e, "program", a->programFile() );
+ writeString( e, "arguments", a->programArguments() );
+ break;
+ case KCalCore::Alarm::Email:
+ {
+ e.setAttribute( "type", "email" );
+ QDomElement addresses = e.ownerDocument().createElement( "addresses" );
+ e.appendChild( addresses );
+ foreach ( const KCalCore::Person::Ptr &person, a->mailAddresses() ) {
+ writeString( addresses, "address", person->fullName() );
+ }
+ writeString( e, "subject", a->mailSubject() );
+ writeString( e, "mail-text", a->mailText() );
+ QDomElement attachments = e.ownerDocument().createElement( "attachments" );
+ e.appendChild( attachments );
+ foreach ( const QString &attachment, a->mailAttachments() ) {
+ writeString( attachments, "attachment", attachment );
+ }
+ break;
+ }
+ case KCalCore::Alarm::Audio:
+ e.setAttribute( "type", "audio" );
+ writeString( e, "file", a->audioFile() );
+ break;
+ default:
+ kWarning() << "Unhandled alarm type:" << a->type();
+ break;
+ }
+ }
+}
+
+void Incidence::saveRecurrence( QDomElement& element ) const
+{
+ QDomElement e = element.ownerDocument().createElement( "recurrence" );
+ element.appendChild( e );
+ e.setAttribute( "cycle", mRecurrence.cycle );
+ if ( !mRecurrence.type.isEmpty() )
+ e.setAttribute( "type", mRecurrence.type );
+ writeString( e, "interval", QString::number( mRecurrence.interval ) );
+ foreach ( const QString& recurrence, mRecurrence.days ) {
+ writeString( e, "day", recurrence );
+ }
+ if ( !mRecurrence.dayNumber.isEmpty() )
+ writeString( e, "daynumber", mRecurrence.dayNumber );
+ if ( !mRecurrence.month.isEmpty() )
+ writeString( e, "month", mRecurrence.month );
+ if ( !mRecurrence.rangeType.isEmpty() ) {
+ QDomElement range = element.ownerDocument().createElement( "range" );
+ e.appendChild( range );
+ range.setAttribute( "type", mRecurrence.rangeType );
+ QDomText t = element.ownerDocument().createTextNode( mRecurrence.range );
+ range.appendChild( t );
+ }
+ foreach ( const QDate& date, mRecurrence.exclusions ) {
+ writeString( e, "exclusion", dateToString( date ) );
+ }
+}
+
+void Incidence::loadRecurrence( const QDomElement& element )
+{
+ mRecurrence.interval = 0;
+ mRecurrence.cycle = element.attribute( "cycle" );
+ mRecurrence.type = element.attribute( "type" );
+ for ( QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ QDomElement e = n.toElement();
+ QString tagName = e.tagName();
+ if ( tagName == "interval" ) {
+ //kolab/issue4229, sometimes the interval value can be empty
+ if ( e.text().isEmpty() || e.text().toInt() <= 0 ) {
+ mRecurrence.interval = 1;
+ } else {
+ mRecurrence.interval = e.text().toInt();
+ }
+ }
+ else if ( tagName == "day" ) // can be present multiple times
+ mRecurrence.days.append( e.text() );
+ else if ( tagName == "daynumber" )
+ mRecurrence.dayNumber = e.text();
+ else if ( tagName == "month" )
+ mRecurrence.month = e.text();
+ else if ( tagName == "range" ) {
+ mRecurrence.rangeType = e.attribute( "type" );
+ mRecurrence.range = e.text();
+ } else if ( tagName == "exclusion" ) {
+ mRecurrence.exclusions.append( stringToDate( e.text() ) );
+ } else
+ // TODO: Unhandled tag - save for later storage
+ kDebug() <<"Warning: Unhandled tag" << e.tagName();
+ }
+ }
+}
+
+static void loadAddressesHelper( const QDomElement& element, const KCalCore::Alarm::Ptr &a )
+{
+ for ( QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ QDomElement e = n.toElement();
+ QString tagName = e.tagName();
+
+ if ( tagName == "address" ) {
+ a->addMailAddress( KCalCore::Person::fromFullName( e.text() ) );
+ } else {
+ kWarning() << "Unhandled tag" << tagName;
+ }
+ }
+ }
+}
+
+static void loadAttachmentsHelper( const QDomElement& element, const KCalCore::Alarm::Ptr &a )
+{
+ for ( QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ QDomElement e = n.toElement();
+ QString tagName = e.tagName();
+
+ if ( tagName == "attachment" ) {
+ a->addMailAttachment( e.text() );
+ } else {
+ kWarning() << "Unhandled tag" << tagName;
+ }
+ }
+ }
+}
+
+static void loadAlarmHelper( const QDomElement& element, const KCalCore::Alarm::Ptr &a )
+{
+ for ( QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ QDomElement e = n.toElement();
+ QString tagName = e.tagName();
+
+ if ( tagName == "start-offset" ) {
+ a->setStartOffset( e.text().toInt()*60 );
+ } else if ( tagName == "end-offset" ) {
+ a->setEndOffset( e.text().toInt()*60 );
+ } else if ( tagName == "repeat-count" ) {
+ a->setRepeatCount( e.text().toInt() );
+ } else if ( tagName == "repeat-interval" ) {
+ a->setSnoozeTime( e.text().toInt() );
+ } else if ( tagName == "text" ) {
+ a->setText( e.text() );
+ } else if ( tagName == "program" ) {
+ a->setProgramFile( e.text() );
+ } else if ( tagName == "arguments" ) {
+ a->setProgramArguments( e.text() );
+ } else if ( tagName == "addresses" ) {
+ loadAddressesHelper( e, a );
+ } else if ( tagName == "subject" ) {
+ a->setMailSubject( e.text() );
+ } else if ( tagName == "mail-text" ) {
+ a->setMailText( e.text() );
+ } else if ( tagName == "attachments" ) {
+ loadAttachmentsHelper( e, a );
+ } else if ( tagName == "file" ) {
+ a->setAudioFile( e.text() );
+ } else if ( tagName == "enabled" ) {
+ a->setEnabled( e.text().toInt() != 0 );
+ } else {
+ kWarning() << "Unhandled tag" << tagName;
+ }
+ }
+ }
+}
+
+void Incidence::loadAlarms( const QDomElement& element )
+{
+ for ( QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ QDomElement e = n.toElement();
+ QString tagName = e.tagName();
+
+ if ( tagName == "alarm" ) {
+ KCalCore::Alarm::Ptr a = KCalCore::Alarm::Ptr( new KCalCore::Alarm( 0 ) );
+ a->setEnabled( true ); // default to enabled, unless some XML attribute says otherwise.
+ QString type = e.attribute( "type" );
+ if ( type == "display" ) {
+ a->setType( KCalCore::Alarm::Display );
+ } else if ( type == "procedure" ) {
+ a->setType( KCalCore::Alarm::Procedure );
+ } else if ( type == "email" ) {
+ a->setType( KCalCore::Alarm::Email );
+ } else if ( type == "audio" ) {
+ a->setType( KCalCore::Alarm::Audio );
+ } else {
+ kWarning() << "Unhandled alarm type:" << type;
+ }
+
+ loadAlarmHelper( e, a );
+ mAlarms << a;
+ } else {
+ kWarning() << "Unhandled tag" << tagName;
+ }
+ }
+ }
+}
+
+bool Incidence::loadAttribute( QDomElement& element )
+{
+ QString tagName = element.tagName();
+
+ if ( tagName == "summary" )
+ setSummary( element.text() );
+ else if ( tagName == "location" )
+ setLocation( element.text() );
+ else if ( tagName == "organizer" ) {
+ Email email;
+ if ( loadEmailAttribute( element, email ) ) {
+ setOrganizer( email );
+ return true;
+ } else
+ return false;
+ } else if ( tagName == "start-date" )
+ setStartDate( element.text() );
+ else if ( tagName == "recurrence" )
+ loadRecurrence( element );
+ else if ( tagName == "attendee" ) {
+ Attendee attendee;
+ if ( loadAttendeeAttribute( element, attendee ) ) {
+ addAttendee( attendee );
+ return true;
+ } else
+ return false;
+ } else if ( tagName == "link-attachment" ) {
+ mAttachments.push_back( KCalCore::Attachment::Ptr( new KCalCore::Attachment( element.text() ) ) );
+ } else if ( tagName == "alarm" )
+ // Alarms should be minutes before. Libkcal uses event time + alarm time
+ setAlarm( - element.text().toInt() );
+ else if ( tagName == "advanced-alarms" )
+ loadAlarms( element );
+ else if ( tagName == "x-kde-internaluid" )
+ setInternalUID( element.text() );
+ else if ( tagName == "x-custom" ) {
+ loadCustomAttributes( element );
+ } else if ( tagName == "inline-attachment" ) {
+ // we handle that separately later on, so no need to create a KolabUnhandled entry for it
+ } else {
+ bool ok = KolabBase::loadAttribute( element );
+ if ( !ok ) {
+ // Unhandled tag - save for later storage
+ kDebug() <<"Saving unhandled tag" << element.tagName();
+ Custom c;
+ c.key = QByteArray( "X-KDE-KolabUnhandled-" ) + element.tagName().toLatin1();
+ c.value = element.text();
+ mCustomList.append( c );
+ }
+ }
+ // We handled this
+ return true;
+}
+
+bool Incidence::saveAttributes( QDomElement& element ) const
+{
+ // Save the base class elements
+ KolabBase::saveAttributes( element );
+
+ if ( mFloatingStatus == HasTime )
+ writeString( element, "start-date", dateTimeToString( startDate() ) );
+ else
+ writeString( element, "start-date", dateToString( startDate().date() ) );
+ writeString( element, "summary", summary() );
+ writeString( element, "location", location() );
+ saveEmailAttribute( element, organizer(), "organizer" );
+ if ( !mRecurrence.cycle.isEmpty() )
+ saveRecurrence( element );
+ saveAttendees( element );
+ saveAttachments( element );
+ if ( mHasAlarm ) {
+ // Alarms should be minutes before. Libkcal uses event time + alarm time
+ int alarmTime = qRound( -alarm() );
+ writeString( element, "alarm", QString::number( alarmTime ) );
+ }
+ saveAlarms( element );
+ writeString( element, "x-kde-internaluid", internalUID() );
+ saveCustomAttributes( element );
+ return true;
+}
+
+void Incidence::saveCustomAttributes( QDomElement& element ) const
+{
+ foreach ( const Custom& custom, mCustomList ) {
+ QString key( custom.key );
+ Q_ASSERT( !key.isEmpty() );
+ if ( key.startsWith( QLatin1String( "X-KDE-KolabUnhandled-" ) ) ) {
+ key = key.mid( strlen( "X-KDE-KolabUnhandled-" ) );
+ writeString( element, key, custom.value );
+ } else {
+ // Let's use attributes so that other tag-preserving-code doesn't need sub-elements
+ QDomElement e = element.ownerDocument().createElement( "x-custom" );
+ element.appendChild( e );
+ e.setAttribute( "key", key );
+ e.setAttribute( "value", custom.value );
+ }
+ }
+}
+
+void Incidence::loadCustomAttributes( QDomElement& element )
+{
+ Custom custom;
+ custom.key = element.attribute( "key" ).toLatin1();
+ custom.value = element.attribute( "value" );
+ mCustomList.append( custom );
+}
+
+static KCalCore::Attendee::PartStat attendeeStringToStatus( const QString& s )
+{
+ if ( s == "none" )
+ return KCalCore::Attendee::NeedsAction;
+ if ( s == "tentative" )
+ return KCalCore::Attendee::Tentative;
+ if ( s == "declined" )
+ return KCalCore::Attendee::Declined;
+ if ( s == "delegated" )
+ return KCalCore::Attendee::Delegated;
+
+ // Default:
+ return KCalCore::Attendee::Accepted;
+}
+
+static QString attendeeStatusToString( KCalCore::Attendee::PartStat status )
+{
+ switch( status ) {
+ case KCalCore::Attendee::NeedsAction:
+ return "none";
+ case KCalCore::Attendee::Accepted:
+ return "accepted";
+ case KCalCore::Attendee::Declined:
+ return "declined";
+ case KCalCore::Attendee::Tentative:
+ return "tentative";
+ case KCalCore::Attendee::Delegated:
+ return "delegated";
+ case KCalCore::Attendee::Completed:
+ case KCalCore::Attendee::InProcess:
+ // These don't have any meaning in the Kolab format, so just use:
+ return "accepted";
+ default:
+ // Default for the case that there are more added later:
+ return "accepted";
+ }
+}
+
+static KCalCore::Attendee::Role attendeeStringToRole( const QString& s )
+{
+ if ( s == "optional" )
+ return KCalCore::Attendee::OptParticipant;
+ if ( s == "resource" )
+ return KCalCore::Attendee::NonParticipant;
+ return KCalCore::Attendee::ReqParticipant;
+}
+
+static QString attendeeRoleToString( KCalCore::Attendee::Role role )
+{
+ switch( role ) {
+ case KCalCore::Attendee::ReqParticipant:
+ return "required";
+ case KCalCore::Attendee::OptParticipant:
+ return "optional";
+ case KCalCore::Attendee::Chair:
+ // We don't have the notion of chair, so use
+ return "required";
+ case KCalCore::Attendee::NonParticipant:
+ // In Kolab, a non-participant is a resource
+ return "resource";
+ }
+
+ // Default for the case that there are more added later:
+ return "required";
+}
+
+static const char *s_weekDayName[] =
+{
+ "monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"
+};
+
+static const char *s_monthName[] =
+{
+ "january", "february", "march", "april", "may", "june", "july",
+ "august", "september", "october", "november", "december"
+};
+
+void Incidence::setRecurrence( KCalCore::Recurrence* recur )
+{
+ mRecurrence.interval = recur->frequency();
+ switch ( recur->recurrenceType() ) {
+ case KCalCore::Recurrence::rMinutely: // Not handled by the kolab XML
+ mRecurrence.cycle = "minutely";
+ break;
+ case KCalCore::Recurrence::rHourly: // Not handled by the kolab XML
+ mRecurrence.cycle = "hourly";
+ break;
+ case KCalCore::Recurrence::rDaily:
+ mRecurrence.cycle = "daily";
+ break;
+ case KCalCore::Recurrence::rWeekly: // every X weeks
+ mRecurrence.cycle = "weekly";
+ {
+ QBitArray arr = recur->days();
+ for ( uint idx = 0 ; idx < 7 ; ++idx )
+ if ( arr.testBit( idx ) )
+ mRecurrence.days.append( s_weekDayName[idx] );
+ }
+ break;
+ case KCalCore::Recurrence::rMonthlyPos: {
+ mRecurrence.cycle = "monthly";
+ mRecurrence.type = "weekday";
+ QList<KCalCore::RecurrenceRule::WDayPos> monthPositions = recur->monthPositions();
+ if ( !monthPositions.isEmpty() ) {
+ KCalCore::RecurrenceRule::WDayPos monthPos = monthPositions.first();
+ // TODO: Handle multiple days in the same week
+ mRecurrence.dayNumber = QString::number( monthPos.pos() );
+ mRecurrence.days.append( s_weekDayName[ monthPos.day()-1 ] );
+ // Not (properly) handled(?): monthPos.negative (nth days before end of month)
+ }
+ break;
+ }
+ case KCalCore::Recurrence::rMonthlyDay: {
+ mRecurrence.cycle = "monthly";
+ mRecurrence.type = "daynumber";
+ QList<int> monthDays = recur->monthDays();
+ // ####### Kolab XML limitation: only the first month day is used
+ if ( !monthDays.isEmpty() )
+ mRecurrence.dayNumber = QString::number( monthDays.first() );
+ break;
+ }
+ case KCalCore::Recurrence::rYearlyMonth: // (day n of Month Y)
+ {
+ mRecurrence.cycle = "yearly";
+ mRecurrence.type = "monthday";
+ QList<int> rmd = recur->yearDates();
+ int day = !rmd.isEmpty() ? rmd.first() : recur->startDate().day();
+ mRecurrence.dayNumber = QString::number( day );
+ QList<int> months = recur->yearMonths();
+ if ( !months.isEmpty() )
+ mRecurrence.month = s_monthName[ months.first() - 1 ]; // #### Kolab XML limitation: only one month specified
+ break;
+ }
+ case KCalCore::Recurrence::rYearlyDay: // YearlyDay (day N of the year). Not supported by Outlook
+ mRecurrence.cycle = "yearly";
+ mRecurrence.type = "yearday";
+ mRecurrence.dayNumber = QString::number( recur->yearDays().first() );
+ break;
+ case KCalCore::Recurrence::rYearlyPos: // (weekday X of week N of month Y)
+ mRecurrence.cycle = "yearly";
+ mRecurrence.type = "weekday";
+ QList<int> months = recur->yearMonths();
+ if ( !months.isEmpty() )
+ mRecurrence.month = s_monthName[ months.first() - 1 ]; // #### Kolab XML limitation: only one month specified
+ QList<KCalCore::RecurrenceRule::WDayPos> monthPositions = recur->yearPositions();
+ if ( !monthPositions.isEmpty() ) {
+ KCalCore::RecurrenceRule::WDayPos monthPos = monthPositions.first();
+ // TODO: Handle multiple days in the same week
+ mRecurrence.dayNumber = QString::number( monthPos.pos() );
+ mRecurrence.days.append( s_weekDayName[ monthPos.day()-1 ] );
+
+ //mRecurrence.dayNumber = QString::number( *recur->yearNums().getFirst() );
+ // Not handled: monthPos.negative (nth days before end of month)
+ }
+ break;
+ }
+ int howMany = recur->duration();
+ if ( howMany > 0 ) {
+ mRecurrence.rangeType = "number";
+ mRecurrence.range = QString::number( howMany );
+ } else if ( howMany == 0 ) {
+ mRecurrence.rangeType = "date";
+ mRecurrence.range = dateToString( recur->endDate() );
+ } else {
+ mRecurrence.rangeType = "none";
+ }
+}
+
+void Incidence::setFields( const KCalCore::Incidence::Ptr &incidence )
+{
+ KolabBase::setFields( incidence );
+
+ if ( incidence->allDay() ) {
+ // This is a all-day event. Don't timezone move this one
+ mFloatingStatus = AllDay;
+ setStartDate( incidence->dtStart().date() );
+ } else {
+ mFloatingStatus = HasTime;
+ setStartDate( localToUTC( incidence->dtStart() ) );
+ }
+
+ setSummary( incidence->summary() );
+ setLocation( incidence->location() );
+
+ // Alarm
+ mHasAlarm = false; // Will be set to true, if we actually have one
+ if ( incidence->hasEnabledAlarms() ) {
+ const KCalCore::Alarm::List& alarms = incidence->alarms();
+ if ( !alarms.isEmpty() ) {
+ const KCalCore::Alarm::Ptr alarm = alarms.first();
+ if ( alarm->hasStartOffset() ) {
+ int dur = alarm->startOffset().asSeconds();
+ setAlarm( (float)dur / 60.0 );
+ }
+ }
+ }
+
+ Email org( incidence->organizer()->name(), incidence->organizer()->email() );
+ setOrganizer( org );
+
+ // Attendees:
+ KCalCore::Attendee::List attendees = incidence->attendees();
+ foreach ( KCalCore::Attendee::Ptr kcalAttendee, attendees ) {
+ Attendee attendee;
+
+ attendee.displayName = kcalAttendee->name();
+ attendee.smtpAddress = kcalAttendee->email();
+ attendee.status = attendeeStatusToString( kcalAttendee->status() );
+ attendee.requestResponse = kcalAttendee->RSVP();
+ // TODO: KCalCore::Attendee::mFlag is not accessible
+ // attendee.invitationSent = kcalAttendee->mFlag;
+ // DF: Hmm? mFlag is set to true and never used at all.... Did you mean another field?
+ attendee.role = attendeeRoleToString( kcalAttendee->role() );
+ attendee.delegate = kcalAttendee->delegate();
+ attendee.delegator = kcalAttendee->delegator();
+
+ addAttendee( attendee );
+ }
+
+ mAttachments.clear();
+
+ // Attachments
+ KCalCore::Attachment::List attachments = incidence->attachments();
+ foreach ( KCalCore::Attachment::Ptr a, attachments ) {
+ mAttachments.push_back( a );
+ }
+
+ mAlarms.clear();
+
+ // Alarms
+ KCalCore::Alarm::List alarms = incidence->alarms();
+ foreach ( KCalCore::Alarm::Ptr a, alarms ) {
+ mAlarms.push_back( a );
+ }
+
+ if ( incidence->recurs() ) {
+ setRecurrence( incidence->recurrence() );
+ mRecurrence.exclusions = incidence->recurrence()->exDates();
+ }
+
+ // Handle the scheduling ID
+ if ( incidence->schedulingID() == incidence->uid() ) {
+ // There is no scheduling ID
+ setInternalUID( QString::null ); //krazy:exclude=nullstrassign for old broken gcc
+ } else {
+ // We've internally been using a different uid, so save that as the
+ // temporary (internal) uid and restore the original uid, the one that
+ // is used in the folder and the outside world
+ setUid( incidence->schedulingID() );
+ setInternalUID( incidence->uid() );
+ }
+
+ // Unhandled tags and other custom properties (see libkcal/customproperties.h)
+ const QMap<QByteArray, QString> map = incidence->customProperties();
+ QMap<QByteArray, QString>::ConstIterator cit = map.begin();
+ for ( ; cit != map.end() ; ++cit ) {
+ Custom c;
+ c.key = cit.key();
+ c.value = cit.value();
+ mCustomList.append( c );
+ }
+}
+
+static QBitArray daysListToBitArray( const QStringList& days )
+{
+ QBitArray arr( 7 );
+ arr.fill( false );
+ foreach ( const QString& day, days ) {
+ for ( uint i = 0; i < 7 ; ++i )
+ if ( day == s_weekDayName[i] )
+ arr.setBit( i, true );
+ }
+ return arr;
+}
+
+
+void Incidence::saveTo( const KCalCore::Incidence::Ptr &incidence )
+{
+ KolabBase::saveTo( incidence );
+
+ if ( mFloatingStatus == AllDay ) {
+ // This is an all-day event. Don't timezone move this one
+ incidence->setDtStart( startDate() );
+ incidence->setAllDay( true );
+ } else {
+ incidence->setDtStart( utcToLocal( startDate() ) );
+ incidence->setAllDay( false );
+ }
+
+ incidence->setSummary( summary() );
+ incidence->setLocation( location() );
+
+ if ( mHasAlarm && mAlarms.isEmpty() ) {
+ KCalCore::Alarm::Ptr alarm = incidence->newAlarm();
+ alarm->setStartOffset( qRound( mAlarm * 60.0 ) );
+ alarm->setEnabled( true );
+ alarm->setType( KCalCore::Alarm::Display );
+ } else if ( !mAlarms.isEmpty() ) {
+ foreach ( KCalCore::Alarm::Ptr a, mAlarms ) {
+ a->setParent( incidence.data() );
+ incidence->addAlarm( a );
+ }
+ }
+
+ if ( organizer().displayName.isEmpty() )
+ incidence->setOrganizer( organizer().smtpAddress );
+ else
+ incidence->setOrganizer( organizer().displayName + '<'
+ + organizer().smtpAddress + '>' );
+
+ incidence->clearAttendees();
+ foreach ( const Attendee& attendee, mAttendees ) {
+ KCalCore::Attendee::PartStat status = attendeeStringToStatus( attendee.status );
+ KCalCore::Attendee::Role role = attendeeStringToRole( attendee.role );
+ KCalCore::Attendee::Ptr a( new KCalCore::Attendee( attendee.displayName,
+ attendee.smtpAddress,
+ attendee.requestResponse,
+ status, role ) );
+ a->setDelegate( attendee.delegate );
+ a->setDelegator( attendee.delegator );
+ incidence->addAttendee( a );
+ }
+
+ incidence->clearAttachments();
+ foreach ( KCalCore::Attachment::Ptr a, mAttachments ) {
+ // TODO should we copy?
+ incidence->addAttachment( a );
+ }
+
+ if ( !mRecurrence.cycle.isEmpty() ) {
+ KCalCore::Recurrence* recur = incidence->recurrence(); // yeah, this creates it
+ // done below recur->setFrequency( mRecurrence.interval );
+ if ( mRecurrence.cycle == "minutely" ) {
+ recur->setMinutely( mRecurrence.interval );
+ } else if ( mRecurrence.cycle == "hourly" ) {
+ recur->setHourly( mRecurrence.interval );
+ } else if ( mRecurrence.cycle == "daily" ) {
+ recur->setDaily( mRecurrence.interval );
+ } else if ( mRecurrence.cycle == "weekly" ) {
+ QBitArray rDays = daysListToBitArray( mRecurrence.days );
+ recur->setWeekly( mRecurrence.interval, rDays );
+ } else if ( mRecurrence.cycle == "monthly" ) {
+ recur->setMonthly( mRecurrence.interval );
+ if ( mRecurrence.type == "weekday" ) {
+ recur->addMonthlyPos( mRecurrence.dayNumber.toInt(), daysListToBitArray( mRecurrence.days ) );
+ } else if ( mRecurrence.type == "daynumber" ) {
+ recur->addMonthlyDate( mRecurrence.dayNumber.toInt() );
+ } else kWarning() <<"Unhandled monthly recurrence type" << mRecurrence.type;
+ } else if ( mRecurrence.cycle == "yearly" ) {
+ recur->setYearly( mRecurrence.interval );
+ if ( mRecurrence.type == "monthday" ) {
+ recur->addYearlyDate( mRecurrence.dayNumber.toInt() );
+ for ( int i = 0; i < 12; ++i )
+ if ( s_monthName[ i ] == mRecurrence.month )
+ recur->addYearlyMonth( i+1 );
+ } else if ( mRecurrence.type == "yearday" ) {
+ recur->addYearlyDay( mRecurrence.dayNumber.toInt() );
+ } else if ( mRecurrence.type == "weekday" ) {
+ for ( int i = 0; i < 12; ++i )
+ if ( s_monthName[ i ] == mRecurrence.month )
+ recur->addYearlyMonth( i+1 );
+ recur->addYearlyPos( mRecurrence.dayNumber.toInt(), daysListToBitArray( mRecurrence.days ) );
+ } else kWarning() <<"Unhandled yearly recurrence type" << mRecurrence.type;
+ } else kWarning() <<"Unhandled recurrence cycle" << mRecurrence.cycle;
+
+ if ( mRecurrence.rangeType == "number" ) {
+ recur->setDuration( mRecurrence.range.toInt() );
+ } else if ( mRecurrence.rangeType == "date" ) {
+ recur->setEndDate( stringToDate( mRecurrence.range ) );
+ } // "none" is default since tje set*ly methods set infinite recurrence
+
+ incidence->recurrence()->setExDates( mRecurrence.exclusions );
+
+ }
+ /* If we've stored a uid to be used internally instead of the real one
+ * (to deal with duplicates of events in different folders) before, then
+ * restore it, so it does not change. Keep the original uid around for
+ * scheduling purposes. */
+ if ( !internalUID().isEmpty() ) {
+ incidence->setUid( internalUID() );
+ incidence->setSchedulingID( uid() );
+ }
+
+ foreach ( const Custom& custom, mCustomList ) {
+ incidence->setNonKDECustomProperty( custom.key, custom.value );
+ }
+
+}
+
+QString Incidence::productID() const
+{
+ return QString( "Akonadi %1, Kolab resource" ).arg( AKONADI_VERSION );
+}
+
+// Unhandled KCalCore::Incidence fields:
+// revision, status (unused), priority (done in tasks), attendee.uid,
+// mComments, mReadOnly
+
diff --git a/kolabformatV2/incidence.h b/kolabformatV2/incidence.h
new file mode 100644
index 0000000..2b96776
--- /dev/null
+++ b/kolabformatV2/incidence.h
@@ -0,0 +1,166 @@
+/*
+ This file is part of the kolab resource - the implementation of the
+ Kolab storage format. See www.kolab.org for documentation on this.
+
+ Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), 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
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef KOLAB_INCIDENCE_H
+#define KOLAB_INCIDENCE_H
+
+#include <kcalcore/incidence.h>
+
+#include "kolabbase.h"
+
+class QDomElement;
+
+namespace Kolab {
+
+/**
+ * This abstract class represents an incidence which has the shared
+ * fields, of events and tasks and knows how to load/save these
+ * from/to XML, and from/to a KCalCore::Incidence.
+ */
+class Incidence : public KolabBase {
+public:
+ struct Recurrence {
+ QString cycle;
+ QString type;
+ int interval;
+ QStringList days; // list of days-of-the-week
+ QString dayNumber;
+ QString month;
+ QString rangeType;
+ QString range; // date or number or nothing
+ QList<QDate> exclusions;
+ };
+
+ struct Attendee : Email {
+ Attendee() : requestResponse( true ), invitationSent( false ) {}
+ QString status;
+ bool requestResponse;
+ bool invitationSent;
+ QString role;
+ QString delegate;
+ QString delegator;
+ };
+
+ explicit Incidence( const QString& tz, const KCalCore::Incidence::Ptr &incidence = KCalCore::Incidence::Ptr() );
+
+public:
+ virtual ~Incidence();
+
+ void saveTo( const KCalCore::Incidence::Ptr &incidence );
+
+ virtual void setSummary( const QString& summary );
+ virtual QString summary() const;
+
+ virtual void setLocation( const QString& location );
+ virtual QString location() const;
+
+ virtual void setOrganizer( const Email& organizer );
+ virtual Email organizer() const;
+
+ virtual void setStartDate( const KDateTime& startDate );
+ virtual void setStartDate( const QDate& startDate );
+ virtual void setStartDate( const QString& startDate );
+ virtual KDateTime startDate() const;
+
+ virtual void setAlarm( float alarm );
+ virtual float alarm() const;
+
+ virtual void setRecurrence( KCalCore::Recurrence* recur );
+ virtual Recurrence recurrence() const;
+
+ virtual void addAttendee( const Attendee& attendee );
+ QList<Attendee>& attendees();
+ const QList<Attendee>& attendees() const;
+
+ virtual QString type() const { return "Incidence"; }
+ /**
+ * The internal uid is used as the uid inside KOrganizer whenever
+ * two or more events with the same uid appear, which KOrganizer
+ * can't handle. To avoid keep that interal uid from changing all the
+ * time, it is persisted in the XML between a save and the next load.
+ */
+ void setInternalUID( const QString& iuid );
+ QString internalUID() const;
+
+ // Load the attributes of this class
+ virtual bool loadAttribute( QDomElement& );
+
+ // Save the attributes of this class
+ virtual bool saveAttributes( QDomElement& ) const;
+
+protected:
+ enum FloatingStatus { Unset, AllDay, HasTime };
+
+ // Read all known fields from this ical incidence
+ void setFields( const KCalCore::Incidence::Ptr & );
+
+ bool loadAttendeeAttribute( QDomElement&, Attendee& );
+ void saveAttendeeAttribute( QDomElement& element,
+ const Attendee& attendee ) const;
+ void saveAttendees( QDomElement& element ) const;
+ void saveAttachments( QDomElement& element ) const;
+
+ void loadAlarms( const QDomElement& element );
+ void saveAlarms( QDomElement& element ) const;
+
+ void loadRecurrence( const QDomElement& element );
+ void saveRecurrence( QDomElement& element ) const;
+ void saveCustomAttributes( QDomElement& element ) const;
+ void loadCustomAttributes( QDomElement& element );
+
+ QString productID() const;
+
+ QString mSummary;
+ QString mLocation;
+ Email mOrganizer;
+ KDateTime mStartDate;
+ FloatingStatus mFloatingStatus;
+ float mAlarm;
+ bool mHasAlarm;
+ Recurrence mRecurrence;
+ QList<Attendee> mAttendees;
+ QList<KCalCore::Alarm::Ptr> mAlarms;
+ QList<KCalCore::Attachment::Ptr> mAttachments;
+ QString mInternalUID;
+
+ struct Custom {
+ QByteArray key;
+ QString value;
+ };
+ QList<Custom> mCustomList;
+
+};
+
+}
+
+#endif // KOLAB_INCIDENCE_H
diff --git a/kolabformatV2/journal.cpp b/kolabformatV2/journal.cpp
new file mode 100644
index 0000000..c9c2c1b
--- /dev/null
+++ b/kolabformatV2/journal.cpp
@@ -0,0 +1,184 @@
+/*
+ This file is part of the kolab resource - the implementation of the
+ Kolab storage format. See www.kolab.org for documentation on this.
+
+ Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), 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
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "journal.h"
+#include "akonadi-version.h"
+
+#include <kdebug.h>
+
+using namespace Kolab;
+
+
+KCalCore::Journal::Ptr Journal::fromXml( const QDomDocument& xmlDoc, const QString& tz )
+{
+ Journal journal( tz );
+ journal.loadXML( xmlDoc );
+ KCalCore::Journal::Ptr kcalJournal( new KCalCore::Journal() );
+ journal.saveTo( kcalJournal );
+ return kcalJournal;
+}
+
+QString Journal::journalToXML( const KCalCore::Journal::Ptr &kcalJournal, const QString& tz )
+{
+ Journal journal( tz, kcalJournal );
+ return journal.saveXML();
+}
+
+Journal::Journal( const QString& tz, const KCalCore::Journal::Ptr &journal )
+ : KolabBase( tz )
+{
+ if ( journal ) {
+ setFields( journal );
+ }
+}
+
+Journal::~Journal()
+{
+}
+
+void Journal::setSummary( const QString& summary )
+{
+ mSummary = summary;
+}
+
+QString Journal::summary() const
+{
+ return mSummary;
+}
+
+void Journal::setStartDate( const KDateTime& startDate )
+{
+ mStartDate = startDate;
+}
+
+KDateTime Journal::startDate() const
+{
+ return mStartDate;
+}
+
+void Journal::setEndDate( const KDateTime& endDate )
+{
+ mEndDate = endDate;
+}
+
+KDateTime Journal::endDate() const
+{
+ return mEndDate;
+}
+
+bool Journal::loadAttribute( QDomElement& element )
+{
+ QString tagName = element.tagName();
+
+ if ( tagName == "summary" )
+ setSummary( element.text() );
+ else if ( tagName == "start-date" )
+ setStartDate( stringToDateTime( element.text() ) );
+ else
+ // Not handled here
+ return KolabBase::loadAttribute( element );
+
+ // We handled this
+ return true;
+}
+
+bool Journal::saveAttributes( QDomElement& element ) const
+{
+ // Save the base class elements
+ KolabBase::saveAttributes( element );
+
+ writeString( element, "summary", summary() );
+ writeString( element, "start-date", dateTimeToString( startDate() ) );
+
+ return true;
+}
+
+
+bool Journal::loadXML( const QDomDocument& document )
+{
+ QDomElement top = document.documentElement();
+
+ if ( top.tagName() != "journal" ) {
+ qWarning( "XML error: Top tag was %s instead of the expected Journal",
+ top.tagName().toAscii().data() );
+ return false;
+ }
+
+ for ( QDomNode n = top.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ QDomElement e = n.toElement();
+ if ( !loadAttribute( e ) ) {
+ // Unhandled tag - save for later storage
+ //qDebug( "Unhandled tag: %s", e.toCString().data() );
+ }
+ } else
+ qDebug( "Node is not a comment or an element???" );
+ }
+
+ return true;
+}
+
+QString Journal::saveXML() const
+{
+ QDomDocument document = domTree();
+ QDomElement element = document.createElement( "journal" );
+ element.setAttribute( "version", "1.0" );
+ saveAttributes( element );
+ document.appendChild( element );
+ return document.toString();
+}
+
+void Journal::saveTo( const KCalCore::Journal::Ptr &journal )
+{
+ KolabBase::saveTo( journal );
+
+ journal->setSummary( summary() );
+ journal->setDtStart( utcToLocal( startDate() ) );
+}
+
+void Journal::setFields( const KCalCore::Journal::Ptr &journal )
+{
+ // Set baseclass fields
+ KolabBase::setFields( journal );
+
+ // Set our own fields
+ setSummary( journal->summary() );
+ setStartDate( localToUTC( journal->dtStart() ) );
+}
+
+QString Journal::productID() const
+{
+ return QString( "Akonadi " ) + AKONADI_VERSION + ", Kolab resource";
+}
diff --git a/kolabformatV2/journal.h b/kolabformatV2/journal.h
new file mode 100644
index 0000000..a049c86
--- /dev/null
+++ b/kolabformatV2/journal.h
@@ -0,0 +1,101 @@
+/*
+ This file is part of the kolab resource - the implementation of the
+ Kolab storage format. See www.kolab.org for documentation on this.
+
+ Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), 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
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef KOLAB_JOURNAL_H
+#define KOLAB_JOURNAL_H
+
+#include <kcalcore/journal.h>
+
+#include <kolabbase.h>
+
+class QDomElement;
+
+namespace Kolab {
+
+/**
+ * This class represents a journal entry, and knows how to load/save it
+ * from/to XML, and from/to a KCalCore::Journal.
+ * The instances of this class are temporary, only used to convert
+ * one to the other.
+ */
+class Journal : public KolabBase {
+public:
+ /// Use this to parse an xml string to a journal entry
+ /// The caller is responsible for deleting the returned journal
+ static KCalCore::Journal::Ptr fromXml( const QDomDocument& xmlDoc, const QString& tz );
+
+ /// Use this to get an xml string describing this journal entry
+ static QString journalToXML( const KCalCore::Journal::Ptr &, const QString& tz );
+
+ explicit Journal( const QString& tz, const KCalCore::Journal::Ptr &journal = KCalCore::Journal::Ptr() );
+ virtual ~Journal();
+
+ virtual QString type() const { return "Journal"; }
+
+ void saveTo( const KCalCore::Journal::Ptr &journal );
+
+ virtual void setSummary( const QString& summary );
+ virtual QString summary() const;
+
+ virtual void setStartDate( const KDateTime& startDate );
+ virtual KDateTime startDate() const;
+
+ virtual void setEndDate( const KDateTime& endDate );
+ virtual KDateTime endDate() const;
+
+ // Load the attributes of this class
+ virtual bool loadAttribute( QDomElement& );
+
+ // Save the attributes of this class
+ virtual bool saveAttributes( QDomElement& ) const;
+
+ // Load this journal by reading the XML file
+ virtual bool loadXML( const QDomDocument& xml );
+
+ // Serialize this journal to an XML string
+ virtual QString saveXML() const;
+
+protected:
+ // Read all known fields from this ical journal
+ void setFields( const KCalCore::Journal::Ptr & );
+
+ QString productID() const;
+
+ QString mSummary;
+ KDateTime mStartDate;
+ KDateTime mEndDate;
+};
+
+}
+
+#endif // KOLAB_JOURNAL_H
diff --git a/kolabformatV2/kolabbase.cpp b/kolabformatV2/kolabbase.cpp
new file mode 100644
index 0000000..4315f3e
--- /dev/null
+++ b/kolabformatV2/kolabbase.cpp
@@ -0,0 +1,500 @@
+/*
+ This file is part of the kolab resource - the implementation of the
+ Kolab storage format. See www.kolab.org for documentation on this.
+
+ Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), 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
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "kolabbase.h"
+
+#include <kabc/addressee.h>
+#include <kabc/contactgroup.h>
+#include <kcalcore/incidence.h>
+#include <kcalcore/journal.h>
+#include <ksystemtimezone.h>
+#include <kdebug.h>
+
+using namespace Kolab;
+
+KolabBase::KolabBase( const QString& tz )
+ : mCreationDate( QDateTime::currentDateTime() ),
+ mLastModified( KDateTime::currentUtcDateTime() ),
+ mSensitivity( Public ),
+ mTimeZone( KSystemTimeZones::zone( tz ) ),
+ mHasPilotSyncId( false ), mHasPilotSyncStatus( false )
+{
+}
+
+KolabBase::~KolabBase()
+{
+}
+
+void KolabBase::setFields( const KCalCore::Incidence::Ptr &incidence )
+{
+ // So far unhandled KCalCore::IncidenceBase fields:
+ // mPilotID, mSyncStatus, mFloats
+
+ setUid( incidence->uid() );
+ setBody( incidence->description() );
+ setCategories( incidence->categoriesStr() );
+ setCreationDate( localToUTC( incidence->created() ) );
+ setLastModified( incidence->lastModified() );
+ setSensitivity( static_cast<Sensitivity>( incidence->secrecy() ) );
+ // TODO: Attachments
+}
+
+void KolabBase::saveTo( const KCalCore::Incidence::Ptr &incidence ) const
+{
+ incidence->setUid( uid() );
+ incidence->setDescription( body() );
+ incidence->setCategories( categories() );
+ incidence->setCreated( utcToLocal( creationDate() ) );
+ incidence->setLastModified( lastModified() );
+ switch( sensitivity() ) {
+ case 1:
+ incidence->setSecrecy( KCalCore::Incidence::SecrecyPrivate );
+ break;
+ case 2:
+ incidence->setSecrecy( KCalCore::Incidence::SecrecyConfidential );
+ break;
+ default:
+ incidence->setSecrecy( KCalCore::Incidence::SecrecyPublic );
+ break;
+ }
+
+ // TODO: Attachments
+}
+
+void KolabBase::setFields( const KABC::Addressee* addressee )
+{
+ // An addressee does not have a creation date, so somehow we should
+ // make one, if this is a new entry
+
+ setUid( addressee->uid() );
+ setBody( addressee->note() );
+ setCategories( addressee->categories().join( "," ) );
+
+ // Set creation-time and last-modification-time
+ const QString creationString = addressee->custom( "KOLAB", "CreationDate" );
+ kDebug() <<"Creation time string:" << creationString;
+ KDateTime creationDate;
+ if ( creationString.isEmpty() ) {
+ creationDate = KDateTime::currentDateTime(KDateTime::Spec( mTimeZone ) );
+ kDebug() <<"Creation date set to current time";
+ }
+ else {
+ creationDate = stringToDateTime( creationString );
+ kDebug() <<"Creation date loaded";
+ }
+ KDateTime modified = KDateTime( addressee->revision(), mTimeZone );
+ if ( !modified.isValid() )
+ modified = KDateTime::currentUtcDateTime();
+ setLastModified( modified );
+ if ( modified < creationDate ) {
+ // It's not possible that the modification date is earlier than creation
+ creationDate = modified;
+ kDebug() <<"Creation date set to modification date";
+ }
+ setCreationDate( creationDate );
+ const QString newCreationDate = dateTimeToString( creationDate );
+ if ( creationString != newCreationDate ) {
+ // We modified the creation date, so store it for future reference
+ const_cast<KABC::Addressee*>( addressee )
+ ->insertCustom( "KOLAB", "CreationDate", newCreationDate );
+ kDebug() <<"Creation date modified. New one:" << newCreationDate;
+ }
+
+ switch( addressee->secrecy().type() ) {
+ case KABC::Secrecy::Private:
+ setSensitivity( Private );
+ break;
+ case KABC::Secrecy::Confidential:
+ setSensitivity( Confidential );
+ break;
+ default:
+ setSensitivity( Public );
+ }
+
+ // TODO: Attachments
+}
+
+void KolabBase::saveTo( KABC::Addressee* addressee ) const
+{
+ addressee->setUid( uid() );
+ addressee->setNote( body() );
+ addressee->setCategories( categories().split( ',', QString::SkipEmptyParts ) );
+ addressee->setRevision( lastModified().toZone( mTimeZone ).dateTime() );
+ addressee->insertCustom( "KOLAB", "CreationDate",
+ dateTimeToString( creationDate() ) );
+
+ switch( sensitivity() ) {
+ case Private:
+ addressee->setSecrecy( KABC::Secrecy( KABC::Secrecy::Private ) );
+ break;
+ case Confidential:
+ addressee->setSecrecy( KABC::Secrecy( KABC::Secrecy::Confidential ) );
+ break;
+ default:
+ addressee->setSecrecy( KABC::Secrecy( KABC::Secrecy::Public ) );
+ break;
+ }
+ // TODO: Attachments
+}
+
+void KolabBase::setFields( const KABC::ContactGroup* contactGroup )
+{
+ // A contactgroup does not have a creation date, so somehow we should
+ // make one, if this is a new entry
+
+ setUid( contactGroup->id() );
+
+ // Set creation-time and last-modification-time
+ KDateTime creationDate = KDateTime::currentDateTime( KDateTime::Spec( mTimeZone ) );
+ kDebug() <<"Creation date set to current time";
+
+ KDateTime modified = KDateTime::currentUtcDateTime();
+ setLastModified( modified );
+ if ( modified < creationDate ) {
+ // It's not possible that the modification date is earlier than creation
+ creationDate = modified;
+ kDebug() <<"Creation date set to modification date";
+ }
+ setCreationDate( creationDate );
+}
+
+void KolabBase::saveTo( KABC::ContactGroup* contactGroup ) const
+{
+ contactGroup->setId( uid() );
+}
+
+void KolabBase::setUid( const QString& uid )
+{
+ mUid = uid;
+}
+
+QString KolabBase::uid() const
+{
+ return mUid;
+}
+
+void KolabBase::setBody( const QString& body )
+{
+ mBody = body;
+}
+
+QString KolabBase::body() const
+{
+ return mBody;
+}
+
+void KolabBase::setCategories( const QString& categories )
+{
+ mCategories = categories;
+}
+
+QString KolabBase::categories() const
+{
+ return mCategories;
+}
+
+void KolabBase::setCreationDate( const KDateTime& date )
+{
+ mCreationDate = date;
+}
+
+KDateTime KolabBase::creationDate() const
+{
+ return mCreationDate;
+}
+
+void KolabBase::setLastModified( const KDateTime& date )
+{
+ mLastModified = date;
+}
+
+KDateTime KolabBase::lastModified() const
+{
+ return mLastModified;
+}
+
+void KolabBase::setSensitivity( Sensitivity sensitivity )
+{
+ mSensitivity = sensitivity;
+}
+
+KolabBase::Sensitivity KolabBase::sensitivity() const
+{
+ return mSensitivity;
+}
+
+void KolabBase::setPilotSyncId( unsigned long id )
+{
+ mHasPilotSyncId = true;
+ mPilotSyncId = id;
+}
+
+bool KolabBase::hasPilotSyncId() const
+{
+ return mHasPilotSyncId;
+}
+
+unsigned long KolabBase::pilotSyncId() const
+{
+ return mPilotSyncId;
+}
+
+void KolabBase::setPilotSyncStatus( int status )
+{
+ mHasPilotSyncStatus = true;
+ mPilotSyncStatus = status;
+}
+
+bool KolabBase::hasPilotSyncStatus() const
+{
+ return mHasPilotSyncStatus;
+}
+
+int KolabBase::pilotSyncStatus() const
+{
+ return mPilotSyncStatus;
+}
+
+bool KolabBase::loadEmailAttribute( QDomElement& element, Email& email )
+{
+ for ( QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ QDomElement e = n.toElement();
+ const QString tagName = e.tagName();
+
+ if ( tagName == "display-name" )
+ email.displayName = e.text();
+ else if ( tagName == "smtp-address" )
+ email.smtpAddress = e.text();
+ else
+ // TODO: Unhandled tag - save for later storage
+ kDebug() <<"Warning: Unhandled tag" << e.tagName();
+ } else
+ kDebug() <<"Node is not a comment or an element???";
+ }
+
+ return true;
+}
+
+void KolabBase::saveEmailAttribute( QDomElement& element, const Email& email,
+ const QString& tagName ) const
+{
+ QDomElement e = element.ownerDocument().createElement( tagName );
+ element.appendChild( e );
+ writeString( e, "display-name", email.displayName );
+ writeString( e, "smtp-address", email.smtpAddress );
+}
+
+bool KolabBase::loadAttribute( QDomElement& element )
+{
+ const QString tagName = element.tagName();
+ switch ( tagName[0].toLatin1() ) {
+ case 'u':
+ if ( tagName == "uid" ) {
+ setUid( element.text() );
+ return true;
+ }
+ break;
+ case 'b':
+ if ( tagName == "body" ) {
+ setBody( element.text() );
+ return true;
+ }
+ break;
+ case 'c':
+ if ( tagName == "categories" ) {
+ setCategories( element.text() );
+ return true;
+ }
+ if ( tagName == "creation-date" ) {
+ setCreationDate( stringToDateTime( element.text() ) );
+ return true;
+ }
+ break;
+ case 'l':
+ if ( tagName == "last-modification-date" ) {
+ setLastModified( stringToDateTime( element.text() ) );
+ return true;
+ }
+ break;
+ case 's':
+ if ( tagName == "sensitivity" ) {
+ setSensitivity( stringToSensitivity( element.text() ) );
+ return true;
+ }
+ break;
+ case 'p':
+ if ( tagName == "product-id" )
+ return true; // ignore this field
+ if ( tagName == "pilot-sync-id" ) {
+ setPilotSyncId( element.text().toULong() );
+ return true;
+ }
+ if ( tagName == "pilot-sync-status" ) {
+ setPilotSyncStatus( element.text().toInt() );
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
+bool KolabBase::saveAttributes( QDomElement& element ) const
+{
+ writeString( element, "product-id", productID() );
+ writeString( element, "uid", uid() );
+ writeString( element, "body", body() );
+ writeString( element, "categories", categories() );
+ writeString( element, "creation-date", dateTimeToString( creationDate().toUtc() ) );
+ writeString( element, "last-modification-date", dateTimeToString( lastModified().toUtc() ) );
+ writeString( element, "sensitivity", sensitivityToString( sensitivity() ) );
+ if ( hasPilotSyncId() )
+ writeString( element, "pilot-sync-id", QString::number( pilotSyncId() ) );
+ if ( hasPilotSyncStatus() )
+ writeString( element, "pilot-sync-status", QString::number( pilotSyncStatus() ) );
+ return true;
+}
+
+bool KolabBase::load( const QString& xml )
+{
+ const QDomDocument document = loadDocument( xml );
+ if ( document.isNull() )
+ return false;
+ // XML file loaded into tree. Now parse it
+ return loadXML( document );
+}
+
+QDomDocument KolabBase::loadDocument( const QString& xmlData )
+{
+ QString errorMsg;
+ int errorLine, errorColumn;
+ QDomDocument document;
+ bool ok = document.setContent( xmlData, &errorMsg, &errorLine, &errorColumn );
+
+ if ( !ok ) {
+ qWarning( "Error loading document: %s, line %d, column %d", qPrintable( errorMsg ), errorLine, errorColumn );
+ return QDomDocument();
+ }
+
+ return document;
+}
+
+QDomDocument KolabBase::domTree()
+{
+ QDomDocument document;
+
+ QString p = "version=\"1.0\" encoding=\"UTF-8\"";
+ document.appendChild(document.createProcessingInstruction( "xml", p ) );
+
+ return document;
+}
+
+
+QString KolabBase::dateTimeToString( const KDateTime& time )
+{
+ return time.toString( KDateTime::ISODate );
+}
+
+QString KolabBase::dateToString( const QDate& date )
+{
+ return date.toString( Qt::ISODate );
+}
+
+KDateTime KolabBase::stringToDateTime( const QString& _date )
+{
+ const QString date( _date );
+ return KDateTime::fromString( date, KDateTime::ISODate );
+}
+
+QDate KolabBase::stringToDate( const QString& date )
+{
+ return QDate::fromString( date, Qt::ISODate );
+}
+
+QString KolabBase::sensitivityToString( Sensitivity s )
+{
+ switch( s ) {
+ case Private: return "private";
+ case Confidential: return "confidential";
+ case Public: return "public";
+ }
+
+ return "What what what???";
+}
+
+KolabBase::Sensitivity KolabBase::stringToSensitivity( const QString& s )
+{
+ if ( s == "private" )
+ return Private;
+ if ( s == "confidential" )
+ return Confidential;
+ return Public;
+}
+
+QString KolabBase::colorToString( const QColor& color )
+{
+ // Color is in the format "#RRGGBB"
+ return color.name();
+}
+
+QColor KolabBase::stringToColor( const QString& s )
+{
+ return QColor( s );
+}
+
+void KolabBase::writeString( QDomElement& element, const QString& tag,
+ const QString& tagString )
+{
+ if ( !tagString.isEmpty() ) {
+ QDomElement e = element.ownerDocument().createElement( tag );
+ QDomText t = element.ownerDocument().createTextNode( tagString );
+ e.appendChild( t );
+ element.appendChild( e );
+ }
+}
+
+KDateTime KolabBase::localToUTC( const KDateTime& time ) const
+{
+ return time.toUtc();
+}
+
+KDateTime KolabBase::utcToLocal( const KDateTime& time ) const
+{
+ KDateTime dt = time;
+ dt.setTimeSpec( KDateTime::UTC );
+ return dt;
+}
diff --git a/kolabformatV2/kolabbase.h b/kolabformatV2/kolabbase.h
new file mode 100644
index 0000000..5044bc3
--- /dev/null
+++ b/kolabformatV2/kolabbase.h
@@ -0,0 +1,183 @@
+/*
+ This file is part of the kolab resource - the implementation of the
+ Kolab storage format. See www.kolab.org for documentation on this.
+
+ Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), 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
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef KOLABBASE_H
+#define KOLABBASE_H
+
+
+#include <kcalcore/incidence.h>
+
+#include <KDateTime>
+#include <KTimeZone>
+
+#include <QColor>
+#include <qdom.h>
+
+namespace KABC {
+ class Addressee;
+ class ContactGroup;
+}
+
+namespace Kolab {
+
+class KolabBase {
+public:
+ struct Email {
+ public:
+ Email( const QString& name = QString(),
+ const QString& email = QString() )
+ : displayName( name ), smtpAddress( email )
+ {
+ }
+
+ QString displayName;
+ QString smtpAddress;
+ };
+
+ enum Sensitivity { Public = 0, Private = 1, Confidential = 2 };
+
+ explicit KolabBase( const QString& time_zone = QString() );
+ virtual ~KolabBase();
+
+ // Return a string identifying this type
+ virtual QString type() const = 0;
+
+ virtual void setUid( const QString& uid );
+ virtual QString uid() const;
+
+ virtual void setBody( const QString& body );
+ virtual QString body() const;
+
+ virtual void setCategories( const QString& categories );
+ virtual QString categories() const;
+
+ virtual void setCreationDate( const KDateTime& date );
+ virtual KDateTime creationDate() const;
+
+ virtual void setLastModified( const KDateTime& date );
+ virtual KDateTime lastModified() const;
+
+ virtual void setSensitivity( Sensitivity sensitivity );
+ virtual Sensitivity sensitivity() const;
+
+ virtual void setPilotSyncId( unsigned long id );
+ virtual bool hasPilotSyncId() const;
+ virtual unsigned long pilotSyncId() const;
+
+ virtual void setPilotSyncStatus( int status );
+ virtual bool hasPilotSyncStatus() const;
+ virtual int pilotSyncStatus() const;
+
+ // String - Date conversion methods
+ static QString dateTimeToString( const KDateTime& time );
+ static QString dateToString( const QDate& date );
+ static KDateTime stringToDateTime( const QString& time );
+ static QDate stringToDate( const QString& date );
+
+ // String - Sensitivity conversion methods
+ static QString sensitivityToString( Sensitivity );
+ static Sensitivity stringToSensitivity( const QString& );
+
+ // String - Color conversion methods
+ static QString colorToString( const QColor& );
+ static QColor stringToColor( const QString& );
+
+ // Load this object by reading the XML file
+ bool load( const QString& xml );
+ static QDomDocument loadDocument( const QString& xmlData );
+
+ // Load this QDomDocument
+ virtual bool loadXML( const QDomDocument& xml ) = 0;
+
+ // Serialize this object to an XML string
+ virtual QString saveXML() const = 0;
+
+protected:
+ /// Read all known fields from this ical incidence
+ void setFields( const KCalCore::Incidence::Ptr & );
+
+ /// Save all known fields into this ical incidence
+ void saveTo( const KCalCore::Incidence::Ptr & ) const;
+
+ /// Read all known fields from this contact
+ void setFields( const KABC::Addressee* );
+
+ /// Save all known fields into this contact
+ void saveTo( KABC::Addressee* ) const;
+
+ /// Read all known fields from this contact group
+ void setFields( const KABC::ContactGroup* );
+
+ /// Save all known fields into this contact groupd
+ void saveTo( KABC::ContactGroup* ) const;
+
+ // This just makes the initial dom tree with version and doctype
+ static QDomDocument domTree();
+
+ bool loadEmailAttribute( QDomElement& element, Email& email );
+
+ void saveEmailAttribute( QDomElement& element, const Email& email,
+ const QString& tagName = "email" ) const;
+
+ // Load the attributes of this class
+ virtual bool loadAttribute( QDomElement& );
+
+ // Save the attributes of this class
+ virtual bool saveAttributes( QDomElement& ) const;
+
+ // Return the product ID
+ virtual QString productID() const = 0;
+
+ // Write a string tag
+ static void writeString( QDomElement&, const QString&, const QString& );
+
+ KDateTime localToUTC( const KDateTime& time ) const;
+ KDateTime utcToLocal( const KDateTime& time ) const;
+
+ QString mUid;
+ QString mBody;
+ QString mCategories;
+ KDateTime mCreationDate;
+ KDateTime mLastModified;
+ Sensitivity mSensitivity;
+ KTimeZone mTimeZone;
+
+ // KPilot synchronization stuff
+ bool mHasPilotSyncId, mHasPilotSyncStatus;
+ unsigned long mPilotSyncId;
+ int mPilotSyncStatus;
+};
+
+}
+
+#endif // KOLABBASE_H
diff --git a/kolabformatV2/note.cpp b/kolabformatV2/note.cpp
new file mode 100644
index 0000000..65afebe
--- /dev/null
+++ b/kolabformatV2/note.cpp
@@ -0,0 +1,230 @@
+/*
+ This file is part of the kolab resource - the implementation of the
+ Kolab storage format. See www.kolab.org for documentation on this.
+
+ Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), 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
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "note.h"
+#include "akonadi-version.h"
+
+#include <kcalcore/journal.h>
+#include <kdebug.h>
+
+using namespace Kolab;
+
+
+KCalCore::Journal::Ptr Note::xmlToJournal( const QString& xml )
+{
+ Note note;
+ note.load( xml );
+ KCalCore::Journal::Ptr journal( new KCalCore::Journal() );
+ note.saveTo( journal );
+ return journal;
+}
+
+QString Note::journalToXML( const KCalCore::Journal::Ptr &journal )
+{
+ Note note( journal );
+ return note.saveXML();
+}
+
+Note::Note( const KCalCore::Journal::Ptr &journal ) : mRichText( false )
+{
+ if ( journal )
+ setFields( journal );
+}
+
+Note::~Note()
+{
+}
+
+void Note::setSummary( const QString& summary )
+{
+ mSummary = summary;
+}
+
+QString Note::summary() const
+{
+ return mSummary;
+}
+
+void Note::setBackgroundColor( const QColor& bgColor )
+{
+ mBackgroundColor = bgColor;
+}
+
+QColor Note::backgroundColor() const
+{
+ return mBackgroundColor;
+}
+
+void Note::setForegroundColor( const QColor& fgColor )
+{
+ mForegroundColor = fgColor;
+}
+
+QColor Note::foregroundColor() const
+{
+ return mForegroundColor;
+}
+
+void Note::setRichText( bool richText )
+{
+ mRichText = richText;
+}
+
+bool Note::richText() const
+{
+ return mRichText;
+}
+
+bool Note::loadAttribute( QDomElement& element )
+{
+ QString tagName = element.tagName();
+ if ( tagName == "summary" )
+ setSummary( element.text() );
+ else if ( tagName == "foreground-color" )
+ setForegroundColor( stringToColor( element.text() ) );
+ else if ( tagName == "background-color" )
+ setBackgroundColor( stringToColor( element.text() ) );
+ else if ( tagName == "knotes-richtext" )
+ mRichText = ( element.text() == "true" );
+ else
+ return KolabBase::loadAttribute( element );
+
+ // We handled this
+ return true;
+}
+
+bool Note::saveAttributes( QDomElement& element ) const
+{
+ // Save the base class elements
+ KolabBase::saveAttributes( element );
+
+ // Save the elements
+#if 0
+ QDomComment c = element.ownerDocument().createComment( "Note specific attributes" );
+ element.appendChild( c );
+#endif
+
+ writeString( element, "summary", summary() );
+ if ( foregroundColor().isValid() )
+ writeString( element, "foreground-color", colorToString( foregroundColor() ) );
+ if ( backgroundColor().isValid() )
+ writeString( element, "background-color", colorToString( backgroundColor() ) );
+ writeString( element, "knotes-richtext", mRichText ? "true" : "false" );
+
+ return true;
+}
+
+
+bool Note::loadXML( const QDomDocument& document )
+{
+ QDomElement top = document.documentElement();
+
+ if ( top.tagName() != "note" ) {
+ qWarning( "XML error: Top tag was %s instead of the expected note",
+ top.tagName().toAscii().data() );
+ return false;
+ }
+
+ for ( QDomNode n = top.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ QDomElement e = n.toElement();
+ if ( !loadAttribute( e ) )
+ // TODO: Unhandled tag - save for later storage
+ kDebug() <<"Warning: Unhandled tag" << e.tagName();
+ } else
+ kDebug() <<"Node is not a comment or an element???";
+ }
+
+ return true;
+}
+
+QString Note::saveXML() const
+{
+ QDomDocument document = domTree();
+ QDomElement element = document.createElement( "note" );
+ element.setAttribute( "version", "1.0" );
+ saveAttributes( element );
+ document.appendChild( element );
+ return document.toString();
+}
+
+void Note::setFields( const KCalCore::Journal::Ptr &journal )
+{
+ KolabBase::setFields( journal );
+
+ setSummary( journal->summary() );
+
+ QString property = journal->customProperty( "KNotes", "BgColor" );
+ if ( !property.isEmpty() ) {
+ setBackgroundColor( property );
+ } else {
+ setBackgroundColor( "yellow" );
+ }
+
+ property = journal->customProperty( "KNotes", "FgColor" );
+ if ( !property.isEmpty() ) {
+ setForegroundColor( property );
+ } else {
+ setForegroundColor( "black" );
+ }
+
+ property = journal->customProperty( "KNotes", "RichText" );
+ if ( !property.isEmpty() ) {
+ setRichText( property == "true" ? true : false );
+ } else {
+ setRichText( "false" );
+ }
+}
+
+void Note::saveTo( const KCalCore::Journal::Ptr &journal )
+{
+ KolabBase::saveTo( journal );
+
+ // TODO: background and foreground
+ journal->setSummary( summary() );
+ if ( foregroundColor().isValid() )
+ journal->setCustomProperty( "KNotes", "FgColor",
+ colorToString( foregroundColor() ) );
+ if ( backgroundColor().isValid() )
+ journal->setCustomProperty( "KNotes", "BgColor",
+ colorToString( backgroundColor() ) );
+ journal->setCustomProperty( "KNotes", "RichText",
+ richText() ? "true" : "false" );
+}
+
+QString Note::productID() const
+{
+ return QString( "KNotes %1, Kolab resource" ).arg( AKONADI_VERSION );
+}
diff --git a/kolabformatV2/note.h b/kolabformatV2/note.h
new file mode 100644
index 0000000..b0291c4
--- /dev/null
+++ b/kolabformatV2/note.h
@@ -0,0 +1,109 @@
+/*
+ This file is part of the kolab resource - the implementation of the
+ Kolab storage format. See www.kolab.org for documentation on this.
+
+ Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), 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
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef KOLAB_NOTE_H
+#define KOLAB_NOTE_H
+
+#include <kcalcore/journal.h>
+
+#include <kolabbase.h>
+
+class QDomElement;
+
+namespace Kolab {
+
+/**
+ * This class represents a note, and knows how to load/save it
+ * from/to XML, and from/to a KCalCore::Journal.
+ * The instances of this class are temporary, only used to convert
+ * one to the other.
+ */
+class Note : public KolabBase {
+public:
+ /// Use this to parse an xml string to a journal entry
+ /// The caller is responsible for deleting the returned journal
+ static KCalCore::Journal::Ptr xmlToJournal( const QString& xml );
+
+ /// Use this to get an xml string describing this journal entry
+ static QString journalToXML( const KCalCore::Journal::Ptr & );
+
+ /// Create a note object and
+ explicit Note( const KCalCore::Journal::Ptr &journal = KCalCore::Journal::Ptr() );
+ virtual ~Note();
+
+ void saveTo( const KCalCore::Journal::Ptr &journal );
+
+ virtual QString type() const { return "Note"; }
+
+ virtual void setSummary( const QString& summary );
+ virtual QString summary() const;
+
+ virtual void setBackgroundColor( const QColor& bgColor );
+ virtual QColor backgroundColor() const;
+
+ virtual void setForegroundColor( const QColor& fgColor );
+ virtual QColor foregroundColor() const;
+
+ virtual void setRichText( bool richText );
+ virtual bool richText() const;
+
+ // Load the attributes of this class
+ virtual bool loadAttribute( QDomElement& );
+
+ // Save the attributes of this class
+ virtual bool saveAttributes( QDomElement& ) const;
+
+ // Load this note by reading the XML file
+ virtual bool loadXML( const QDomDocument& xml );
+
+ // Serialize this note to an XML string
+ virtual QString saveXML() const;
+
+protected:
+ // Read all known fields from this ical incidence
+ void setFields( const KCalCore::Journal::Ptr & );
+
+ // Save all known fields into this ical incidence
+ void saveTo( const KCalCore::Incidence::Ptr & ) const;
+
+ QString productID() const;
+
+ QString mSummary;
+ QColor mBackgroundColor;
+ QColor mForegroundColor;
+ bool mRichText;
+};
+
+}
+
+#endif // KOLAB_NOTE_H
diff --git a/kolabformatV2/task.cpp b/kolabformatV2/task.cpp
new file mode 100644
index 0000000..974fdb2
--- /dev/null
+++ b/kolabformatV2/task.cpp
@@ -0,0 +1,455 @@
+/*
+ This file is part of the kolab resource - the implementation of the
+ Kolab storage format. See www.kolab.org for documentation on this.
+
+ Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), 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
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "task.h"
+
+#include <kcalcore/todo.h>
+#include <kdebug.h>
+
+using namespace Kolab;
+
+// Kolab Storage Specification:
+// "The priority can be a number between 1 and 5, with 1 being the highest priority."
+// iCalendar (RFC 2445):
+// "The priority is specified as an integer in the range
+// zero to nine. A value of zero specifies an
+// undefined priority. A value of one is the
+// highest priority. A value of nine is the lowest
+// priority."
+
+static int kcalPriorityToKolab( const int kcalPriority )
+{
+ if ( kcalPriority >= 0 && kcalPriority <= 9 ) {
+ // We'll map undefined (0) to 3 (default)
+ // 0 1 2 3 4 5 6 7 8 9
+ static const int priorityMap[10] = { 3, 1, 1, 2, 2, 3, 3, 4, 4, 5 };
+ return priorityMap[kcalPriority];
+ }
+ else {
+ kWarning() << "Got invalid priority" << kcalPriority;
+ return 3;
+ }
+}
+
+static int kolabPrioritytoKCal( const int kolabPriority )
+{
+ if ( kolabPriority >= 1 && kolabPriority <= 5 ) {
+ // 1 2 3 4 5
+ static const int priorityMap[5] = { 1, 3, 5, 7, 9 };
+ return priorityMap[kolabPriority - 1];
+ }
+ else {
+ kWarning() << "Got invalid priority" << kolabPriority;
+ return 5;
+ }
+}
+
+KCalCore::Todo::Ptr Task::fromXml( const QDomDocument& xmlDoc, const QString& tz )
+{
+ Task task( tz );
+ task.loadXML( xmlDoc );
+ KCalCore::Todo::Ptr todo( new KCalCore::Todo() );
+ task.saveTo( todo );
+ return todo;
+}
+
+QString Task::taskToXML( const KCalCore::Todo::Ptr &todo, const QString& tz )
+{
+ Task task( tz, todo );
+ return task.saveXML();
+}
+
+Task::Task( const QString& tz, const KCalCore::Todo::Ptr &task )
+ : Incidence( tz, task ),
+ mPriority( 5 ), mPercentCompleted( 0 ),
+ mStatus( KCalCore::Incidence::StatusNone ),
+ mHasStartDate( false ), mHasDueDate( false ),
+ mHasCompletedDate( false )
+{
+ if ( task ) {
+ setFields( task );
+ }
+}
+
+Task::~Task()
+{
+}
+
+void Task::setPriority( int priority )
+{
+ mPriority = priority;
+}
+
+int Task::priority() const
+{
+ return mPriority;
+}
+
+void Task::setPercentCompleted( int percent )
+{
+ mPercentCompleted = percent;
+}
+
+int Task::percentCompleted() const
+{
+ return mPercentCompleted;
+}
+
+void Task::setStatus( KCalCore::Incidence::Status status )
+{
+ mStatus = status;
+}
+
+KCalCore::Incidence::Status Task::status() const
+{
+ return mStatus;
+}
+
+void Task::setParent( const QString& parentUid )
+{
+ mParent = parentUid;
+}
+
+QString Task::parent() const
+{
+ return mParent;
+}
+
+void Task::setDueDate( const KDateTime &date )
+{
+ mDueDate = date;
+ mHasDueDate = true;
+}
+
+void Task::setDueDate( const QDate &date )
+{
+ mDueDate = KDateTime( date );
+ mHasDueDate = true;
+ mFloatingStatus = AllDay;
+}
+
+void Task::setDueDate( const QString &date )
+{
+ if ( date.length() > 10 ) {
+ // This is a date + time
+ setDueDate( stringToDateTime( date ) );
+ } else {
+ // This is only a date
+ setDueDate( stringToDate( date ) );
+ }
+}
+
+KDateTime Task::dueDate() const
+{
+ return mDueDate;
+}
+
+void Task::setHasStartDate( bool v )
+{
+ mHasStartDate = v;
+}
+
+bool Task::hasStartDate() const
+{
+ return mHasStartDate;
+}
+
+bool Task::hasDueDate() const
+{
+ return mHasDueDate;
+}
+
+void Task::setCompletedDate( const KDateTime& date )
+{
+ mCompletedDate = date;
+ mHasCompletedDate = true;
+}
+
+KDateTime Task::completedDate() const
+{
+ return mCompletedDate;
+}
+
+bool Task::hasCompletedDate() const
+{
+ return mHasCompletedDate;
+}
+
+bool Task::loadAttribute( QDomElement& element )
+{
+ QString tagName = element.tagName();
+
+ if ( tagName == "priority" ) {
+ bool ok;
+ mKolabPriorityFromDom = element.text().toInt( &ok );
+ if ( !ok || mKolabPriorityFromDom < 1 || mKolabPriorityFromDom > 5 ) {
+ kWarning() << "Invalid \"priority\" value:" << element.text();
+ mKolabPriorityFromDom = -1;
+ }
+ } else if ( tagName == "x-kcal-priority" ) {
+ bool ok;
+ mKCalPriorityFromDom = element.text().toInt( &ok );
+ if ( !ok || mKCalPriorityFromDom < 0 || mKCalPriorityFromDom > 9 ) {
+ kWarning() << "Invalid \"x-kcal-priority\" value:" << element.text();
+ mKCalPriorityFromDom = -1;
+ }
+ } else if ( tagName == "completed" ) {
+ bool ok;
+ int percent = element.text().toInt( &ok );
+ if ( !ok || percent < 0 || percent > 100 )
+ percent = 0;
+ setPercentCompleted( percent );
+ } else if ( tagName == "status" ) {
+ if ( element.text() == "in-progress" )
+ setStatus( KCalCore::Incidence::StatusInProcess );
+ else if ( element.text() == "completed" )
+ setStatus( KCalCore::Incidence::StatusCompleted );
+ else if ( element.text() == "waiting-on-someone-else" )
+ setStatus( KCalCore::Incidence::StatusNeedsAction );
+ else if ( element.text() == "deferred" )
+ // Guessing a status here
+ setStatus( KCalCore::Incidence::StatusCanceled );
+ else
+ // Default
+ setStatus( KCalCore::Incidence::StatusNone );
+ } else if ( tagName == "due-date" ) {
+ setDueDate( element.text() );
+ } else if ( tagName == "parent" ) {
+ setParent( element.text() );
+ } else if ( tagName == "x-completed-date" ) {
+ setCompletedDate( stringToDateTime( element.text() ) );
+ } else if ( tagName == "start-date" ) {
+ setHasStartDate( true );
+ setStartDate( element.text() );
+ } else
+ return Incidence::loadAttribute( element );
+
+ // We handled this
+ return true;
+}
+
+bool Task::saveAttributes( QDomElement& element ) const
+{
+ // Save the base class elements
+ Incidence::saveAttributes( element );
+
+ // We need to save x-kcal-priority as well, since the Kolab priority can only save values from
+ // 1 to 5, but we have values from 0 to 9, and do not want to loose them
+ writeString( element, "priority", QString::number( kcalPriorityToKolab( priority() ) ) );
+ writeString( element, "x-kcal-priority", QString::number( priority() ) );
+
+ writeString( element, "completed", QString::number( percentCompleted() ) );
+
+ switch( status() ) {
+ case KCalCore::Incidence::StatusInProcess:
+ writeString( element, "status", "in-progress" );
+ break;
+ case KCalCore::Incidence::StatusCompleted:
+ writeString( element, "status", "completed" );
+ break;
+ case KCalCore::Incidence::StatusNeedsAction:
+ writeString( element, "status", "waiting-on-someone-else" );
+ break;
+ case KCalCore::Incidence::StatusCanceled:
+ writeString( element, "status", "deferred" );
+ break;
+ case KCalCore::Incidence::StatusNone:
+ writeString( element, "status", "not-started" );
+ break;
+ case KCalCore::Incidence::StatusTentative:
+ case KCalCore::Incidence::StatusConfirmed:
+ case KCalCore::Incidence::StatusDraft:
+ case KCalCore::Incidence::StatusFinal:
+ case KCalCore::Incidence::StatusX:
+ // All of these are saved as StatusNone.
+ writeString( element, "status", "not-started" );
+ break;
+ }
+
+ if ( hasDueDate() ) {
+ if ( mFloatingStatus == HasTime ) {
+ writeString( element, "due-date", dateTimeToString( dueDate() ) );
+ } else {
+ writeString( element, "due-date", dateToString( dueDate().date() ) );
+ }
+ }
+
+ if ( !parent().isNull() ) {
+ writeString( element, "parent", parent() );
+ }
+
+ if ( hasCompletedDate() && percentCompleted() == 100 ) {
+ writeString( element, "x-completed-date", dateTimeToString( completedDate() ) );
+ }
+
+ return true;
+}
+
+
+bool Task::loadXML( const QDomDocument& document )
+{
+ mKolabPriorityFromDom = -1;
+ mKCalPriorityFromDom = -1;
+
+ QDomElement top = document.documentElement();
+
+ if ( top.tagName() != "task" ) {
+ qWarning( "XML error: Top tag was %s instead of the expected task",
+ top.tagName().toAscii().data() );
+ return false;
+ }
+ setHasStartDate( false ); // todo's don't necessarily have one
+
+ for ( QDomNode n = top.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ QDomElement e = n.toElement();
+ if ( !loadAttribute( e ) )
+ // TODO: Unhandled tag - save for later storage
+ kDebug() <<"Warning: Unhandled tag" << e.tagName();
+ } else
+ kDebug() <<"Node is not a comment or an element???";
+ }
+
+ decideAndSetPriority();
+ return true;
+}
+
+QString Task::saveXML() const
+{
+ QDomDocument document = domTree();
+ QDomElement element = document.createElement( "task" );
+ element.setAttribute( "version", "1.0" );
+ saveAttributes( element );
+ if ( !hasStartDate() && startDate().isValid() ) {
+ // events and journals always have a start date, but tasks don't.
+ // Remove the entry done by the inherited save above, because we
+ // don't have one.
+ QDomNodeList l = element.elementsByTagName( "start-date" );
+ Q_ASSERT( l.count() == 1 );
+ element.removeChild( l.item( 0 ) );
+ }
+ document.appendChild( element );
+ return document.toString();
+}
+
+void Task::setFields( const KCalCore::Todo::Ptr &task )
+{
+ Incidence::setFields( task );
+
+ setPriority( task->priority() );
+ setPercentCompleted( task->percentComplete() );
+ setStatus( task->status() );
+ setHasStartDate( task->hasStartDate() );
+
+ if ( task->hasDueDate() ) {
+ if ( task->allDay() ) {
+ // This is a floating task. Don't timezone move this one
+ mFloatingStatus = AllDay;
+ setDueDate( KDateTime( task->dtDue().date() ) );
+ } else {
+ mFloatingStatus = HasTime;
+ setDueDate( localToUTC( task->dtDue() ) );
+ }
+ } else {
+ mHasDueDate = false;
+ }
+
+ if ( !task->relatedTo().isEmpty() ) {
+ setParent( task->relatedTo() );
+ } else{
+ setParent( QString() );
+ }
+
+ if ( task->hasCompletedDate() && task->percentComplete() == 100 ) {
+ setCompletedDate( localToUTC( task->completed() ) );
+ } else {
+ mHasCompletedDate = false;
+ }
+}
+
+void Task::decideAndSetPriority()
+{
+ // If we have both Kolab and KCal values in the XML, we prefer the KCal value, but only if the
+ // values are still in sync
+ if ( mKolabPriorityFromDom != -1 && mKCalPriorityFromDom != -1 ) {
+ const bool inSync = ( kcalPriorityToKolab( mKCalPriorityFromDom ) == mKolabPriorityFromDom );
+ if ( inSync ) {
+ setPriority( mKCalPriorityFromDom );
+ }
+ else {
+ // Out of sync, some other client changed the Kolab priority, so we have to ignore our
+ // KCal priority
+ setPriority( kolabPrioritytoKCal( mKolabPriorityFromDom ) );
+ }
+ }
+
+ // Only KCal priority set, use that.
+ else if ( mKolabPriorityFromDom == -1 && mKCalPriorityFromDom != -1 ) {
+ kWarning() << "No Kolab priority found, only the KCal priority!";
+ setPriority( mKCalPriorityFromDom );
+ }
+
+ // Only Kolab priority set, use that
+ else if ( mKolabPriorityFromDom != -1 && mKCalPriorityFromDom == -1 ) {
+ setPriority( kolabPrioritytoKCal( mKolabPriorityFromDom ) );
+ }
+
+ // No priority set, use the default
+ else {
+ // According the RFC 2445, we should use 0 here, for undefined priority, but AFAIK KOrganizer
+ // doesn't support that, so we'll use 5.
+ setPriority( 5 );
+ }
+}
+
+void Task::saveTo( const KCalCore::Todo::Ptr &task )
+{
+ Incidence::saveTo( task );
+
+ task->setPriority( priority() );
+ task->setPercentComplete( percentCompleted() );
+ task->setStatus( status() );
+ task->setHasStartDate( hasStartDate() );
+ task->setHasDueDate( hasDueDate() );
+ if ( hasDueDate() )
+ task->setDtDue( utcToLocal( dueDate() ) );
+
+ if ( !parent().isEmpty() ) {
+ task->setRelatedTo( parent() );
+ }
+
+ if ( hasCompletedDate() && task->percentComplete() == 100 )
+ task->setCompleted( utcToLocal( mCompletedDate ) );
+}
diff --git a/kolabformatV2/task.h b/kolabformatV2/task.h
new file mode 100644
index 0000000..bafc160
--- /dev/null
+++ b/kolabformatV2/task.h
@@ -0,0 +1,143 @@
+/*
+ This file is part of the kolab resource - the implementation of the
+ Kolab storage format. See www.kolab.org for documentation on this.
+
+ Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), 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
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef KOLAB_TASK_H
+#define KOLAB_TASK_H
+
+#include <incidence.h>
+
+#include <kcalcore/todo.h>
+#include <kcalcore/incidence.h>
+
+class QDomElement;
+
+namespace KCal {
+ class ResourceKolab;
+}
+
+namespace Kolab {
+
+/**
+ * This class represents a task, and knows how to load/save it
+ * from/to XML, and from/to a KCalCore::Todo.
+ * The instances of this class are temporary, only used to convert
+ * one to the other.
+ */
+class Task : public Incidence {
+public:
+ /// Use this to parse an xml string to a task entry
+ /// The caller is responsible for deleting the returned task
+ static KCalCore::Todo::Ptr fromXml( const QDomDocument& xmlDoc, const QString& tz/*, KCalCore::ResourceKolab *res = 0,
+ const QString& subResource = QString(), quint32 sernum = 0 */);
+
+ /// Use this to get an xml string describing this task entry
+ static QString taskToXML( const KCalCore::Todo::Ptr &, const QString& tz );
+
+ explicit Task( /*KCalCore::ResourceKolab *res, const QString& subResource, quint32 sernum,*/
+ const QString& tz, const KCalCore::Todo::Ptr &todo = KCalCore::Todo::Ptr() );
+ virtual ~Task();
+
+ virtual QString type() const { return "Task"; }
+
+ void saveTo( const KCalCore::Todo::Ptr &todo );
+
+ virtual void setPriority( int priority );
+ virtual int priority() const;
+
+ virtual void setPercentCompleted( int percent );
+ virtual int percentCompleted() const;
+
+ virtual void setStatus( KCalCore::Incidence::Status status );
+ virtual KCalCore::Incidence::Status status() const;
+
+ virtual void setParent( const QString& parentUid );
+ virtual QString parent() const;
+
+ virtual void setHasStartDate( bool );
+ virtual bool hasStartDate() const;
+
+ virtual void setDueDate( const KDateTime& date );
+ virtual void setDueDate( const QString &date );
+ virtual void setDueDate( const QDate &date );
+ virtual KDateTime dueDate() const;
+ virtual bool hasDueDate() const;
+
+ virtual void setCompletedDate( const KDateTime& date );
+ virtual KDateTime completedDate() const;
+ virtual bool hasCompletedDate() const;
+
+ // Load the attributes of this class
+ virtual bool loadAttribute( QDomElement& );
+
+ // Save the attributes of this class
+ virtual bool saveAttributes( QDomElement& ) const;
+
+ // Load this task by reading the XML file
+ virtual bool loadXML( const QDomDocument& xml );
+
+ // Serialize this task to an XML string
+ virtual QString saveXML() const;
+
+protected:
+ // Read all known fields from this ical todo
+ void setFields( const KCalCore::Todo::Ptr & );
+
+ // This sets the priority of this task by looking at mKolabPriorityFromDom and
+ // mKCalPriorityFromDom.
+ void decideAndSetPriority();
+
+ // This is the KCal priority, not the Kolab priority.
+ // See kcalPriorityToKolab() and kolabPrioritytoKCal().
+ int mPriority;
+
+ // Those priority values are the raw values read by loadAttribute().
+ // They will be converted later in decideAndSetPriority().
+ int mKolabPriorityFromDom;
+ int mKCalPriorityFromDom;
+
+ int mPercentCompleted;
+ KCalCore::Incidence::Status mStatus;
+ QString mParent;
+
+ bool mHasStartDate;
+
+ bool mHasDueDate;
+ KDateTime mDueDate;
+
+ bool mHasCompletedDate;
+ KDateTime mCompletedDate;
+};
+
+}
+
+#endif // KOLAB_TASK_H
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Apr 4, 8:17 AM (1 w, 5 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18720888
Default Alt Text
(160 KB)
Attached To
Mode
rLK libkolab
Attached
Detach File
Event Timeline