diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | 460c52653ab0dcca6f19a4f492ed2c5e4e963ab0 (patch) | |
tree | 67208f7c145782a7e90b123b982ca78d88cc2c87 /kresources/scalix | |
download | tdepim-460c52653ab0dcca6f19a4f492ed2c5e4e963ab0.tar.gz tdepim-460c52653ab0dcca6f19a4f492ed2c5e4e963ab0.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdepim@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kresources/scalix')
64 files changed, 7714 insertions, 0 deletions
diff --git a/kresources/scalix/Makefile.am b/kresources/scalix/Makefile.am new file mode 100644 index 000000000..1a58c7ec9 --- /dev/null +++ b/kresources/scalix/Makefile.am @@ -0,0 +1,4 @@ +SUBDIRS = shared kabc kcal kioslave knotes scalixadmin + +messages: rc.cpp + $(XGETTEXT) shared/*.cpp kabc/*.cpp kcal/*.cpp knotes/*.cpp -o $(podir)/kres_scalix.pot diff --git a/kresources/scalix/README b/kresources/scalix/README new file mode 100644 index 000000000..34a00e9ad --- /dev/null +++ b/kresources/scalix/README @@ -0,0 +1,9 @@ +The Scalix Resource is based on the code of the Kolab resource as both +groupware servers use a similar storage concept (storing pim items as +email attachments on an IMAP server). + +However the Scalix Resource has several modifications, e.g. the XML storage +type was removed and freebusy handling is done via a separated KIO slave. + +If you have any problems, questions or suggestions contact me under + Tobias Koenig <[email protected]> diff --git a/kresources/scalix/kabc/Makefile.am b/kresources/scalix/kabc/Makefile.am new file mode 100644 index 000000000..a9fbf2021 --- /dev/null +++ b/kresources/scalix/kabc/Makefile.am @@ -0,0 +1,27 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/kresources/scalix/shared -I$(top_srcdir) $(all_includes) + +# The scalix wizard links to this library too +lib_LTLIBRARIES = libkabcscalix.la + +libkabcscalix_la_SOURCES = resourcescalix.cpp contact.cpp +libkabcscalix_la_LDFLAGS = $(all_libraries) -no-undefined +libkabcscalix_la_LIBADD = \ + $(top_builddir)/kresources/scalix/shared/libresourcescalixshared.la \ + -lkresources -lkabc + +kde_module_LTLIBRARIES = kabc_scalix.la + +noinst_HEADERS = resourcescalix.h + +kabc_scalix_la_SOURCES = resourcescalix_plugin.cpp +kabc_scalix_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) -no-undefined +kabc_scalix_la_LIBADD = libkabcscalix.la + +servicedir = $(kde_servicesdir)/kresources/kabc +service_DATA = scalix.desktop + +install-data-local: $(srcdir)/../uninstall.desktop + $(mkinstalldirs) $(DESTDIR)$(servicedir) + $(INSTALL_DATA) $(srcdir)/../uninstall.desktop $(DESTDIR)$(servicedir)/imap.desktop diff --git a/kresources/scalix/kabc/contact.cpp b/kresources/scalix/kabc/contact.cpp new file mode 100644 index 000000000..156ae01af --- /dev/null +++ b/kresources/scalix/kabc/contact.cpp @@ -0,0 +1,377 @@ +/* + * This file is part of the scalix resource. + * + * Copyright (C) 2007 Trolltech ASA. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <qdom.h> + +#include <libkdepim/distributionlist.h> +#include <kstaticdeleter.h> + +#include "contact.h" + +using namespace Scalix; + +static QMap<QString, QString> *s_distListMap = 0; +static KStaticDeleter< QMap<QString, QString> > sd; + +static QString custom( const QString &name, const KABC::Addressee &addr, const QString &defaultValue = QString() ) +{ + const QString value = addr.custom( "Scalix", name ); + if ( value.isEmpty() ) + return defaultValue; + else + return value; +} + +static void setCustom( const QString &name, const QString &value, KABC::Addressee &addr ) +{ + addr.insertCustom( "Scalix", name, value ); +} + +QString Contact::toXml( const KABC::Addressee &addr ) +{ + /** + * Handle distribution lists. + */ + if ( KPIM::DistributionList::isDistributionList( addr ) ) { + if ( s_distListMap ) + return (*s_distListMap)[ addr.uid() ]; + else + return QString(); + } + + /** + * Handle normal contacts. + */ + QString xml; + xml += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; + xml += "<contact>\n"; + + xml += "<direct_ref>" + addr.uid() + "</direct_ref>\n"; + xml += "<sensitivity>" + custom( "sensitivity", addr, "0" ) + "</sensitivity>\n"; + + xml += "<message_class>IPM.Contact</message_class>\n"; + xml += "<is_recurring>" + custom( "is_recurring", addr, "false" ) + "</is_recurring>\n"; + xml += "<reminder_set>" + custom( "reminder_set", addr, "false" ) + "</reminder_set>\n"; + xml += "<send_rich_info>" + custom( "send_rich_info", addr, "false" ) + "</send_rich_info>\n"; + xml += "<subject>" + addr.formattedName() + "</subject>\n"; + xml += "<last_modification_time>" + addr.revision().toString( Qt::ISODate ) + "</last_modification_time>\n"; + + xml += "<display_name_prefix>" + addr.prefix() + "</display_name_prefix>\n"; + xml += "<first_name>" + addr.givenName() + "</first_name>\n"; + xml += "<middle_name>" + addr.additionalName() + "</middle_name>\n"; + xml += "<last_name>" + addr.familyName() + "</last_name>\n"; + xml += "<suffix>" + addr.suffix() + "</suffix>\n"; + xml += "<display_name>" + addr.assembledName() + "</display_name>\n"; + xml += "<file_as>" + addr.formattedName() + "</file_as>\n"; + xml += "<nickname>" + addr.nickName() + "</nickname>\n"; + + xml += "<web_page_address>" + addr.url().url() + "</web_page_address>\n"; + xml += "<company_name>" + addr.organization() + "</company_name>\n"; + xml += "<job_title>" + addr.title() + "</job_title>\n"; + + QStringList emails = addr.emails(); + for ( uint i = 0; i < 3; ++i ) { + QString type, address, comment, display; + + if ( i < emails.count() ) { + type = "SMTP"; + address = emails[ i ]; + + /** + * If the contact was created by kontact use the email address as + * display name and the formatted name as comment, otherwise we use + * the values from the server. + */ + if ( custom( "comes_from_scalix", addr ) != "true" ) { + comment = addr.formattedName(); + display = emails[ i ]; + } else { + comment = custom( QString( "email%1_address_with_comment" ).arg( i + 1 ), addr ); + display = custom( QString( "email%1_display_name" ).arg( i + 1 ), addr ); + } + } + + xml += QString( "<email%1_address_type>" ).arg( i + 1 ) + type + + QString( "</email%1_address_type>" ).arg( i + 1 ) +"\n"; + xml += QString( "<email%1_address>" ).arg( i + 1 ) + address + + QString( "</email%1_address>" ).arg( i + 1 ) +"\n"; + xml += QString( "<email%1_address_with_comment>" ).arg( i + 1 ) + comment + + QString( "</email%1_address_with_comment>" ).arg( i + 1 ) + "\n"; + xml += QString( "<email%1_display_name>" ).arg( i + 1 ) + display + + QString( "</email%1_display_name>" ).arg( i + 1 ) + "\n"; + } + + KABC::PhoneNumber phone = addr.phoneNumber( KABC::PhoneNumber::Home ); + xml += "<home_phone_number>" + phone.number() + "</home_phone_number>\n"; + + phone = addr.phoneNumber( KABC::PhoneNumber::Work ); + xml += "<work_phone_number>" + phone.number() + "</work_phone_number>\n"; + + phone = addr.phoneNumber( KABC::PhoneNumber::Work | KABC::PhoneNumber::Fax ); + xml += "<work_fax_number>" + phone.number() + "</work_fax_number>\n"; + + phone = addr.phoneNumber( KABC::PhoneNumber::Cell ); + xml += "<mobile_phone_number>" + phone.number() + "</mobile_phone_number>\n"; + + const KABC::Address workAddress = addr.address( KABC::Address::Work ); + xml += "<work_address_street>" + workAddress.street() + "</work_address_street>\n"; + xml += "<work_address_zip>" + workAddress.postalCode() + "</work_address_zip>\n"; + xml += "<work_address_city>" + workAddress.locality() + "</work_address_city>\n"; + xml += "<work_address_state>" + workAddress.region() + "</work_address_state>\n"; + xml += "<work_address_country>" + workAddress.country() + "</work_address_country>\n"; + + const KABC::Address homeAddress = addr.address( KABC::Address::Home ); + xml += "<home_address_street>" + homeAddress.street() + "</home_address_street>\n"; + xml += "<home_address_zip>" + homeAddress.postalCode() + "</home_address_zip>\n"; + xml += "<home_address_city>" + homeAddress.locality() + "</home_address_city>\n"; + xml += "<home_address_state>" + homeAddress.region() + "</home_address_state>\n"; + xml += "<home_address_country>" + homeAddress.country() + "</home_address_country>\n"; + + const KABC::Address otherAddress = addr.address( KABC::Address::Dom ); + xml += "<other_address_street>" + otherAddress.street() + "</other_address_street>\n"; + xml += "<other_address_zip>" + otherAddress.postalCode() + "</other_address_zip>\n"; + xml += "<other_address_city>" + otherAddress.locality() + "</other_address_city>\n"; + xml += "<other_address_state>" + otherAddress.region() + "</other_address_state>\n"; + xml += "<other_address_country>" + otherAddress.country() + "</other_address_country>\n"; + + if ( homeAddress.type() & KABC::Address::Pref ) + xml += "<selected_mailing_address>1</selected_mailing_address>\n"; + else if ( workAddress.type() & KABC::Address::Pref ) + xml += "<selected_mailing_address>2</selected_mailing_address>\n"; + else if ( otherAddress.type() & KABC::Address::Pref ) + xml += "<selected_mailing_address>3</selected_mailing_address>\n"; + + xml += "<im_address>" + addr.custom( "KADDRESSBOOK", "X-IMAddress" ) + "</im_address>\n"; + xml += "<manager>" + addr.custom( "KADDRESSBOOK", "X-ManagersName" ) + "</manager>\n"; + xml += "<department>" + addr.custom( "KADDRESSBOOK", "X-Department" ) + "</department>\n"; + xml += "<assistant>" + addr.custom( "KADDRESSBOOK", "X-AssistantsName" ) + "</assistant>\n"; + xml += "<profession>" + addr.custom( "KADDRESSBOOK", "X-Profession" ) + "</profession>\n"; + xml += "<office_location>" + addr.custom( "KADDRESSBOOK", "X-Office" ) + "</office_location>\n"; + xml += "<spouse>" + addr.custom( "KADDRESSBOOK", "X-SpousesName" ) + "</spouse>\n"; + + xml += "<bday>" + addr.birthday().toString( Qt::ISODate ) + "</bday>\n"; + xml += "<anniversary>" + addr.custom( "KADDRESSBOOK", "X-Anniversary" ) + "</anniversary>\n"; + + xml += "<mapi_charset>" + custom( "mapi_charset", addr, "UTF8" ) + "</mapi_charset>"; + + xml += "</contact>\n"; + + return xml; +} + +KABC::Addressee Contact::fromXml( const QString &xml ) +{ + QDomDocument document; + + QString errorMsg; + int errorLine, errorColumn; + if ( !document.setContent( xml, true, &errorMsg, &errorLine, &errorColumn ) ) { + qDebug( "Error parsing XML in Scalix::Contact::fromXml: %s (%d,%d)", errorMsg.latin1(), errorLine, errorColumn ); + return KABC::Addressee(); + } + + QDomElement contactElement = document.documentElement(); + if ( contactElement.tagName() != "contact" ) { + if ( contactElement.tagName() == "distlist" ) { + const QDomNodeList names = contactElement.elementsByTagName( "display_name" ); + const QString listName = ( names.count() == 1 ? names.item( 0 ).toElement().text() : "Scalix Dummy List" ); + + /** + * As we can't provide distribution list functionality we store the entry + * here and return it on save. + */ + KPIM::DistributionList list; + list.setName( listName ); + + if ( !s_distListMap ) + sd.setObject( s_distListMap, new QMap<QString, QString>() ); + + s_distListMap->insert( list.uid(), xml ); + + return list; + } else { + qDebug( "Error interpreting XML in Scalix::Contact::fromXml: no 'contact' or 'distlist' tag found" ); + return KABC::Addressee(); + } + } + + QString emails[ 3 ]; + KABC::Address homeAddress( KABC::Address::Home ); + KABC::Address workAddress( KABC::Address::Work ); + KABC::Address otherAddress( KABC::Address::Dom ); + + KABC::Addressee addr; + setCustom( "comes_from_scalix", "true", addr ); + + QDomNode node = contactElement.firstChild(); + while ( !node.isNull() ) { + QDomElement element = node.toElement(); + if ( !element.isNull() ) { + if ( element.tagName() == "direct_ref" ) + addr.setUid( element.text() ); + else if ( element.tagName() == "sensitivity" ) + setCustom( "sensitivity", element.text(), addr ); + else if ( element.tagName() == "is_recurring" ) + setCustom( "is_recurring", element.text(), addr ); + else if ( element.tagName() == "reminder_set" ) + setCustom( "reminder_set", element.text(), addr ); + else if ( element.tagName() == "send_rich_info" ) + setCustom( "send_rich_info", element.text(), addr ); + else if ( element.tagName() == "last_modification_time" ) + addr.setRevision( QDateTime::fromString( element.text(), Qt::ISODate ) ); + + // name + else if ( element.tagName() == "display_name_prefix" ) + addr.setPrefix( element.text() ); + else if ( element.tagName() == "first_name" ) + addr.setGivenName( element.text() ); + else if ( element.tagName() == "middle_name" ) + addr.setAdditionalName( element.text() ); + else if ( element.tagName() == "last_name" ) + addr.setFamilyName( element.text() ); + else if ( element.tagName() == "suffix" ) + addr.setSuffix( element.text() ); + else if ( element.tagName() == "file_as" ) + addr.setFormattedName( element.text() ); + else if ( element.tagName() == "nickname" ) + addr.setNickName( element.text() ); + + // job + else if ( element.tagName() == "web_page_address" ) + addr.setUrl( element.text() ); + else if ( element.tagName() == "company_name" ) + addr.setOrganization( element.text() ); + else if ( element.tagName() == "job_title" ) + addr.setTitle( element.text() ); + + // emails + else if ( element.tagName().startsWith( "email" ) ) { + if ( element.tagName() == "email1_address" ) + emails[ 0 ] = element.text(); + else if ( element.tagName() == "email2_address" ) + emails[ 1 ] = element.text(); + else if ( element.tagName() == "email3_address" ) + emails[ 2 ] = element.text(); + else + setCustom( element.tagName(), element.text(), addr ); + } + + // phone numbers + else if ( element.tagName() == "home_phone_number" ) + addr.insertPhoneNumber( KABC::PhoneNumber( element.text(), KABC::PhoneNumber::Home ) ); + else if ( element.tagName() == "work_phone_number" ) + addr.insertPhoneNumber( KABC::PhoneNumber( element.text(), KABC::PhoneNumber::Work ) ); + else if ( element.tagName() == "work_fax_number" ) + addr.insertPhoneNumber( KABC::PhoneNumber( element.text(), KABC::PhoneNumber::Work | KABC::PhoneNumber::Fax ) ); + else if ( element.tagName() == "mobile_phone_number" ) + addr.insertPhoneNumber( KABC::PhoneNumber( element.text(), KABC::PhoneNumber::Cell ) ); + + // address (work) + else if ( element.tagName() == "work_address_street" ) + workAddress.setStreet( element.text() ); + else if ( element.tagName() == "work_address_zip" ) + workAddress.setPostalCode( element.text() ); + else if ( element.tagName() == "work_address_city" ) + workAddress.setLocality( element.text() ); + else if ( element.tagName() == "work_address_state" ) + workAddress.setRegion( element.text() ); + else if ( element.tagName() == "work_address_country" ) + workAddress.setCountry( element.text() ); + + // address (home) + else if ( element.tagName() == "home_address_street" ) + homeAddress.setStreet( element.text() ); + else if ( element.tagName() == "home_address_zip" ) + homeAddress.setPostalCode( element.text() ); + else if ( element.tagName() == "home_address_city" ) + homeAddress.setLocality( element.text() ); + else if ( element.tagName() == "home_address_state" ) + homeAddress.setRegion( element.text() ); + else if ( element.tagName() == "home_address_country" ) + homeAddress.setCountry( element.text() ); + + // address (other) + else if ( element.tagName() == "other_address_street" ) + otherAddress.setStreet( element.text() ); + else if ( element.tagName() == "other_address_zip" ) + otherAddress.setPostalCode( element.text() ); + else if ( element.tagName() == "other_address_city" ) + otherAddress.setLocality( element.text() ); + else if ( element.tagName() == "other_address_state" ) + otherAddress.setRegion( element.text() ); + else if ( element.tagName() == "other_address_country" ) + otherAddress.setCountry( element.text() ); + + else if ( element.tagName() == "selected_mailing_address" ) + switch ( element.text().toInt() ) { + case 1: + homeAddress.setType( homeAddress.type() | KABC::Address::Pref ); + break; + case 2: + workAddress.setType( workAddress.type() | KABC::Address::Pref ); + break; + case 3: + otherAddress.setType( otherAddress.type() | KABC::Address::Pref ); + break; + default: + Q_ASSERT( !"Unknown selected_mailing_address enum" ); + break; + } + + // misc + else if ( element.tagName() == "im_address" ) + addr.insertCustom( "KADDRESSBOOK", "X-IMAddress", element.text() ); + else if ( element.tagName() == "manager" ) + addr.insertCustom( "KADDRESSBOOK", "X-ManagersName", element.text() ); + else if ( element.tagName() == "department" ) + addr.insertCustom( "KADDRESSBOOK", "X-Department", element.text() ); + else if ( element.tagName() == "assistant" ) + addr.insertCustom( "KADDRESSBOOK", "X-AssistantsName", element.text() ); + else if ( element.tagName() == "profession" ) + addr.insertCustom( "KADDRESSBOOK", "X-Profession", element.text() ); + else if ( element.tagName() == "office_location" ) + addr.insertCustom( "KADDRESSBOOK", "X-Office", element.text() ); + else if ( element.tagName() == "spouse" ) + addr.insertCustom( "KADDRESSBOOK", "X-SpousesName", element.text() ); + + else if ( element.tagName() == "bday" ) + addr.setBirthday( QDateTime::fromString( element.text(), Qt::ISODate ) ); + else if ( element.tagName() == "anniversary" ) + addr.insertCustom( "KADDRESSBOOK", "X-Anniversary", element.text() ); + else + setCustom( element.tagName(), element.text(), addr ); + } + + node = node.nextSibling(); + } + + for ( int i = 0; i < 3; ++i ) + if ( !emails[ i ].isEmpty() ) + addr.insertEmail( emails[ i ] ); + + if ( !homeAddress.isEmpty() ) + addr.insertAddress( homeAddress ); + if ( !workAddress.isEmpty() ) + addr.insertAddress( workAddress ); + if ( !otherAddress.isEmpty() ) + addr.insertAddress( otherAddress ); + + return addr; +} diff --git a/kresources/scalix/kabc/contact.h b/kresources/scalix/kabc/contact.h new file mode 100644 index 000000000..d73765ede --- /dev/null +++ b/kresources/scalix/kabc/contact.h @@ -0,0 +1,37 @@ +/* + * This file is part of the scalix resource. + * + * Copyright (C) 2007 Trolltech ASA. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef SCALIX_CONTACT_H +#define SCALIX_CONTACT_H + +#include <kabc/addressee.h> + +namespace Scalix { + +class Contact +{ + public: + static QString toXml( const KABC::Addressee &addr ); + static KABC::Addressee fromXml( const QString &xml ); +}; + +} + +#endif diff --git a/kresources/scalix/kabc/resourcescalix.cpp b/kresources/scalix/kabc/resourcescalix.cpp new file mode 100644 index 000000000..6cbf10832 --- /dev/null +++ b/kresources/scalix/kabc/resourcescalix.cpp @@ -0,0 +1,628 @@ +/* + This file is part of the scalix resource - based on the kolab resource. + + Copyright (c) 2002 - 2004 Klar�lvdalens Datakonsult AB + + 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 "resourcescalix.h" + +#include <kdebug.h> +#include <kglobal.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <ktempfile.h> +#include <kio/observer.h> +#include <kio/uiserver_stub.h> +#include <kmainwindow.h> +#include <kapplication.h> +#include <dcopclient.h> + +#include <qobject.h> +#include <qtimer.h> +#include <qstring.h> +#include <qfile.h> +#include <qapplication.h> + +#include <assert.h> + +#include "contact.h" + +using namespace Scalix; + +class ScalixFactory : public KRES::PluginFactoryBase +{ + public: + KRES::Resource *resource( const KConfig *config ) + { + return new KABC::ResourceScalix( config ); + } + + KRES::ConfigWidget *configWidget( QWidget* ) + { + return 0; + } +}; + +K_EXPORT_COMPONENT_FACTORY(kabc_scalix,ScalixFactory) + +static const char* s_kmailContentsType = "Contact"; +static const char* s_attachmentMimeTypeContact = "application/x-vnd.kolab.contact"; +static const char* s_attachmentMimeTypeDistList = "application/x-vnd.kolab.contact.distlist"; +static const char* s_inlineMimeType = "application/scalix-properties"; + +KABC::ResourceScalix::ResourceScalix( const KConfig *config ) + : KPIM::ResourceABC( config ), + Scalix::ResourceScalixBase( "ResourceScalix-KABC" ), + mCachedSubresource( QString::null ), mLocked( false ) +{ + setType( "scalix" ); +} + +KABC::ResourceScalix::~ResourceScalix() +{ + // The resource is deleted on exit (StdAddressBook's KStaticDeleter), + // and it wasn't closed before that, so close here to save the config. + if ( isOpen() ) { + close(); + } +} + +void KABC::ResourceScalix::loadSubResourceConfig( KConfig& config, + const QString& name, + const QString& label, + bool writable ) +{ + KConfigGroup group( &config, name ); + bool active = group.readBoolEntry( "Active", true ); + int completionWeight = group.readNumEntry( "CompletionWeight", 80 ); + mSubResources.insert( name, Scalix::SubResource( active, writable, label, + completionWeight ) ); +} + +bool KABC::ResourceScalix::doOpen() +{ + KConfig config( configFile() ); + + // Read the calendar entries + QValueList<KMailICalIface::SubResource> subResources; + if ( !kmailSubresources( subResources, s_kmailContentsType ) ) + return false; + mSubResources.clear(); + QValueList<KMailICalIface::SubResource>::ConstIterator it; + for ( it = subResources.begin(); it != subResources.end(); ++it ) { + loadSubResourceConfig( config, (*it).location, (*it).label, (*it).writable ); + } + + return true; +} + +void KABC::ResourceScalix::doClose() +{ + KConfig config( configFile() ); + + Scalix::ResourceMap::ConstIterator it; + for ( it = mSubResources.begin(); it != mSubResources.end(); ++it ) { + config.setGroup( it.key() ); + config.writeEntry( "Active", it.data().active() ); + config.writeEntry( "CompletionWeight", it.data().completionWeight() ); + } +} + +KABC::Ticket * KABC::ResourceScalix::requestSaveTicket() +{ + if ( !addressBook() ) { + kdError() << "no addressbook" << endl; + return 0; + } + mLocked = true; + + return createTicket( this ); +} + +void KABC::ResourceScalix::releaseSaveTicket( Ticket* ticket ) +{ + mLocked = false; + mCachedSubresource = QString::null; + delete ticket; +} + +QString KABC::ResourceScalix::loadContact( const QString& contactData, + const QString& subResource, + Q_UINT32 sernum, + KMailICalIface::StorageFormat ) +{ + KABC::Addressee addr = Contact::fromXml( contactData ); + + addr.setResource( this ); + addr.setChanged( false ); + KABC::Resource::insertAddressee( addr ); // same as mAddrMap.insert( addr.uid(), addr ); + mUidMap[ addr.uid() ] = StorageReference( subResource, sernum ); + kdDebug(5650) << "Loaded contact uid=" << addr.uid() << " sernum=" << sernum << " fullName=" << addr.name() << endl; + return addr.uid(); +} + +bool KABC::ResourceScalix::loadSubResource( const QString& subResource ) +{ + bool scalixcontacts = loadSubResourceHelper( subResource, s_attachmentMimeTypeContact, KMailICalIface::StorageXML ); + bool scalixdistlists = loadSubResourceHelper( subResource, s_attachmentMimeTypeDistList, KMailICalIface::StorageXML ); + bool vcardstyle = loadSubResourceHelper( subResource, s_inlineMimeType, KMailICalIface::StorageIcalVcard ); + return scalixcontacts && scalixdistlists && vcardstyle; +} + +bool KABC::ResourceScalix::loadSubResourceHelper( const QString& subResource, + const char* mimetype, + KMailICalIface::StorageFormat format ) +{ + int count = 0; + if ( !kmailIncidencesCount( count, mimetype, subResource ) ) { + kdError() << "Communication problem in KABC::ResourceScalix::loadSubResourceHelper()\n"; + return false; + } + if ( !count ) + return true; + + // Read that many contacts at a time. + // If this number is too small we lose time in kmail. + // If it's too big the progressbar is jumpy. + const int nbMessages = 200; + + (void)Observer::self(); // ensure kio_uiserver is running + UIServer_stub uiserver( "kio_uiserver", "UIServer" ); + int progressId = 0; + if ( count > 200 ) { + progressId = uiserver.newJob( kapp->dcopClient()->appId(), true ); + uiserver.totalFiles( progressId, count ); + uiserver.infoMessage( progressId, i18n( "Loading contacts..." ) ); + uiserver.transferring( progressId, "Contacts" ); + } + + for ( int startIndex = 0; startIndex < count; startIndex += nbMessages ) { + QMap<Q_UINT32, QString> lst; + + if ( !kmailIncidences( lst, mimetype, subResource, startIndex, nbMessages ) ) { + kdError() << "Communication problem in ResourceScalix::load()\n"; + if ( progressId ) + uiserver.jobFinished( progressId ); + return false; + } + + for( QMap<Q_UINT32, QString>::ConstIterator it = lst.begin(); it != lst.end(); ++it ) { + loadContact( it.data(), subResource, it.key(), format ); + } + if ( progressId ) { + uiserver.processedFiles( progressId, startIndex ); + uiserver.percent( progressId, 100 * startIndex / count ); + } + } + + kdDebug(5650) << "Contacts scalix resource: got " << count << " contacts in " << subResource << endl; + + if ( progressId ) + uiserver.jobFinished( progressId ); + return true; +} + +bool KABC::ResourceScalix::load() +{ + mUidMap.clear(); + mAddrMap.clear(); + + bool rc = true; + Scalix::ResourceMap::ConstIterator itR; + for ( itR = mSubResources.begin(); itR != mSubResources.end(); ++itR ) { + if ( !itR.data().active() ) + // This resource is disabled + continue; + + rc &= loadSubResource( itR.key() ); + } + + return rc; +} + +bool KABC::ResourceScalix::save( Ticket* ) +{ + bool rc = true; + + for( ConstIterator it = begin(); it != end(); ++it ) + if( (*it).changed() ) { + rc &= kmailUpdateAddressee( *it ); + } + + if ( !rc ) + kdDebug(5650) << k_funcinfo << " failed." << endl; + return rc; +} + +namespace Scalix { +struct AttachmentList { + QStringList attachmentURLs; + QStringList attachmentNames; + QStringList attachmentMimeTypes; + QStringList deletedAttachments; + QValueList<KTempFile *> tempFiles; + + void addAttachment( const QString& url, const QString& name, const QString& mimetype ) { + attachmentURLs.append( url ); + attachmentNames.append( name ); + attachmentMimeTypes.append( mimetype ); + } + + void updatePictureAttachment( const QImage& image, const QString& name ); + void updateAttachment( const QByteArray& data, const QString& name, const char* mimetype ); +}; +} // namespace + +void AttachmentList::updatePictureAttachment( const QImage& image, const QString& name ) +{ + assert( !name.isEmpty() ); + if ( !image.isNull() ) { + KTempFile* tempFile = new KTempFile; + image.save( tempFile->file(), "PNG" ); + tempFile->close(); + KURL url; + url.setPath( tempFile->name() ); + kdDebug(5650) << "picture saved to " << url.path() << endl; + addAttachment( url.url(), name, "image/png" ); + } else { + deletedAttachments.append( name ); + } +} + +void AttachmentList::updateAttachment( const QByteArray& data, const QString& name, const char* mimetype ) +{ + assert( !name.isEmpty() ); + if ( !data.isNull() ) { + KTempFile* tempFile = new KTempFile; + tempFile->file()->writeBlock( data ); + tempFile->close(); + KURL url; + url.setPath( tempFile->name() ); + kdDebug(5650) << "data saved to " << url.path() << endl; + addAttachment( url.url(), name, mimetype ); + } else { + deletedAttachments.append( name ); + } +} + +bool KABC::ResourceScalix::kmailUpdateAddressee( const Addressee& addr ) +{ + const QString uid = addr.uid(); + QString subResource; + Q_UINT32 sernum; + if ( mUidMap.find( uid ) != mUidMap.end() ) { + subResource = mUidMap[ uid ].resource(); + if ( !subresourceWritable( subResource ) ) { + kdWarning() << "Wow! Something tried to update a non-writable addressee! Fix this caller: " << kdBacktrace() << endl; + return false; + } + sernum = mUidMap[ uid ].serialNumber(); + } else { + if ( !mCachedSubresource.isNull() ) { + subResource = mCachedSubresource; + } else { + subResource = findWritableResource( mSubResources ); + // We were locked, remember the subresource we are working with until + // we are unlocked + if ( mLocked ) + mCachedSubresource = subResource; + } + if ( subResource.isEmpty() ) + return false; + sernum = 0; + } + + AttachmentList att; + QString subject = addr.formattedName(); + + QString mimetype = s_inlineMimeType; + + QString data = Contact::toXml( addr ); + + CustomHeaderMap customHeaders; + customHeaders.insert( "X-Scalix-Class", "IPM.Contact" ); + + bool rc = kmailUpdate( subResource, sernum, data, mimetype, subject, + customHeaders, + att.attachmentURLs, att.attachmentMimeTypes, att.attachmentNames, + att.deletedAttachments ); + if ( !rc ) + kdDebug(5650) << "kmailUpdate returned false!" << endl; + if ( rc ) { + kdDebug(5650) << "kmailUpdate returned, now sernum=" << sernum << " for uid=" << uid << endl; + mUidMap[ uid ] = StorageReference( subResource, sernum ); + // This is ugly, but it's faster than doing + // mAddrMap.find(addr.uid()), which would give the same :-( + // Reason for this: The Changed attribute of Addressee should + // be mutable + const_cast<Addressee&>(addr).setChanged( false ); + } + + for( QValueList<KTempFile *>::Iterator it = att.tempFiles.begin(); it != att.tempFiles.end(); ++it ) { + (*it)->setAutoDelete( true ); + delete (*it); + } + return rc; +} + +void KABC::ResourceScalix::insertAddressee( const Addressee& addr ) +{ + const QString uid = addr.uid(); + //kdDebug(5650) << k_funcinfo << uid << endl; + bool ok = false; + if ( mUidMap.contains( uid ) ) { + mUidsPendingUpdate.append( uid ); + } else { + mUidsPendingAdding.append( uid ); + } + + ok = kmailUpdateAddressee( addr ); + + if ( ok ) + Resource::insertAddressee( addr ); +} + +void KABC::ResourceScalix::removeAddressee( const Addressee& addr ) +{ + const QString uid = addr.uid(); + if ( mUidMap.find( uid ) == mUidMap.end() ) return; + //kdDebug(5650) << k_funcinfo << uid << endl; + const QString resource = mUidMap[ uid ].resource(); + if ( !subresourceWritable( resource ) ) { + kdWarning() << "Wow! Something tried to delete a non-writable addressee! Fix this caller: " << kdBacktrace() << endl; + return; + } + /* The user told us to delete, tell KMail */ + kmailDeleteIncidence( resource, + mUidMap[ uid ].serialNumber() ); + mUidsPendingDeletion.append( uid ); + mUidMap.remove( uid ); + + Resource::removeAddressee( addr ); +} + +/* + * These are the DCOP slots that KMail call to notify when something + * changed. + */ +bool KABC::ResourceScalix::fromKMailAddIncidence( const QString& type, + const QString& subResource, + Q_UINT32 sernum, + int format, + const QString& contactXML ) +{ + // Check if this is a contact + if( type != s_kmailContentsType || !subresourceActive( subResource ) ) + return false; + + // Load contact to find the UID + const QString uid = loadContact( contactXML, subResource, sernum, + ( KMailICalIface::StorageFormat )format ); + + //kdDebug(5650) << k_funcinfo << uid << endl; + + // Emit "addressbook changed" if this comes from kmail and not from the GUI + if ( !mUidsPendingAdding.contains( uid ) + && !mUidsPendingUpdate.contains( uid ) ) { + addressBook()->emitAddressBookChanged(); + } else { + mUidsPendingAdding.remove( uid ); + mUidsPendingUpdate.remove( uid ); + } + + return true; +} + +void KABC::ResourceScalix::fromKMailDelIncidence( const QString& type, + const QString& subResource, + const QString& uid ) +{ + // Check if this is a contact + if( type != s_kmailContentsType || !subresourceActive( subResource ) ) + return; + + //kdDebug(5650) << k_funcinfo << uid << endl; + + // Can't be in both, by contract + if ( mUidsPendingDeletion.contains( uid ) ) { + mUidsPendingDeletion.remove( uid ); + } else if ( mUidsPendingUpdate.contains( uid ) ) { + // It's good to know if was deleted, but we are waiting on a new one to + // replace it, so let's just sit tight. + } else { + // We didn't trigger this, so KMail did, remove the reference to the uid + mAddrMap.remove( uid ); + mUidMap.remove( uid ); + addressBook()->emitAddressBookChanged(); + } +} + +void KABC::ResourceScalix::fromKMailRefresh( const QString& type, + const QString& /*subResource*/ ) +{ + // Check if this is a contact + if( type != s_kmailContentsType ) return; + + //kdDebug(5650) << k_funcinfo << endl; + + load(); // ### should call loadSubResource(subResource) probably + addressBook()->emitAddressBookChanged(); +} + +void KABC::ResourceScalix::fromKMailAddSubresource( const QString& type, + const QString& subResource, + const QString& label, + bool writable ) +{ + if( type != s_kmailContentsType ) return; + + if ( mSubResources.contains( subResource ) ) + // Already registered + return; + + KConfig config( configFile() ); + config.setGroup( "Contact" ); + loadSubResourceConfig( config, subResource, label, writable ); + loadSubResource( subResource ); + addressBook()->emitAddressBookChanged(); + emit signalSubresourceAdded( this, type, subResource ); +} + +void KABC::ResourceScalix::fromKMailDelSubresource( const QString& type, + const QString& subResource ) +{ + if( type != s_kmailContentsType ) return; + + if ( !mSubResources.contains( subResource ) ) + // Not registered + return; + + // Ok, it's our job, and we have it here + mSubResources.erase( subResource ); + + KConfig config( configFile() ); + config.deleteGroup( subResource ); + config.sync(); + + // Make a list of all uids to remove + Scalix::UidMap::ConstIterator mapIt; + QStringList uids; + for ( mapIt = mUidMap.begin(); mapIt != mUidMap.end(); ++mapIt ) + if ( mapIt.data().resource() == subResource ) + // We have a match + uids << mapIt.key(); + + // Finally delete all the incidences + if ( !uids.isEmpty() ) { + QStringList::ConstIterator it; + for ( it = uids.begin(); it != uids.end(); ++it ) { + mAddrMap.remove( *it ); + mUidMap.remove( *it ); + } + + addressBook()->emitAddressBookChanged(); + } + + emit signalSubresourceRemoved( this, type, subResource ); +} + + + +void KABC::ResourceScalix::fromKMailAsyncLoadResult( const QMap<Q_UINT32, QString>& map, + const QString& /* type */, + const QString& folder ) +{ + // FIXME + KMailICalIface::StorageFormat format = KMailICalIface::StorageXML; + for( QMap<Q_UINT32, QString>::ConstIterator it = map.begin(); it != map.end(); ++it ) { + loadContact( it.data(), folder, it.key(), format ); + } + if ( !addressBook() ){ + kdDebug(5650) << "asyncLoadResult() : addressBook() returning NULL pointer.\n"; + }else + addressBook()->emitAddressBookChanged(); +} + +QStringList KABC::ResourceScalix::subresources() const +{ + return mSubResources.keys(); +} + +bool KABC::ResourceScalix::subresourceActive( const QString& subresource ) const +{ + if ( mSubResources.contains( subresource ) ) { + return mSubResources[ subresource ].active(); + } + + // Safe default bet: + kdDebug(5650) << "subresourceActive( " << subresource << " ): Safe bet\n"; + + return true; +} + +bool KABC::ResourceScalix::subresourceWritable( const QString& subresource ) const +{ + if ( mSubResources.contains( subresource ) ) { + return mSubResources[ subresource ].writable(); + } + return false; //better a safe default +} + +int KABC::ResourceScalix::subresourceCompletionWeight( const QString& subresource ) const +{ + if ( mSubResources.contains( subresource ) ) { + return mSubResources[ subresource ].completionWeight(); + } + + kdDebug(5650) << "subresourceCompletionWeight( " << subresource << " ): not found, using default\n"; + + return 80; +} + +QString KABC::ResourceScalix::subresourceLabel( const QString& subresource ) const +{ + if ( mSubResources.contains( subresource ) ) { + return mSubResources[ subresource ].label(); + } + + kdDebug(5650) << "subresourceLabel( " << subresource << " ): not found!\n"; + return QString::null; +} + +void KABC::ResourceScalix::setSubresourceCompletionWeight( const QString& subresource, int completionWeight ) +{ + if ( mSubResources.contains( subresource ) ) { + mSubResources[ subresource ].setCompletionWeight( completionWeight ); + } else { + kdDebug(5650) << "setSubresourceCompletionWeight: subresource " << subresource << " not found" << endl; + } +} + +QMap<QString, QString> KABC::ResourceScalix::uidToResourceMap() const +{ + // TODO: Couldn't this be made simpler? + QMap<QString, QString> map; + Scalix::UidMap::ConstIterator mapIt; + for ( mapIt = mUidMap.begin(); mapIt != mUidMap.end(); ++mapIt ) + map[ mapIt.key() ] = mapIt.data().resource(); + return map; +} + +void KABC::ResourceScalix::setSubresourceActive( const QString &subresource, bool active ) +{ + if ( mSubResources.contains( subresource ) ) { + mSubResources[ subresource ].setActive( active ); + load(); + } else { + kdDebug(5650) << "setSubresourceCompletionWeight: subresource " << subresource << " not found" << endl; + } +} + +#include "resourcescalix.moc" diff --git a/kresources/scalix/kabc/resourcescalix.h b/kresources/scalix/kabc/resourcescalix.h new file mode 100644 index 000000000..10d3d8aa5 --- /dev/null +++ b/kresources/scalix/kabc/resourcescalix.h @@ -0,0 +1,170 @@ +/* + This file is part of the scalix resource - based on the kolab resource. + + Copyright (c) 2002 - 2004 Klar�lvdalens Datakonsult AB + + 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 KABC_RESOURCESCALIX_H +#define KABC_RESOURCESCALIX_H + +#include <libkdepim/resourceabc.h> +#include <dcopobject.h> +#include "../shared/resourcescalixbase.h" +#include "../shared/subresource.h" +#include <kmail/kmailicalIface.h> +#include <kdepimmacros.h> + +namespace KABC { + + class FormatPlugin; + +/** + * This class implements a KAddressBook resource that keeps its + * addresses in an Scalix folder in KMail (or other conforming email + * clients). + */ +class KDE_EXPORT ResourceScalix : public KPIM::ResourceABC, + public Scalix::ResourceScalixBase +{ + Q_OBJECT + +public: + /** + * Constructor + */ + ResourceScalix( const KConfig* ); + + /** + * Destructor. + */ + virtual ~ResourceScalix(); + + /** + * Open the contacts list + */ + virtual bool doOpen(); + + /** + * Request a ticket, you have to pass through save() to + * allow locking. + */ + virtual Ticket *requestSaveTicket(); + + /** + Releases the ticket previousely requested with requestSaveTicket(). + The resource has to remove its locks in this function. + */ + virtual void releaseSaveTicket( Ticket* ); + + /** + * Load all addressees to the addressbook + */ + virtual bool load(); + + /** + * Save all addressees to the addressbook. + * + * @param ticket The ticket you get by requestSaveTicket() + */ + virtual bool save( Ticket *ticket ); + + /** + Insert an addressee into the resource. + */ + virtual void insertAddressee( const Addressee& ); + + /** + * Removes a addressee from resource. This method is mainly + * used by record-based resources like LDAP or SQL. + */ + virtual void removeAddressee( const Addressee& addr ); + + // Listen to KMail changes in the amount of sub resources + void fromKMailAddSubresource( const QString& type, const QString& id, + const QString& label, bool writable ); + void fromKMailDelSubresource( const QString& type, const QString& id ); + + bool fromKMailAddIncidence( const QString& type, const QString& resource, + Q_UINT32 sernum, int format, const QString& contact ); + void fromKMailDelIncidence( const QString& type, const QString& resource, + const QString& contact ); + void fromKMailRefresh( const QString& type, const QString& resource ); + + void fromKMailAsyncLoadResult( const QMap<Q_UINT32, QString>& map, + const QString& type, + const QString& folder ); + + /// Return the list of subresources. + QStringList subresources() const; + + /// Is this subresource active? + bool subresourceActive( const QString& ) const; + /// Is this subresource writabel? + bool subresourceWritable( const QString& ) const; + + virtual void setSubresourceActive( const QString &, bool ); + + /// Completion weight for a given subresource + virtual int subresourceCompletionWeight( const QString& ) const; + + /// Label for a given subresource + virtual QString subresourceLabel( const QString& ) const; + + /// Set completion weight for a given subresource + virtual void setSubresourceCompletionWeight( const QString&, int ); + + /// Give the uidmap. Used for ordered searching + QMap<QString, QString> uidToResourceMap() const; + +protected: + bool kmailUpdateAddressee( const Addressee& ); + + void doClose(); + + void loadSubResourceConfig( KConfig& config, const QString& name, + const QString& label, bool writable ); + bool loadSubResource( const QString& subResource ); + bool loadSubResourceHelper( const QString& subResource, const char* mimetype, KMailICalIface::StorageFormat format ); + QString loadContact( const QString& contactData, const QString& subResource, + Q_UINT32 sernum, const KMailICalIface::StorageFormat format ); + + QString configFile() const { + return Scalix::ResourceScalixBase::configFile( "kabc" ); + } + + // The list of subresources + Scalix::ResourceMap mSubResources; + QString mCachedSubresource; + bool mLocked; +}; + +} + +#endif // KABC_RESOURCESCALIX_H diff --git a/kresources/scalix/kabc/resourcescalix_plugin.cpp b/kresources/scalix/kabc/resourcescalix_plugin.cpp new file mode 100644 index 000000000..95bc28beb --- /dev/null +++ b/kresources/scalix/kabc/resourcescalix_plugin.cpp @@ -0,0 +1,53 @@ +/* + This file is part of the scalix resource - based on the kolab resource. + + Copyright (c) 2002 - 2004 Klar�lvdalens Datakonsult AB + + 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 "resourcescalix.h" + +using namespace Scalix; + +class ScalixFactory : public KRES::PluginFactoryBase +{ + public: + KRES::Resource *resource( const KConfig *config ) + { + return new KABC::ResourceScalix( config ); + } + + KRES::ConfigWidget *configWidget( QWidget* ) + { + return 0; + } +}; + +K_EXPORT_COMPONENT_FACTORY(kabc_scalix,ScalixFactory) + diff --git a/kresources/scalix/kabc/scalix.desktop b/kresources/scalix/kabc/scalix.desktop new file mode 100644 index 000000000..b91af2470 --- /dev/null +++ b/kresources/scalix/kabc/scalix.desktop @@ -0,0 +1,30 @@ +[Desktop Entry] +Name=Addressbook on Scalix Server via KMail +Name[bg]=Адресник на сървъра Scalix през KMail +Name[ca]=Llibreta d'adreces en un servidor Scalix mitjançant el KMail +Name[da]=Adressebog på Scalix-server via KMail +Name[de]=Adressbuch auf einem Scalix-Server via KMail +Name[el]=Βιβλίο διευθύνσεων σε εξυπηρετητή Scalix μέσω του KMail +Name[es]=Libreta de direcciones en servidor Scalix por medio de KMail +Name[et]=Aadressiraamat Scalix-serveris (KMaili vahendusel) +Name[fr]=Carnet d'adresses sur serveur Scalix via KMail +Name[is]=Vistfangaskrá á Scalix-þjóni gegnum KMail +Name[it]=Rubrica indirizzi su server Scalix via KMail +Name[ja]=KMail 経由 Scalix サーバのアドレス帳 +Name[km]=សៀវភៅអាសយដ្ឋាននៅលើម៉ាស៊ីនបម្រើ Scalix តាមរយៈ KMail +Name[nds]=Adressbook op Scalix-Server över KMail +Name[nl]=Adresboek op Scalix-server via KMail +Name[pl]=Książka adresowa na serwerze Scalix za pośrednictwem KMaila +Name[ru]=Адресная книга на сервере Scalix через KMail +Name[sk]=Adresár na Scalix serveri pomocou KMail +Name[sr]=Адресар на Scalix серверу преко KMail-а +Name[sr@Latn]=Adresar na Scalix serveru preko KMail-a +Name[sv]=Adressbok på Scalix-server via Kmail +Name[tr]=KMail Aracılığı ile Scalix Sunucusunda Adres Defteri +Name[zh_CN]=通过 KMail 访问 Scalix 服务器上的地址簿 +Name[zh_TW]=透過 KMail 取得 Scalix 伺服器上的通訊錄 +X-KDE-Library=kabc_scalix +Type=Service +ServiceTypes=KResources/Plugin +X-KDE-ResourceFamily=contact +X-KDE-ResourceType=scalix diff --git a/kresources/scalix/kcal/Makefile.am b/kresources/scalix/kcal/Makefile.am new file mode 100644 index 000000000..060c5c00c --- /dev/null +++ b/kresources/scalix/kcal/Makefile.am @@ -0,0 +1,27 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/kresources/scalix/shared -I$(top_srcdir) \ + -I$(top_builddir)/libkdepim $(all_includes) + +# The scalix wizard links to this library too +lib_LTLIBRARIES = libkcalscalix.la + +libkcalscalix_la_SOURCES = resourcescalix.cpp +libkcalscalix_la_LDFLAGS = $(all_libraries) -no-undefined +libkcalscalix_la_LIBADD = $(top_builddir)/libkcal/libkcal.la \ + $(top_builddir)/kresources/scalix/shared/libresourcescalixshared.la \ + -lkresources + +kde_module_LTLIBRARIES = kcal_scalix.la + +kcal_scalix_la_SOURCES = resourcescalix_plugin.cpp +kcal_scalix_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) -no-undefined +kcal_scalix_la_LIBADD = libkcalscalix.la + +servicedir = $(kde_servicesdir)/kresources/kcal +service_DATA = scalix.desktop + +install-data-local: $(srcdir)/../uninstall.desktop + $(mkinstalldirs) $(DESTDIR)$(servicedir) + $(INSTALL_DATA) $(srcdir)/../uninstall.desktop $(DESTDIR)$(servicedir)/imap.desktop + diff --git a/kresources/scalix/kcal/resourcescalix.cpp b/kresources/scalix/kcal/resourcescalix.cpp new file mode 100644 index 000000000..9a8beeb9e --- /dev/null +++ b/kresources/scalix/kcal/resourcescalix.cpp @@ -0,0 +1,885 @@ +/* + This file is part of the scalix resource - based on the kolab resource. + + Copyright (c) 2004 Bo Thorsen <[email protected]> + 2004 Till Adam <[email protected]> + + 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 "resourcescalix.h" + +#include <kio/observer.h> +#include <kio/uiserver_stub.h> +#include <kapplication.h> +#include <dcopclient.h> +#include <libkcal/icalformat.h> +#include <libkdepim/kincidencechooser.h> +#include <kabc/locknull.h> +#include <kmainwindow.h> +#include <klocale.h> + +#include <qobject.h> +#include <qtimer.h> +#include <qapplication.h> + +#include <assert.h> + +using namespace KCal; +using namespace Scalix; + +static const char* kmailCalendarContentsType = "Calendar"; +static const char* kmailTodoContentsType = "Task"; +static const char* kmailJournalContentsType = "Journal"; +static const char* eventAttachmentMimeType = "application/x-vnd.kolab.event"; +static const char* todoAttachmentMimeType = "application/x-vnd.kolab.task"; +static const char* journalAttachmentMimeType = "application/x-vnd.kolab.journal"; +static const char* incidenceInlineMimeType = "text/calendar"; + + +ResourceScalix::ResourceScalix( const KConfig *config ) + : ResourceCalendar( config ), ResourceScalixBase( "ResourceScalix-libkcal" ), + mCalendar( QString::fromLatin1("UTC") ), mOpen( false ) +{ + setType( "scalix" ); + connect( &mResourceChangedTimer, SIGNAL( timeout() ), + this, SLOT( slotEmitResourceChanged() ) ); +} + +ResourceScalix::~ResourceScalix() +{ + // The resource is deleted on exit (StdAddressBook's KStaticDeleter), + // and it wasn't closed before that, so close here to save the config. + if ( mOpen ) { + close(); + } +} + +void ResourceScalix::loadSubResourceConfig( KConfig& config, + const QString& name, + const QString& label, + bool writable, + ResourceMap& subResource ) +{ + KConfigGroup group( &config, name ); + bool active = group.readBoolEntry( "Active", true ); + subResource.insert( name, Scalix::SubResource( active, writable, label ) ); +} + +bool ResourceScalix::openResource( KConfig& config, const char* contentType, + ResourceMap& map ) +{ + // Read the subresource entries from KMail + QValueList<KMailICalIface::SubResource> subResources; + if ( !kmailSubresources( subResources, contentType ) ) + return false; + map.clear(); + QValueList<KMailICalIface::SubResource>::ConstIterator it; + for ( it = subResources.begin(); it != subResources.end(); ++it ) + loadSubResourceConfig( config, (*it).location, (*it).label, (*it).writable, map ); + return true; +} + +bool ResourceScalix::doOpen() +{ + if ( mOpen ) + // Already open + return true; + mOpen = true; + + KConfig config( configFile() ); + config.setGroup( "General" ); + mProgressDialogIncidenceLimit = config.readNumEntry("ProgressDialogIncidenceLimit", 200); + + return openResource( config, kmailCalendarContentsType, mEventSubResources ) + && openResource( config, kmailTodoContentsType, mTodoSubResources ) + && openResource( config, kmailJournalContentsType, mJournalSubResources ); +} + +static void closeResource( KConfig& config, ResourceMap& map ) +{ + ResourceMap::ConstIterator it; + for ( it = map.begin(); it != map.end(); ++it ) { + config.setGroup( it.key() ); + config.writeEntry( "Active", it.data().active() ); + } +} + +void ResourceScalix::doClose() +{ + if ( !mOpen ) + // Not open + return; + mOpen = false; + + KConfig config( configFile() ); + closeResource( config, mEventSubResources ); + closeResource( config, mTodoSubResources ); + closeResource( config, mJournalSubResources ); +} + +bool ResourceScalix::loadSubResource( const QString& subResource, + const char* mimetype ) +{ + int count = 0; + if ( !kmailIncidencesCount( count, mimetype, subResource ) ) { + kdError(5650) << "Communication problem in ResourceScalix::load()\n"; + return false; + } + + if ( !count ) + return true; + + const int nbMessages = 200; // read 200 mails at a time (see kabc resource) + + const QString labelTxt = !strcmp(mimetype, "application/x-vnd.kolab.task") ? i18n( "Loading tasks..." ) + : !strcmp(mimetype, "application/x-vnd.kolab.journal") ? i18n( "Loading journals..." ) + : i18n( "Loading events..." ); + const bool useProgress = qApp && qApp->type() != QApplication::Tty && count > mProgressDialogIncidenceLimit; + if ( useProgress ) + (void)::Observer::self(); // ensure kio_uiserver is running + UIServer_stub uiserver( "kio_uiserver", "UIServer" ); + int progressId = 0; + if ( useProgress ) { + progressId = uiserver.newJob( kapp->dcopClient()->appId(), true ); + uiserver.totalFiles( progressId, count ); + uiserver.infoMessage( progressId, labelTxt ); + uiserver.transferring( progressId, labelTxt ); + } + + for ( int startIndex = 0; startIndex < count; startIndex += nbMessages ) { + QMap<Q_UINT32, QString> lst; + if ( !kmailIncidences( lst, mimetype, subResource, startIndex, nbMessages ) ) { + kdError(5650) << "Communication problem in ResourceScalix::load()\n"; + if ( progressId ) + uiserver.jobFinished( progressId ); + return false; + } + + { // for RAII scoping below + TemporarySilencer t( this ); + for( QMap<Q_UINT32, QString>::ConstIterator it = lst.begin(); it != lst.end(); ++it ) { + addIncidence( mimetype, it.data(), subResource, it.key() ); + } + } + if ( progressId ) { + uiserver.processedFiles( progressId, startIndex ); + uiserver.percent( progressId, 100 * startIndex / count ); + } + } + + if ( progressId ) + uiserver.jobFinished( progressId ); + return true; +} + +bool ResourceScalix::doLoad() +{ + mUidMap.clear(); + + return loadAllEvents() & loadAllTodos() & loadAllJournals(); +} + +bool ResourceScalix::doLoadAll( ResourceMap& map, const char* mimetype ) +{ + bool rc = true; + for ( ResourceMap::ConstIterator it = map.begin(); it != map.end(); ++it ) { + if ( !it.data().active() ) + // This resource is disabled + continue; + + rc &= loadSubResource( it.key(), mimetype ); + } + return rc; +} + +bool ResourceScalix::loadAllEvents() +{ + removeIncidences( "Event" ); + mCalendar.deleteAllEvents(); + return doLoadAll( mEventSubResources, incidenceInlineMimeType ); +} + +bool ResourceScalix::loadAllTodos() +{ + removeIncidences( "Todo" ); + mCalendar.deleteAllTodos(); + return doLoadAll( mTodoSubResources, incidenceInlineMimeType ); +} + +bool ResourceScalix::loadAllJournals() +{ + removeIncidences( "Journal" ); + mCalendar.deleteAllJournals(); + return doLoadAll( mJournalSubResources, incidenceInlineMimeType ); +} + +void ResourceScalix::removeIncidences( const QCString& incidenceType ) +{ + Scalix::UidMap::Iterator mapIt = mUidMap.begin(); + while ( mapIt != mUidMap.end() ) + { + Scalix::UidMap::Iterator it = mapIt++; + // Check the type of this uid: event, todo or journal. + // Need to look up in mCalendar for that. Given the implementation of incidence(uid), + // better call event(uid), todo(uid) etc. directly. + + // A faster but hackish way would probably be to check the type of the resource, + // like mEventSubResources.find( it.data().resource() ) != mEventSubResources.end() ? + const QString& uid = it.key(); + if ( incidenceType == "Event" && mCalendar.event( uid ) ) + mUidMap.remove( it ); + else if ( incidenceType == "Todo" && mCalendar.todo( uid ) ) + mUidMap.remove( it ); + else if ( incidenceType == "Journal" && mCalendar.journal( uid ) ) + mUidMap.remove( it ); + } +} + +bool ResourceScalix::doSave() +{ + return true; +} + +void ResourceScalix::incidenceUpdated( KCal::IncidenceBase* incidencebase ) +{ + if ( incidencebase->isReadOnly() ) return; // Should not happen (TM) + incidencebase->setSyncStatus( KCal::Event::SYNCMOD ); + incidencebase->setLastModified( QDateTime::currentDateTime() ); + // we should probably update the revision number here, + // or internally in the Event itself when certain things change. + // need to verify with ical documentation. + + const QString uid = incidencebase->uid(); + + if ( mUidsPendingUpdate.contains( uid ) || mUidsPendingAdding.contains( uid ) ) { + /* We are currently processing this event ( removing and readding or + * adding it ). If so, ignore this update. Keep the last of these around + * and process once we hear back from KMail on this event. */ + mPendingUpdates.replace( uid, incidencebase ); + return; + } + + QString subResource; + Q_UINT32 sernum = 0; + if ( mUidMap.contains( uid ) ) { + subResource = mUidMap[ uid ].resource(); + sernum = mUidMap[ uid ].serialNumber(); + mUidsPendingUpdate.append( uid ); + } + sendKMailUpdate( incidencebase, subResource, sernum ); +} + +void ResourceScalix::resolveConflict( KCal::Incidence* inc, const QString& subresource, Q_UINT32 sernum ) +{ + if ( ! inc ) + return; + if ( ! mResolveConflict ) { + // we should do no conflict resolution + delete inc; + return; + } + Incidence* local = mCalendar.incidence( inc->uid() ); + Incidence* localIncidence = 0; + Incidence* addedIncidence = 0; + if ( local ) { + KIncidenceChooser* ch = new KIncidenceChooser(); + ch->setIncidence( local ,inc ); + if ( KIncidenceChooser::chooseMode == KIncidenceChooser::ask ) { + connect ( this, SIGNAL( useGlobalMode() ), ch, SLOT ( useGlobalMode() ) ); + if ( ch->exec() ) + if ( KIncidenceChooser::chooseMode != KIncidenceChooser::ask ) + emit useGlobalMode() ; + } + Incidence* result = ch->getIncidence(); + delete ch; + if ( result == local ) { + localIncidence = local->clone(); + delete inc; + } else if ( result == inc ) { + addedIncidence = inc; + } else if ( result == 0 ) { // take both + localIncidence = local->clone(); + localIncidence->recreate(); + localIncidence->setSummary( i18n("Copy of: %1").arg(localIncidence->summary()) ); + addedIncidence = inc; + } + bool silent = mSilent; + mSilent = false; + deleteIncidence( local ); // remove local from kmail + kmailDeleteIncidence( subresource, sernum );// remove new from kmail + if ( localIncidence ) { + addIncidence( localIncidence, subresource, 0 ); + mUidsPendingAdding.remove( localIncidence->uid() ); // we do want to inform KOrg also + } + if ( addedIncidence ) { + addIncidence( addedIncidence, subresource, 0 ); + mUidsPendingAdding.remove( addedIncidence->uid() ); // we do want to inform KOrg also + } + mSilent = silent; + } +} +void ResourceScalix::addIncidence( const char* mimetype, const QString& data, + const QString& subResource, Q_UINT32 sernum ) +{ + // This uses pointer comparison, so it only works if we use the static + // objects defined in the top of the file + Incidence *inc = mFormat.fromString( data ); + addIncidence( inc, subResource, sernum ); +} + + +bool ResourceScalix::sendKMailUpdate( KCal::IncidenceBase* incidencebase, const QString& subresource, + Q_UINT32 sernum ) +{ + const QString& type = incidencebase->type(); + const char* mimetype = 0; + QString data; + if ( type == "Event" ) { + mimetype = incidenceInlineMimeType; + data = mFormat.createScheduleMessage( static_cast<KCal::Event *>(incidencebase), + Scheduler::Publish ); + } else if ( type == "Todo" ) { + mimetype = incidenceInlineMimeType; + data = mFormat.createScheduleMessage( static_cast<KCal::Todo *>(incidencebase), + Scheduler::Publish ); + } else if ( type == "Journal" ) { + mimetype = incidenceInlineMimeType; + data = mFormat.createScheduleMessage( static_cast<KCal::Journal *>(incidencebase), + Scheduler::Publish ); + } else { + kdWarning(5006) << "Can't happen: unhandled type=" << type << endl; + } + +// kdDebug() << k_funcinfo << "Data string:\n" << data << endl; + + KCal::Incidence* incidence = static_cast<KCal::Incidence *>( incidencebase ); + CustomHeaderMap customHeaders; + + if ( type == "Event" ) + customHeaders.insert( "X-Scalix-Class", "IPM.Appointment" ); + else if ( type == "Todo" ) + customHeaders.insert( "X-Scalix-Class", "IPM.Task" ); + + QString subject = incidence->summary(); + + // behold, sernum is an in-parameter + const bool rc = kmailUpdate( subresource, sernum, data, mimetype, subject, customHeaders ); + // update the serial number + if ( mUidMap.contains( incidencebase->uid() ) ) { + mUidMap[ incidencebase->uid() ].setSerialNumber( sernum ); + } + return rc; +} + +bool ResourceScalix::addIncidence( KCal::Incidence* incidence, const QString& _subresource, + Q_UINT32 sernum ) +{ + Q_ASSERT( incidence ); + if ( !incidence ) return false; + const QString &uid = incidence->uid(); + QString subResource = _subresource; + + Scalix::ResourceMap *map = &mEventSubResources; // don't use a ref here! + + const QString& type = incidence->type(); + if ( type == "Event" ) + map = &mEventSubResources; + else if ( type == "Todo" ) + map = &mTodoSubResources; + else if ( type == "Journal" ) + map = &mJournalSubResources; + else + kdWarning() << "unknown type " << type << endl; + + if ( !mSilent ) { /* We got this one from the user, tell KMail. */ + // Find out if this event was previously stored in KMail + bool newIncidence = _subresource.isEmpty(); + if ( newIncidence ) { + subResource = findWritableResource( *map ); + } + + if ( subResource.isEmpty() ) + return false; + + mNewIncidencesMap.insert( uid, subResource ); + + if ( !sendKMailUpdate( incidence, subResource, sernum ) ) { + kdError(5650) << "Communication problem in ResourceScalix::addIncidence()\n"; + return false; + } else { + // KMail is doing it's best to add the event now, put a sticker on it, + // so we know it's one of our transient ones + mUidsPendingAdding.append( uid ); + + /* Add to the cache immediately if this is a new event coming from + * KOrganizer. It relies on the incidence being in the calendar when + * addIncidence returns. */ + if ( newIncidence ) { + mCalendar.addIncidence( incidence ); + incidence->registerObserver( this ); + } + } + } else { /* KMail told us */ + bool ourOwnUpdate = false; + /* Check if we updated this one, which means kmail deleted and added it. + * We know the new state, so lets just not do much at all. The old incidence + * in the calendar remains valid, but the serial number changed, so we need to + * update that */ + if ( ourOwnUpdate = mUidsPendingUpdate.contains( uid ) ) { + mUidsPendingUpdate.remove( uid ); + mUidMap.remove( uid ); + mUidMap[ uid ] = StorageReference( subResource, sernum ); + } else { + /* This is a real add, from KMail, we didn't trigger this ourselves. + * If this uid already exists in this folder, do conflict resolution, + * unless the folder is read-only, in which case the user should not be + * offered a means of putting mails in a folder she'll later be unable to + * upload. Skip the incidence, in this case. */ + if ( mUidMap.contains( uid ) + && ( mUidMap[ uid ].resource() == subResource ) ) { + if ( (*map)[ subResource ].writable() ) { + resolveConflict( incidence, subResource, sernum ); + } else { + kdWarning( 5650 ) << "Duplicate event in a read-only folder detected! " + "Please inform the owner of the folder. " << endl; + } + return true; + } + /* Add to the cache if the add didn't come from KOrganizer, in which case + * we've already added it, and listen to updates from KOrganizer for it. */ + if ( !mUidsPendingAdding.contains( uid ) ) { + mCalendar.addIncidence( incidence ); + incidence->registerObserver( this ); + } + if ( !subResource.isEmpty() && sernum != 0 ) { + mUidMap[ uid ] = StorageReference( subResource, sernum ); + incidence->setReadOnly( !(*map)[ subResource ].writable() ); + } + } + /* Check if there are updates for this uid pending and if so process them. */ + if ( KCal::IncidenceBase *update = mPendingUpdates.find( uid ) ) { + mSilent = false; // we do want to tell KMail + mPendingUpdates.remove( uid ); + incidenceUpdated( update ); + } else { + /* If the uid was added by KMail, KOrganizer needs to be told, so + * schedule emitting of the resourceChanged signal. */ + if ( !mUidsPendingAdding.contains( uid ) ) { + if ( !ourOwnUpdate ) mResourceChangedTimer.changeInterval( 100 ); + } else { + mUidsPendingAdding.remove( uid ); + } + } + + mNewIncidencesMap.remove( uid ); + } + return true; +} + + +bool ResourceScalix::addEvent( KCal::Event* event ) +{ + if ( mUidMap.contains( event->uid() ) ) + return true; //noop + else + return addIncidence( event, QString::null, 0 ); +} + +bool ResourceScalix::deleteIncidence( KCal::Incidence* incidence ) +{ + if ( incidence->isReadOnly() ) return false; + + const QString uid = incidence->uid(); + if( !mUidMap.contains( uid ) ) return false; // Odd + /* The user told us to delete, tell KMail */ + if ( !mSilent ) { + kmailDeleteIncidence( mUidMap[ uid ].resource(), + mUidMap[ uid ].serialNumber() ); + mUidsPendingDeletion.append( uid ); + incidence->unRegisterObserver( this ); + mCalendar.deleteIncidence( incidence ); + mUidMap.remove( uid ); + } else { + assert( false ); // If this still happens, something is very wrong + } + return true; +} + +bool ResourceScalix::deleteEvent( KCal::Event* event ) +{ + return deleteIncidence( event ); +} + +KCal::Event* ResourceScalix::event( const QString& uid ) +{ + return mCalendar.event(uid); +} + +KCal::Event::List ResourceScalix::rawEvents( EventSortField sortField, SortDirection sortDirection ) +{ + return mCalendar.rawEvents( sortField, sortDirection ); +} + +KCal::Event::List ResourceScalix::rawEventsForDate( const QDate& date, + EventSortField sortField, + SortDirection sortDirection ) +{ + return mCalendar.rawEventsForDate( date, sortField, sortDirection ); +} + +KCal::Event::List ResourceScalix::rawEventsForDate( const QDateTime& qdt ) +{ + return mCalendar.rawEventsForDate( qdt ); +} + +KCal::Event::List ResourceScalix::rawEvents( const QDate& start, + const QDate& end, + bool inclusive ) +{ + return mCalendar.rawEvents( start, end, inclusive ); +} + +bool ResourceScalix::addTodo( KCal::Todo* todo ) +{ + if ( mUidMap.contains( todo->uid() ) ) + return true; //noop + else + return addIncidence( todo, QString::null, 0 ); +} + +bool ResourceScalix::deleteTodo( KCal::Todo* todo ) +{ + return deleteIncidence( todo ); +} + +KCal::Todo* ResourceScalix::todo( const QString& uid ) +{ + return mCalendar.todo( uid ); +} + +KCal::Todo::List ResourceScalix::rawTodos( TodoSortField sortField, SortDirection sortDirection ) +{ + return mCalendar.rawTodos( sortField, sortDirection ); +} + +KCal::Todo::List ResourceScalix::rawTodosForDate( const QDate& date ) +{ + return mCalendar.rawTodosForDate( date ); +} + +bool ResourceScalix::addJournal( KCal::Journal* journal ) +{ + if ( mUidMap.contains( journal->uid() ) ) + return true; //noop + else + return addIncidence( journal, QString::null, 0 ); +} + +bool ResourceScalix::deleteJournal( KCal::Journal* journal ) +{ + return deleteIncidence( journal ); +} + +KCal::Journal* ResourceScalix::journal( const QString& uid ) +{ + return mCalendar.journal(uid); +} + +KCal::Journal::List ResourceScalix::rawJournals( JournalSortField sortField, SortDirection sortDirection ) +{ + return mCalendar.rawJournals( sortField, sortDirection ); +} + +KCal::Journal::List ResourceScalix::rawJournalsForDate( const QDate &date ) +{ + return mCalendar.rawJournalsForDate( date ); +} + +KCal::Alarm::List ResourceScalix::alarms( const QDateTime& from, + const QDateTime& to ) +{ + return mCalendar.alarms( from, to ); +} + +KCal::Alarm::List ResourceScalix::alarmsTo( const QDateTime& to ) +{ + return mCalendar.alarmsTo(to); +} + +void ResourceScalix::setTimeZoneId( const QString& tzid ) +{ + mCalendar.setTimeZoneId( tzid ); + mFormat.setTimeZone( mCalendar.timeZoneId(), !mCalendar.isLocalTime() ); +} + +bool ResourceScalix::fromKMailAddIncidence( const QString& type, + const QString& subResource, + Q_UINT32 sernum, + int /*format*/, + const QString& data ) +{ + bool rc = true; + TemporarySilencer t( this ); // RAII + if ( type != kmailCalendarContentsType && type != kmailTodoContentsType + && type != kmailJournalContentsType ) + // Not ours + return false; + if ( !subresourceActive( subResource ) ) return true; + + Incidence *inc = mFormat.fromString( data ); + if ( !inc ) + rc = false; + else + addIncidence( inc, subResource, sernum ); + + return rc; +} + +void ResourceScalix::fromKMailDelIncidence( const QString& type, + const QString& subResource, + const QString& uid ) +{ + if ( type != kmailCalendarContentsType && type != kmailTodoContentsType + && type != kmailJournalContentsType ) + // Not ours + return; + if ( !subresourceActive( subResource ) ) return; + + // Can't be in both, by contract + if ( mUidsPendingDeletion.contains( uid ) ) { + mUidsPendingDeletion.remove( uid ); + } else if ( mUidsPendingUpdate.contains( uid ) ) { + // It's good to know if was deleted, but we are waiting on a new one to + // replace it, so let's just sit tight. + } else { + // We didn't trigger this, so KMail did, remove the reference to the uid + KCal::Incidence* incidence = mCalendar.incidence( uid ); + if( incidence ) { + incidence->unRegisterObserver( this ); + mCalendar.deleteIncidence( incidence ); + } + mUidMap.remove( uid ); + mResourceChangedTimer.changeInterval( 100 ); + } +} + +void ResourceScalix::fromKMailRefresh( const QString& type, + const QString& /*subResource*/ ) +{ + // TODO: Only load the specified subResource + if ( type == "Calendar" ) + loadAllEvents(); + else if ( type == "Task" ) + loadAllTodos(); + else if ( type == "Journal" ) + loadAllJournals(); + else + kdWarning(5006) << "KCal Scalix resource: fromKMailRefresh: unknown type " << type << endl; + mResourceChangedTimer.changeInterval( 100 ); +} + +void ResourceScalix::fromKMailAddSubresource( const QString& type, + const QString& subResource, + const QString& label, + bool writable ) +{ + ResourceMap* map = 0; + const char* mimetype = 0; + if ( type == kmailCalendarContentsType ) { + map = &mEventSubResources; + mimetype = eventAttachmentMimeType; + } else if ( type == kmailTodoContentsType ) { + map = &mTodoSubResources; + mimetype = todoAttachmentMimeType; + } else if ( type == kmailJournalContentsType ) { + map = &mJournalSubResources; + mimetype = journalAttachmentMimeType; + } else + // Not ours + return; + + if ( map->contains( subResource ) ) + // Already registered + return; + + KConfig config( configFile() ); + config.setGroup( subResource ); + + bool active = config.readBoolEntry( subResource, true ); + (*map)[ subResource ] = Scalix::SubResource( active, writable, label ); + loadSubResource( subResource, mimetype ); + emit signalSubresourceAdded( this, type, subResource, label ); +} + +void ResourceScalix::fromKMailDelSubresource( const QString& type, + const QString& subResource ) +{ + ResourceMap* map = subResourceMap( type ); + if ( !map ) // not ours + return; + if ( map->contains( subResource ) ) + map->erase( subResource ); + else + // Not registered + return; + + // Delete from the config file + KConfig config( configFile() ); + config.deleteGroup( subResource ); + config.sync(); + + // Make a list of all uids to remove + Scalix::UidMap::ConstIterator mapIt; + QStringList uids; + for ( mapIt = mUidMap.begin(); mapIt != mUidMap.end(); ++mapIt ) + if ( mapIt.data().resource() == subResource ) + // We have a match + uids << mapIt.key(); + + // Finally delete all the incidences + if ( !uids.isEmpty() ) { + TemporarySilencer t( this ); + QStringList::ConstIterator it; + for ( it = uids.begin(); it != uids.end(); ++it ) { + KCal::Incidence* incidence = mCalendar.incidence( *it ); + if( incidence ) + mCalendar.deleteIncidence( incidence ); + mUidMap.remove( *it ); + } + } + + emit signalSubresourceRemoved( this, type, subResource ); +} + +QStringList ResourceScalix::subresources() const +{ + // Workaround: The ResourceView in KOrganizer wants to know this + // before it opens the resource :-( Make sure we are open + const_cast<ResourceScalix*>( this )->doOpen(); + return ( mEventSubResources.keys() + + mTodoSubResources.keys() + + mJournalSubResources.keys() ); +} + +const QString +ResourceScalix::labelForSubresource( const QString& subresource ) const +{ + if ( mEventSubResources.contains( subresource ) ) + return mEventSubResources[ subresource ].label(); + if ( mTodoSubResources.contains( subresource ) ) + return mTodoSubResources[ subresource ].label(); + if ( mJournalSubResources.contains( subresource ) ) + return mJournalSubResources[ subresource ].label(); + return subresource; +} + +QString ResourceScalix::subresourceIdentifier( Incidence *incidence ) +{ + QString uid = incidence->uid(); + if ( mUidMap.contains( uid ) ) + return mUidMap[ uid ].resource(); + else + if ( mNewIncidencesMap.contains( uid ) ) + return mNewIncidencesMap[ uid ]; + else + return QString(); +} + +void ResourceScalix::fromKMailAsyncLoadResult( const QMap<Q_UINT32, QString>& map, + const QString& type, + const QString& folder ) +{ + TemporarySilencer t( this ); + for( QMap<Q_UINT32, QString>::ConstIterator it = map.begin(); it != map.end(); ++it ) + addIncidence( type.latin1(), it.data(), folder, it.key() ); +} + +bool ResourceScalix::subresourceActive( const QString& subresource ) const +{ + // Workaround: The ResourceView in KOrganizer wants to know this + // before it opens the resource :-( Make sure we are open + const_cast<ResourceScalix*>( this )->doOpen(); + + if ( mEventSubResources.contains( subresource ) ) + return mEventSubResources[ subresource ].active(); + if ( mTodoSubResources.contains( subresource ) ) + return mTodoSubResources[ subresource ].active(); + if ( mJournalSubResources.contains( subresource ) ) + return mJournalSubResources[ subresource ].active(); + + // Safe default bet: + kdDebug(5650) << "subresourceActive( " << subresource << " ): Safe bet\n"; + + return true; +} + +void ResourceScalix::setSubresourceActive( const QString &subresource, bool v ) +{ + ResourceMap *map = 0; + + if ( mEventSubResources.contains( subresource ) ) + map = &mEventSubResources; + if ( mTodoSubResources.contains( subresource ) ) + map = &mTodoSubResources; + if ( mJournalSubResources.contains( subresource ) ) + map = &mJournalSubResources; + + if ( map && ( ( *map )[ subresource ].active() != v ) ) { + ( *map )[ subresource ].setActive( v ); + doLoad(); // refresh the mCalendar cache + mResourceChangedTimer.changeInterval( 100 ); + } +} + +void ResourceScalix::slotEmitResourceChanged() +{ + kdDebug(5650) << "KCal Scalix resource: emitting resource changed " << endl; + mResourceChangedTimer.stop(); + emit resourceChanged( this ); +} + +KABC::Lock* ResourceScalix::lock() +{ + return new KABC::LockNull( true ); +} + + +Scalix::ResourceMap* ResourceScalix::subResourceMap( const QString& contentsType ) +{ + if ( contentsType == kmailCalendarContentsType ) { + return &mEventSubResources; + } else if ( contentsType == kmailTodoContentsType ) { + return &mTodoSubResources; + } else if ( contentsType == kmailJournalContentsType ) { + return &mJournalSubResources; + } + // Not ours + return 0; +} + +#include "resourcescalix.moc" diff --git a/kresources/scalix/kcal/resourcescalix.h b/kresources/scalix/kcal/resourcescalix.h new file mode 100644 index 000000000..0c845a6ce --- /dev/null +++ b/kresources/scalix/kcal/resourcescalix.h @@ -0,0 +1,221 @@ +/* + This file is part of the scalix resource - based on the kolab resource. + + Copyright (c) 2004 Bo Thorsen <[email protected]> + 2004 Till Adam <[email protected]> + + 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 KCAL_RESOURCESCALIX_H +#define KCAL_RESOURCESCALIX_H + +#include <qtimer.h> + +#include <kdepimmacros.h> +#include <libkcal/calendarlocal.h> +#include <libkcal/icalformat.h> +#include <libkcal/resourcecalendar.h> +#include "../shared/resourcescalixbase.h" + +namespace KCal { + +struct TemporarySilencer; + +class KDE_EXPORT ResourceScalix : public KCal::ResourceCalendar, + public KCal::IncidenceBase::Observer, + public Scalix::ResourceScalixBase +{ + Q_OBJECT + friend struct TemporarySilencer; + +public: + ResourceScalix( const KConfig* ); + virtual ~ResourceScalix(); + + /// Load resource data. + bool doLoad(); + + /// Save resource data. + bool doSave(); + + /// Open the notes resource. + bool doOpen(); + /// Close the notes resource. + void doClose(); + + // The libkcal functions. See the resource for descriptions + bool addEvent( KCal::Event* anEvent ); + bool deleteEvent( KCal::Event* ); + KCal::Event* event( const QString &UniqueStr ); + KCal::Event::List rawEvents( EventSortField sortField = EventSortUnsorted, SortDirection sortDirection = SortDirectionAscending ); + KCal::Event::List rawEventsForDate( + const QDate& date, + EventSortField sortField=EventSortUnsorted, + SortDirection sortDirection=SortDirectionAscending ); + KCal::Event::List rawEventsForDate( const QDateTime& qdt ); + KCal::Event::List rawEvents( const QDate& start, const QDate& end, + bool inclusive = false ); + + bool addTodo( KCal::Todo* todo ); + bool deleteTodo( KCal::Todo* ); + KCal::Todo* todo( const QString& uid ); + KCal::Todo::List rawTodos( TodoSortField sortField = TodoSortUnsorted, SortDirection sortDirection = SortDirectionAscending ); + KCal::Todo::List rawTodosForDate( const QDate& date ); + + bool addJournal( KCal::Journal* ); + bool deleteJournal( KCal::Journal* ); + KCal::Journal* journal( const QString& uid ); + KCal::Journal::List rawJournals( JournalSortField sortField = JournalSortUnsorted, SortDirection sortDirection = SortDirectionAscending ); + KCal::Journal::List rawJournalsForDate( const QDate &date ); + + KCal::Alarm::List alarms( const QDateTime& from, const QDateTime& to ); + KCal::Alarm::List alarmsTo( const QDateTime& to ); + + void setTimeZoneId( const QString& tzid ); + + bool deleteIncidence( KCal::Incidence* i ); + + /// The ResourceScalixBase methods called by KMail + bool fromKMailAddIncidence( const QString& type, const QString& subResource, + Q_UINT32 sernum, int format, const QString& data ); + void fromKMailDelIncidence( const QString& type, const QString& subResource, + const QString& uid ); + void fromKMailRefresh( const QString& type, const QString& subResource ); + + /// Listen to KMail changes in the amount of sub resources + void fromKMailAddSubresource( const QString& type, const QString& subResource, + const QString& label, bool writable ); + void fromKMailDelSubresource( const QString& type, const QString& subResource ); + + void fromKMailAsyncLoadResult( const QMap<Q_UINT32, QString>& map, + const QString& type, + const QString& folder ); + + /** Return the list of subresources. */ + QStringList subresources() const; + + /** Is this subresource active? */ + bool subresourceActive( const QString& ) const; + /** (De)activate the subresource */ + virtual void setSubresourceActive( const QString &, bool ); + + /** What is the label for this subresource? */ + virtual const QString labelForSubresource( const QString& resource ) const; + + virtual QString subresourceIdentifier( Incidence *incidence ); + + KABC::Lock* lock(); + +signals: + void useGlobalMode(); +protected slots: + void slotEmitResourceChanged(); + +private: + void removeIncidences( const QCString& incidenceType ); + void resolveConflict( KCal::Incidence*, const QString& subresource, Q_UINT32 sernum ); + + void addIncidence( const char* mimetype, const QString& xml, + const QString& subResource, Q_UINT32 sernum ); + + bool addIncidence( KCal::Incidence* i, const QString& subresource, + Q_UINT32 sernum ); +/* + void addEvent( const QString& xml, const QString& subresource, + Q_UINT32 sernum ); + void addTodo( const QString& xml, const QString& subresource, + Q_UINT32 sernum ); + void addJournal( const QString& xml, const QString& subresource, + Q_UINT32 sernum ); +*/ + + bool loadAllEvents(); + bool loadAllTodos(); + bool loadAllJournals(); + + bool doLoadAll( Scalix::ResourceMap& map, const char* mimetype ); + + /// Reimplemented from IncidenceBase::Observer to know when an incidence was changed + void incidenceUpdated( KCal::IncidenceBase* ); + + bool openResource( KConfig& config, const char* contentType, + Scalix::ResourceMap& map ); + void loadSubResourceConfig( KConfig& config, const QString& name, + const QString& label, bool writable, + Scalix::ResourceMap& subResource ); + bool loadSubResource( const QString& subResource, const char* mimetype ); + + QString configFile() const { + return ResourceScalixBase::configFile( "kcal" ); + } + + Scalix::ResourceMap* subResourceMap( const QString& contentsType ); + + bool sendKMailUpdate( KCal::IncidenceBase* incidence, const QString& _subresource, + Q_UINT32 sernum ); + + + KCal::CalendarLocal mCalendar; + + // The list of subresources + Scalix::ResourceMap mEventSubResources, mTodoSubResources, mJournalSubResources; + + bool mOpen; // If the resource is open, this is true + QDict<KCal::IncidenceBase> mPendingUpdates; + QTimer mResourceChangedTimer; + ICalFormat mFormat; + + /** + This map contains the association between a new added incidence + and the subresource it belongs to. + That's needed to return the correct mapping in subresourceIdentifier(). + + We can't trust on mUidMap here, because it contains only non-pending uids. + */ + QMap<QString, QString> mNewIncidencesMap; + int mProgressDialogIncidenceLimit; +}; + +struct TemporarySilencer { + TemporarySilencer( ResourceScalix *_resource ) + { + resource = _resource; + oldValue = resource->mSilent; + resource->mSilent = true; + } + ~TemporarySilencer() + { + resource->mSilent = oldValue; + } + ResourceScalix *resource; + bool oldValue; +}; + +} + +#endif // KCAL_RESOURCESCALIX_H diff --git a/kresources/scalix/kcal/resourcescalix_plugin.cpp b/kresources/scalix/kcal/resourcescalix_plugin.cpp new file mode 100644 index 000000000..53ac6705f --- /dev/null +++ b/kresources/scalix/kcal/resourcescalix_plugin.cpp @@ -0,0 +1,50 @@ +/* + This file is part of the scalix resource - based on the kolab resource. + + Copyright (c) 2002 - 2004 Klar�lvdalens Datakonsult AB + + 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 "resourcescalix.h" + +class ScalixFactory : public KRES::PluginFactoryBase +{ +public: + KRES::Resource *resource( const KConfig *config ) + { + return new KCal::ResourceScalix( config ); + } + + KRES::ConfigWidget *configWidget( QWidget* ) + { + return 0; + } +}; + +K_EXPORT_COMPONENT_FACTORY(kcal_scalix,ScalixFactory) diff --git a/kresources/scalix/kcal/scalix.desktop b/kresources/scalix/kcal/scalix.desktop new file mode 100644 index 000000000..1c468cca4 --- /dev/null +++ b/kresources/scalix/kcal/scalix.desktop @@ -0,0 +1,31 @@ +[Desktop Entry] +Name=Calendar on Scalix Server via KMail +Name[bg]=Календар на сървъра Scalix през KMail +Name[ca]=Calendari en un servidor Scalix mitjançant el KMail +Name[da]=Kalender på Scalix-server via KMail +Name[de]=Kalender auf einem Scalix-Server via KMail +Name[el]=Ημερολόγιο σε εξυπηρετητή Scalix μέσω του KMail +Name[es]=Calendario en servidor Scalix por medio de KMail +Name[et]=Kalender Scalix-serveris (KMaili vahendusel) +Name[fr]=Agenda sur serveur Scalix via KMail +Name[is]=Dagatal á Scalix-þjóni gegnum KMail +Name[it]=Calendario su server Scalix via KMail +Name[ja]=KMail 経由 Scalix サーバのカレンダー +Name[km]=ប្រតិទិននៅលើម៉ាស៊ីនបម្រើ Scalix តាមរយៈ KMail +Name[nds]=Kalenner op Scalix-Server över KMail +Name[nl]=Agenda op Scalix-server via KMail +Name[pl]=Kalendarz na serwerze Scalix za pośrednictwem KMaila +Name[pt_BR]=Calendário em Servidor Scalix via KMail +Name[ru]=Календарь на сервере Scalix через KMail +Name[sk]=Kalendár na Scalix serveri pomocou KMail +Name[sr]=Календар на Scalix серверу преко KMail-а +Name[sr@Latn]=Kalendar na Scalix serveru preko KMail-a +Name[sv]=Kalender på Scalix-server via Kmail +Name[tr]=KMail Aracılığı ile Scalix Sunucusunda Takvim +Name[zh_CN]=通过 KMail 访问 Scalix 服务器上的日历 +Name[zh_TW]=透過 KMail 取得 Scalix 伺服器上的行事曆 +X-KDE-Library=kcal_scalix +Type=Service +ServiceTypes=KResources/Plugin +X-KDE-ResourceFamily=calendar +X-KDE-ResourceType=scalix diff --git a/kresources/scalix/kioslave/Makefile.am b/kresources/scalix/kioslave/Makefile.am new file mode 100644 index 000000000..8396c4985 --- /dev/null +++ b/kresources/scalix/kioslave/Makefile.am @@ -0,0 +1,17 @@ +INCLUDES = -I$(top_srcdir) -I$(top_builddir)/libkdepim $(all_includes) + +noinst_HEADERS = scalix.h + +METASOURCES = AUTO + +kdelnkdir = $(kde_servicesdir) +kdelnk_DATA = scalix.protocol scalixs.protocol + +kde_module_LTLIBRARIES = kio_scalix.la + +kio_scalix_la_SOURCES = scalix.cpp +kio_scalix_la_LIBADD = $(top_builddir)/libkcal/libkcal.la $(top_builddir)/libkdepim/libkdepim.la $(LIB_KIO) +kio_scalix_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) + +messages: rc.cpp + $(XGETTEXT) *.cpp -o $(podir)/kio_scalix.pot diff --git a/kresources/scalix/kioslave/scalix.cpp b/kresources/scalix/kioslave/scalix.cpp new file mode 100644 index 000000000..199bd0980 --- /dev/null +++ b/kresources/scalix/kioslave/scalix.cpp @@ -0,0 +1,225 @@ +/* + This file is part of KDE. + + Copyright (C) 2007 Trolltech ASA. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include <qapplication.h> +#include <qeventloop.h> + +#include <kapplication.h> +#include <kcmdlineargs.h> +#include <kdebug.h> +#include <kdeversion.h> +#include <kio/global.h> +#include <klocale.h> + +#include <kdepimmacros.h> + +#include <stdlib.h> + +#include "scalix.h" + +extern "C" { + KDE_EXPORT int kdemain( int argc, char **argv ); +} + +static const KCmdLineOptions options[] = +{ + { "+protocol", I18N_NOOP( "Protocol name" ), 0 }, + { "+pool", I18N_NOOP( "Socket name" ), 0 }, + { "+app", I18N_NOOP( "Socket name" ), 0 }, + KCmdLineLastOption +}; + +int kdemain( int argc, char **argv ) +{ + putenv( strdup( "SESSION_MANAGER=" ) ); + KApplication::disableAutoDcopRegistration(); + + KCmdLineArgs::init( argc, argv, "kio_scalix", 0, 0, 0, 0 ); + KCmdLineArgs::addCmdLineOptions( options ); + KApplication app( false, false ); + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + Scalix slave( args->arg( 0 ), args->arg( 1 ), args->arg( 2 ) ); + slave.dispatchLoop(); + + return 0; +} + +Scalix::Scalix( const QCString &protocol, const QCString &pool, const QCString &app ) + : SlaveBase( protocol, pool, app ) +{ +} + +void Scalix::get( const KURL &url ) +{ + mimeType( "text/plain" ); + + QString path = url.path(); + + if ( path.contains( "/freebusy/" ) ) { + retrieveFreeBusy( url ); + } else { + error( KIO::ERR_SLAVE_DEFINED, i18n( "Unknown path. Known path is '/freebusy/'" ) ); + } +} + +void Scalix::put( const KURL& url, int, bool, bool ) +{ + QString path = url.path(); + + if ( path.contains( "/freebusy/" ) ) { + publishFreeBusy( url ); + } else { + error( KIO::ERR_SLAVE_DEFINED, i18n( "Unknown path. Known path is '/freebusy/'" ) ); + } +} + +void Scalix::retrieveFreeBusy( const KURL &url ) +{ + /** + * The url is of the following form: + * scalix://user:password@host/freebusy/[email protected] + */ + + // Extract user@domain (e.g. everything between '/freebusy/' and '.ifb') + const QString requestUser = url.path().mid( 10, url.path().length() - 14 ); + + QByteArray packedArgs; + QDataStream stream( packedArgs, IO_WriteOnly ); + + const QString argument = QString( "BEGIN:VFREEBUSY\nATTENDEE:MAILTO:%1\nEND:VFREEBUSY" ).arg( requestUser ); + const QString command = QString( "X-GET-ICAL-FREEBUSY {%1}" ).arg( argument.length() ); + + stream << (int) 'X' << 'E' << command << argument; + + QString imapUrl = QString( "imap://%1@%3/" ).arg( url.pass().isEmpty() ? + url.user() : url.user() + ":" + url.pass() ) + .arg( url.host() ); + + mFreeBusyData = QString(); + + KIO::SimpleJob *job = KIO::special( imapUrl, packedArgs, false ); + connect( job, SIGNAL( infoMessage( KIO::Job*, const QString& ) ), + this, SLOT( slotInfoMessage( KIO::Job*, const QString& ) ) ); + connect( job, SIGNAL( result( KIO::Job* ) ), + this, SLOT( slotRetrieveResult( KIO::Job* ) ) ); + + qApp->eventLoop()->enterLoop(); +} + +void Scalix::publishFreeBusy( const KURL &url ) +{ + /** + * The url is of the following form: + * scalix://user:password@host/freebusy/path/to/calendar/user@domain + */ + QString requestUser, calendar; + QString path = url.path(); + + // extract user name + int lastSlash = path.findRev( '/' ); + if ( lastSlash != -1 ) + requestUser = path.mid( lastSlash + 1 ); + + // extract calendar name + int secondSlash = path.find( '/', 1 ); + if ( secondSlash != -1 ) + calendar = path.mid( secondSlash + 1, lastSlash - secondSlash - 1 ); + + if ( requestUser.isEmpty() || calendar.isEmpty() ) { + error( KIO::ERR_SLAVE_DEFINED, i18n( "No user or calendar given!" ) ); + return; + }; + + // read freebusy information + QByteArray data; + while ( true ) { + dataReq(); + + QByteArray buffer; + const int newSize = readData(buffer); + if ( newSize < 0 ) { + // read error: network in unknown state so disconnect + error( KIO::ERR_COULD_NOT_READ, i18n("KIO data supply error.") ); + return; + } + + if ( newSize == 0 ) + break; + + unsigned int oldSize = data.size(); + data.resize( oldSize + buffer.size() ); + memcpy( data.data() + oldSize, buffer.data(), buffer.size() ); + } + + QByteArray packedArgs; + QDataStream stream( packedArgs, IO_WriteOnly ); + + const QString argument = QString::fromUtf8( data ); + const QString command = QString( "X-PUT-ICAL-FREEBUSY Calendar {%1}" ).arg( argument.length() ); + + stream << (int) 'X' << 'E' << command << argument; + + QString imapUrl = QString( "imap://%1@%3/" ).arg( url.pass().isEmpty() ? + url.user() : url.user() + ":" + url.pass() ) + .arg( url.host() ); + + KIO::SimpleJob *job = KIO::special( imapUrl, packedArgs, false ); + connect( job, SIGNAL( result( KIO::Job* ) ), + this, SLOT( slotPublishResult( KIO::Job* ) ) ); + + qApp->eventLoop()->enterLoop(); +} + +void Scalix::slotInfoMessage( KIO::Job *job, const QString &data ) +{ + if ( job->error() ) { + // error is handled in slotResult + return; + } + + mFreeBusyData = data; +} + + +void Scalix::slotRetrieveResult( KIO::Job *job ) +{ + if ( job->error() ) { + error( KIO::ERR_SLAVE_DEFINED, job->errorString() ); + } else { + data( mFreeBusyData.utf8() ); + finished(); + } + + qApp->eventLoop()->exitLoop(); +} + +void Scalix::slotPublishResult( KIO::Job *job ) +{ + if ( job->error() ) { + error( KIO::ERR_SLAVE_DEFINED, job->errorString() ); + } else { + finished(); + } + + qApp->eventLoop()->exitLoop(); +} + +#include "scalix.moc" diff --git a/kresources/scalix/kioslave/scalix.h b/kresources/scalix/kioslave/scalix.h new file mode 100644 index 000000000..3697c49d7 --- /dev/null +++ b/kresources/scalix/kioslave/scalix.h @@ -0,0 +1,51 @@ +/* + This file is part of KDE. + + Copyright (C) 2007 Trolltech ASA. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef SCALIX_H +#define SCALIX_H + +#include <kio/job.h> +#include <kio/slavebase.h> + +#include <qobject.h> + +class Scalix : public QObject, public KIO::SlaveBase +{ + Q_OBJECT + + public: + Scalix( const QCString &protocol, const QCString &pool, const QCString &app ); + + void get( const KURL &url ); + void put( const KURL &url, int permissions, bool overwrite, bool resume ); + + private slots: + void slotRetrieveResult( KIO::Job* ); + void slotPublishResult( KIO::Job* ); + void slotInfoMessage( KIO::Job*, const QString& ); + + private: + void retrieveFreeBusy( const KURL& ); + void publishFreeBusy( const KURL& ); + + QString mFreeBusyData; +}; + +#endif diff --git a/kresources/scalix/kioslave/scalix.protocol b/kresources/scalix/kioslave/scalix.protocol new file mode 100644 index 000000000..a527d77dd --- /dev/null +++ b/kresources/scalix/kioslave/scalix.protocol @@ -0,0 +1,8 @@ +[Protocol] +DocPath=kioslave/scalix.html +exec=kio_scalix +input=none +output=filesystem +protocol=scalix +reading=true +writing=true diff --git a/kresources/scalix/kioslave/scalixs.protocol b/kresources/scalix/kioslave/scalixs.protocol new file mode 100644 index 000000000..fd13db6ad --- /dev/null +++ b/kresources/scalix/kioslave/scalixs.protocol @@ -0,0 +1,8 @@ +[Protocol] +DocPath=kioslave/scalix.html +exec=kio_scalix +input=none +output=filesystem +protocol=scalixs +reading=true +writing=true diff --git a/kresources/scalix/knotes/Makefile.am b/kresources/scalix/knotes/Makefile.am new file mode 100644 index 000000000..42a1c2302 --- /dev/null +++ b/kresources/scalix/knotes/Makefile.am @@ -0,0 +1,28 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/kresources/scalix/shared \ + -I$(top_srcdir) -I$(top_srcdir)/knotes -I$(top_builddir)/libkdepim $(all_includes) + +# The scalix wizard links to this library too +lib_LTLIBRARIES = libknotesscalix.la + +libknotesscalix_la_SOURCES = resourcescalix.cpp +libknotesscalix_la_LDFLAGS = $(all_libraries) -no-undefined +libknotesscalix_la_LIBADD = \ + $(top_builddir)/kresources/scalix/shared/libresourcescalixshared.la \ + $(top_builddir)/knotes/libknotesresources.la \ + $(top_builddir)/libkcal/libkcal.la \ + -lkresources -lkdeprint + +kde_module_LTLIBRARIES = knotes_scalix.la + +knotes_scalix_la_SOURCES = resourcescalix_plugin.cpp +knotes_scalix_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) -no-undefined +knotes_scalix_la_LIBADD = libknotesscalix.la + +servicedir = $(kde_servicesdir)/kresources/knotes +service_DATA = scalix.desktop + +install-data-local: $(srcdir)/../uninstall.desktop + $(mkinstalldirs) $(DESTDIR)$(servicedir) + $(INSTALL_DATA) $(srcdir)/../uninstall.desktop $(DESTDIR)$(servicedir)/scalix.desktop diff --git a/kresources/scalix/knotes/resourcescalix.cpp b/kresources/scalix/knotes/resourcescalix.cpp new file mode 100644 index 000000000..e43a9a912 --- /dev/null +++ b/kresources/scalix/knotes/resourcescalix.cpp @@ -0,0 +1,425 @@ +/* + This file is part of the scalix resource - based on the kolab resource. + + Copyright (c) 2004 Bo Thorsen <[email protected]> + Copyright (c) 2004 Till Adam <[email protected]> + + 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 "resourcescalix.h" + +#include <knotes/resourcemanager.h> + +#include <libkcal/icalformat.h> + +#include <kdebug.h> +#include <kglobal.h> + +using namespace Scalix; + +static const char* configGroupName = "Note"; +static const char* kmailContentsType = "Note"; +static const char* attachmentMimeType = "application/x-vnd.kolab.note"; +static const char* inlineMimeType = "text/calendar"; + +ResourceScalix::ResourceScalix( const KConfig *config ) + : ResourceNotes( config ), ResourceScalixBase( "ResourceScalix-KNotes" ), + mCalendar( QString::fromLatin1("UTC") ) +{ + setType( "scalix" ); +} + +ResourceScalix::~ResourceScalix() +{ +} + +bool ResourceScalix::doOpen() +{ + KConfig config( configFile() ); + config.setGroup( configGroupName ); + + // Get the list of Notes folders from KMail + QValueList<KMailICalIface::SubResource> subResources; + if ( !kmailSubresources( subResources, kmailContentsType ) ) + return false; + + // Make the resource map from the folder list + QValueList<KMailICalIface::SubResource>::ConstIterator it; + mSubResources.clear(); + for ( it = subResources.begin(); it != subResources.end(); ++it ) { + const QString subResource = (*it).location; + const bool active = config.readBoolEntry( subResource, true ); + mSubResources[ subResource ] = Scalix::SubResource( active, (*it).writable, (*it).label ); + } + + return true; +} + +void ResourceScalix::doClose() +{ + KConfig config( configFile() ); + config.setGroup( configGroupName ); + Scalix::ResourceMap::ConstIterator it; + for ( it = mSubResources.begin(); it != mSubResources.end(); ++it ) + config.writeEntry( it.key(), it.data().active() ); +} + +bool ResourceScalix::loadSubResource( const QString& subResource, + const QString &mimetype ) +{ + // Get the list of journals + int count = 0; + if ( !kmailIncidencesCount( count, mimetype, subResource ) ) { + kdError() << "Communication problem in ResourceScalix::load()\n"; + return false; + } + + QMap<Q_UINT32, QString> lst; + if( !kmailIncidences( lst, mimetype, subResource, 0, count ) ) { + kdError(5500) << "Communication problem in " + << "ResourceScalix::getIncidenceList()\n"; + return false; + } + + kdDebug(5500) << "Notes scalix resource: got " << lst.count() << " notes in " << subResource << endl; + + // Populate with the new entries + const bool silent = mSilent; + mSilent = true; + QMap<Q_UINT32, QString>::Iterator it; + for ( it = lst.begin(); it != lst.end(); ++it ) { + KCal::Journal* journal = addNote( it.data(), subResource, it.key(), mimetype ); + if ( !journal ) + kdDebug(5500) << "loading note " << it.key() << " failed" << endl; + else + manager()->registerNote( this, journal ); + } + mSilent = silent; + + return true; +} + +bool ResourceScalix::load() +{ + // We get a fresh list of events, so clean out the old ones + mCalendar.deleteAllEvents(); + mUidMap.clear(); + + bool rc = true; + Scalix::ResourceMap::ConstIterator itR; + for ( itR = mSubResources.begin(); itR != mSubResources.end(); ++itR ) { + if ( !itR.data().active() ) + // This subResource is disabled + continue; + + QString mimetype = inlineMimeType; + rc &= loadSubResource( itR.key(), mimetype ); + mimetype = attachmentMimeType; + rc &= loadSubResource( itR.key(), mimetype ); + } + + return rc; +} + +bool ResourceScalix::save() +{ + // Nothing to do here, we save everything in incidenceUpdated() + return true; +} + +bool ResourceScalix::addNote( KCal::Journal* journal ) +{ + return addNote( journal, QString::null, 0 ); +} + +KCal::Journal* ResourceScalix::addNote( const QString& data, const QString& subresource, + Q_UINT32 sernum, const QString& ) +{ + KCal::Journal* journal = 0; + // FIXME: This does not take into account the time zone! + KCal::ICalFormat formatter; + journal = static_cast<KCal::Journal*>( formatter.fromString( data ) ); + + Q_ASSERT( journal ); + if( journal && !mUidMap.contains( journal->uid() ) ) + if ( addNote( journal, subresource, sernum ) ) + return journal; + else + delete journal; + return 0; +} + +bool ResourceScalix::addNote( KCal::Journal* journal, + const QString& subresource, Q_UINT32 sernum ) +{ + kdDebug(5500) << "ResourceScalix::addNote( KCal::Journal*, '" << subresource << "', " << sernum << " )\n"; + + journal->registerObserver( this ); + + // Find out if this note was previously stored in KMail + bool newNote = subresource.isEmpty(); + mCalendar.addJournal( journal ); + + QString resource = + newNote ? findWritableResource( mSubResources ) : subresource; + if ( resource.isEmpty() ) // canceled + return false; + + if ( !mSilent ) { + KCal::ICalFormat formatter; + const QString xml = formatter.toString( journal ); + kdDebug(5500) << k_funcinfo << "XML string:\n" << xml << endl; + + if( !kmailUpdate( resource, sernum, xml, attachmentMimeType, journal->uid() ) ) { + kdError(5500) << "Communication problem in ResourceScalix::addNote()\n"; + return false; + } + } + + if ( !resource.isEmpty() && sernum != 0 ) { + mUidMap[ journal->uid() ] = StorageReference( resource, sernum ); + return true; + } + + return false; +} + +bool ResourceScalix::deleteNote( KCal::Journal* journal ) +{ + const QString uid = journal->uid(); + if ( !mUidMap.contains( uid ) ) + // Odd + return false; + + if ( !mSilent ) { + kmailDeleteIncidence( mUidMap[ uid ].resource(), + mUidMap[ uid ].serialNumber() ); + } + mUidMap.remove( uid ); + manager()->deleteNote( journal ); + mCalendar.deleteJournal( journal ); + return true; +} + +KCal::Alarm::List ResourceScalix::alarms( const QDateTime& from, const QDateTime& to ) +{ + KCal::Alarm::List alarms; + KCal::Journal::List notes = mCalendar.journals(); + KCal::Journal::List::ConstIterator note; + for ( note = notes.begin(); note != notes.end(); ++note ) + { + QDateTime preTime = from.addSecs( -1 ); + KCal::Alarm::List::ConstIterator it; + for( it = (*note)->alarms().begin(); it != (*note)->alarms().end(); ++it ) + { + if ( (*it)->enabled() ) + { + QDateTime dt = (*it)->nextRepetition( preTime ); + if ( dt.isValid() && dt <= to ) + alarms.append( *it ); + } + } + } + + return alarms; +} + +void ResourceScalix::incidenceUpdated( KCal::IncidenceBase* i ) +{ + QString subResource; + Q_UINT32 sernum; + if ( mUidMap.contains( i->uid() ) ) { + subResource = mUidMap[ i->uid() ].resource(); + sernum = mUidMap[ i->uid() ].serialNumber(); + } else { // can this happen? + subResource = findWritableResource( mSubResources ); + if ( subResource.isEmpty() ) // canceled + return; + sernum = 0; + } + + KCal::Journal* journal = dynamic_cast<KCal::Journal*>( i ); + KCal::ICalFormat formatter; + const QString xml = formatter.toString( journal ); + if( !xml.isEmpty() && kmailUpdate( subResource, sernum, xml, attachmentMimeType, journal->uid() ) ) + mUidMap[ i->uid() ] = StorageReference( subResource, sernum ); +} + +/* + * These are the DCOP slots that KMail call to notify when something + * changed. + */ +bool ResourceScalix::fromKMailAddIncidence( const QString& type, + const QString& subResource, + Q_UINT32 sernum, + int, + const QString& note ) +{ + // Check if this is a note + if( type != kmailContentsType ) return false; + + const bool silent = mSilent; + mSilent = true; + QString mimetype = inlineMimeType; + KCal::Journal* journal = addNote( note, subResource, sernum, mimetype ); + if ( journal ) + manager()->registerNote( this, journal ); + mSilent = silent; + return true; +} + +void ResourceScalix::fromKMailDelIncidence( const QString& type, + const QString& /*subResource*/, + const QString& uid ) +{ + // Check if this is a note + if( type != kmailContentsType ) return; + + kdDebug(5500) << "ResourceScalix::fromKMailDelIncidence( " << type << ", " << uid + << " )" << endl; + + const bool silent = mSilent; + mSilent = true; + KCal::Journal* j = mCalendar.journal( uid ); + if( j ) + deleteNote( j ); + mSilent = silent; +} + +void ResourceScalix::fromKMailRefresh( const QString& type, + const QString& /*subResource*/ ) +{ + if ( type == kmailContentsType ) + load(); // ### should call loadSubResource(subResource) probably +} + +void ResourceScalix::fromKMailAddSubresource( const QString& type, + const QString& subResource, + const QString& mimetype, + bool writable ) +{ + if ( type != kmailContentsType ) + // Not ours + return; + + if ( mSubResources.contains( subResource ) ) + // Already registered + return; + + KConfig config( configFile() ); + config.setGroup( configGroupName ); + + bool active = config.readBoolEntry( subResource, true ); + mSubResources[ subResource ] = Scalix::SubResource( active, writable, subResource ); + loadSubResource( subResource, mimetype ); + emit signalSubresourceAdded( this, type, subResource ); +} + +void ResourceScalix::fromKMailDelSubresource( const QString& type, + const QString& subResource ) +{ + if ( type != configGroupName ) + // Not ours + return; + + if ( !mSubResources.contains( subResource ) ) + // Not registered + return; + + // Ok, it's our job, and we have it here + mSubResources.erase( subResource ); + + KConfig config( configFile() ); + config.setGroup( configGroupName ); + config.deleteEntry( subResource ); + config.sync(); + + // Make a list of all uids to remove + Scalix::UidMap::ConstIterator mapIt; + QStringList uids; + for ( mapIt = mUidMap.begin(); mapIt != mUidMap.end(); ++mapIt ) + if ( mapIt.data().resource() == subResource ) + // We have a match + uids << mapIt.key(); + + // Finally delete all the incidences + if ( !uids.isEmpty() ) { + const bool silent = mSilent; + mSilent = true; + QStringList::ConstIterator it; + for ( it = uids.begin(); it != uids.end(); ++it ) { + KCal::Journal* j = mCalendar.journal( *it ); + if( j ) + deleteNote( j ); + } + mSilent = silent; + } + + emit signalSubresourceRemoved( this, type, subResource ); +} + +void ResourceScalix::fromKMailAsyncLoadResult( const QMap<Q_UINT32, QString>& map, + const QString& type, + const QString& folder ) +{ + // We are only interested in notes + if ( ( type != attachmentMimeType ) && ( type != inlineMimeType ) ) return; + // Populate with the new entries + const bool silent = mSilent; + mSilent = true; + QString mimetype = inlineMimeType; + for( QMap<Q_UINT32, QString>::ConstIterator it = map.begin(); it != map.end(); ++it ) { + KCal::Journal* journal = addNote( it.data(), folder, it.key(), mimetype ); + if ( !journal ) + kdDebug(5500) << "loading note " << it.key() << " failed" << endl; + else + manager()->registerNote( this, journal ); + } + mSilent = silent; +} + + +QStringList ResourceScalix::subresources() const +{ + return mSubResources.keys(); +} + +bool ResourceScalix::subresourceActive( const QString& res ) const +{ + if ( mSubResources.contains( res ) ) { + return mSubResources[ res ].active(); + } + + // Safe default bet: + kdDebug(5650) << "subresourceActive( " << res << " ): Safe bet\n"; + + return true; +} + + +#include "resourcescalix.moc" diff --git a/kresources/scalix/knotes/resourcescalix.h b/kresources/scalix/knotes/resourcescalix.h new file mode 100644 index 000000000..a26bd1973 --- /dev/null +++ b/kresources/scalix/knotes/resourcescalix.h @@ -0,0 +1,127 @@ +/* + This file is part of the scalix resource - based on the kolab resource. + + Copyright (c) 2004 Bo Thorsen <[email protected]> + + 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 KNOTES_RESOURCESCALIX_H +#define KNOTES_RESOURCESCALIX_H + +#include <resourcenotes.h> +#include <libkcal/incidencebase.h> +#include <libkcal/calendarlocal.h> +#include "../shared/resourcescalixbase.h" +#include "../shared/subresource.h" +#include <kdepimmacros.h> + + +namespace Scalix { + +/** + * This class implements a KNotes resource that keeps its + * addresses in an IMAP folder in KMail (or other conforming email + * clients). + */ +class KDE_EXPORT ResourceScalix : public ResourceNotes, + public KCal::IncidenceBase::Observer, + public ResourceScalixBase +{ + Q_OBJECT + +public: + ResourceScalix( const KConfig* ); + virtual ~ResourceScalix(); + + /// Load resource data. + bool load(); + + /// Save resource data. + bool save(); + + /// Open the notes resource. + bool doOpen(); + /// Close the notes resource. + void doClose(); + + bool addNote( KCal::Journal* ); + + bool deleteNote( KCal::Journal* ); + + KCal::Alarm::List alarms( const QDateTime& from, const QDateTime& to ); + + /// Reimplemented from IncidenceBase::Observer to know when a note was changed + void incidenceUpdated( KCal::IncidenceBase* ); + + /// The ResourceScalixBase methods called by KMail + bool fromKMailAddIncidence( const QString& type, const QString& resource, + Q_UINT32 sernum, int format, const QString& note ); + void fromKMailDelIncidence( const QString& type, const QString& resource, + const QString& uid ); + void fromKMailRefresh( const QString& type, const QString& resource ); + + /// Listen to KMail changes in the amount of sub resources + void fromKMailAddSubresource( const QString& type, const QString& resource, + const QString& label, bool writable ); + void fromKMailDelSubresource( const QString& type, const QString& resource ); + + void fromKMailAsyncLoadResult( const QMap<Q_UINT32, QString>& map, + const QString& type, + const QString& folder ); + + /** Return the list of subresources. */ + QStringList subresources() const; + + /** Is this subresource active? */ + bool subresourceActive( const QString& ) const; + +signals: + void signalSubresourceAdded( Resource*, const QString&, const QString& ); + void signalSubresourceRemoved( Resource*, const QString&, const QString& ); + +private: + bool addNote( KCal::Journal* journal, const QString& resource, + Q_UINT32 sernum ); + KCal::Journal* addNote( const QString& data, const QString& subresource, + Q_UINT32 sernum, const QString &mimetype ); + + bool loadSubResource( const QString& resource, const QString& mimetype ); + + QString configFile() const { + return ResourceScalixBase::configFile( "knotes" ); + } + + KCal::CalendarLocal mCalendar; + + // The list of subresources + Scalix::ResourceMap mSubResources; +}; + +} + +#endif // KNOTES_RESOURCESCALIX_H diff --git a/kresources/scalix/knotes/resourcescalix_plugin.cpp b/kresources/scalix/knotes/resourcescalix_plugin.cpp new file mode 100644 index 000000000..a83bbd746 --- /dev/null +++ b/kresources/scalix/knotes/resourcescalix_plugin.cpp @@ -0,0 +1,50 @@ +/* + This file is part of the scalix resource - based on the kolab resource. + + Copyright (c) 2002 - 2004 Klar�lvdalens Datakonsult AB + + 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 "resourcescalix.h" + +class ScalixFactory : public KRES::PluginFactoryBase +{ +public: + KRES::Resource *resource( const KConfig *config ) + { + return new Scalix::ResourceScalix( config ); + } + + KRES::ConfigWidget *configWidget( QWidget* ) + { + return 0; + } +}; + +K_EXPORT_COMPONENT_FACTORY( knotes_scalix, ScalixFactory() ) diff --git a/kresources/scalix/knotes/scalix.desktop b/kresources/scalix/knotes/scalix.desktop new file mode 100644 index 000000000..a573bee8c --- /dev/null +++ b/kresources/scalix/knotes/scalix.desktop @@ -0,0 +1,30 @@ +[Desktop Entry] +Name=Notes on Scalix Server via KMail +Name[bg]=Бележки на сървъра Scalix през KMail +Name[ca]=Notes en un servidor Scalix mitjançant el KMail +Name[da]=Noter på Scalix-server via KMail +Name[de]=Notizen auf einem Scalix-Server via KMail +Name[el]=Σημειώσεις σε εξυπηρετητή Scalix μέσω του KMail +Name[es]=Notas en servidor Scalix por medio de KMail +Name[et]=Kalender Scalix-serveris (KMaili vahendusel) +Name[fr]=Notes sur serveur Scalix via KMail +Name[is]=Minnismiðar á Scalix-þjóni gegnum KMail +Name[it]=Note su server Scalix via KMail +Name[ja]=KMail 経由 Scalix サーバのメモ +Name[km]=ចំណាំនៅលើម៉ាស៊ីនបម្រើ Scalix តាមរយៈ KMail +Name[nds]=Notizen op Scalix-Server över KMail +Name[nl]=Notities op Scalix-server via KMail +Name[pl]=Notatki na serwerze Scalix za pośrednictwem KMaila +Name[ru]=Заметки на сервере Scalix через KMail +Name[sk]=Poznámky na Scalix serveri pomocou KMail +Name[sr]=Белешке на Scalix серверу преко KMail-а +Name[sr@Latn]=Beleške na Scalix serveru preko KMail-a +Name[sv]=Anteckningar på Scalix-server via Kmail +Name[tr]=KMail Aracılığı ile Scalix Sunucusunda Takvim +Name[zh_CN]=通过 KMail 访问 Scalix 服务器上的日历 +Name[zh_TW]=透過 KMail 取得 Scalix 伺服器上的便條 +X-KDE-Library=knotes_scalix +Type=Service +ServiceTypes=KResources/Plugin +X-KDE-ResourceFamily=notes +X-KDE-ResourceType=scalix diff --git a/kresources/scalix/scalixadmin/Makefile.am b/kresources/scalix/scalixadmin/Makefile.am new file mode 100644 index 000000000..7402ef281 --- /dev/null +++ b/kresources/scalix/scalixadmin/Makefile.am @@ -0,0 +1,15 @@ +bin_PROGRAMS = scalixadmin + +INCLUDES = $(all_includes) + +scalixadmin_LDFLAGS = $(KDE_RPATH) $(all_libraries) +scalixadmin_LDADD = $(LIB_KABC) +scalixadmin_SOURCES = main.cpp mainwindow.cpp passwordpage.cpp settings.cpp jobs.cpp \ + otherusermanager.cpp otheruserview.cpp otheruserpage.cpp ldapview.cpp ldapdialog.cpp \ + delegatemanager.cpp delegateview.cpp delegatepage.cpp delegatedialog.cpp \ + outofofficepage.cpp + +METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) *.cpp -o $(podir)/scalixadmin.pot diff --git a/kresources/scalix/scalixadmin/delegatedialog.cpp b/kresources/scalix/scalixadmin/delegatedialog.cpp new file mode 100644 index 000000000..3dc0412a4 --- /dev/null +++ b/kresources/scalix/scalixadmin/delegatedialog.cpp @@ -0,0 +1,105 @@ +/* + * This file is part of ScalixAdmin. + * + * Copyright (C) 2007 Trolltech ASA. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <qcheckbox.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qlineedit.h> +#include <qtoolbutton.h> + +#include <klocale.h> + +#include "jobs.h" +#include "ldapdialog.h" + +#include "delegatedialog.h" + +DelegateDialog::DelegateDialog( QWidget *parent ) + : KDialogBase( parent, "", true, "", Ok | Cancel, Ok, true ) +{ + QWidget *page = new QWidget( this ); + QGridLayout *layout = new QGridLayout( page, 5, 3, 11, 6 ); + + QLabel *label = new QLabel( i18n( "User:" ), page ); + layout->addWidget( label, 0, 0 ); + + mEmail = new QLineEdit( page ); + layout->addWidget( mEmail, 0, 1 ); + + QToolButton *emailSelector = new QToolButton( page ); + emailSelector->setUsesTextLabel( true ); + emailSelector->setTextLabel( i18n( "..." ) ); + layout->addWidget( emailSelector, 0, 2 ); + + QValueList<Scalix::DelegateTypes> types; + types << Scalix::SendOnBehalfOf; + types << Scalix::SeePrivate; + types << Scalix::GetMeetings; + types << Scalix::InsteadOfMe; + + int row = 1; + for ( uint i = 0; i < types.count(); ++i ) { + QCheckBox *box = new QCheckBox( Scalix::Delegate::rightsAsString( types[ i ] ), page ); + layout->addMultiCellWidget( box, row, row, 1, 2 ); + + mRights.insert( types[ i ], box ); + row++; + } + + connect( emailSelector, SIGNAL( clicked() ), SLOT( selectEmail() ) ); + + setMainWidget( page ); +} + +void DelegateDialog::setDelegate( const Scalix::Delegate &delegate ) +{ + mEmail->setText( delegate.email() ); + + QMap<int, QCheckBox*>::Iterator it; + for ( it = mRights.begin(); it != mRights.end(); ++it ) + it.data()->setChecked( delegate.rights() & it.key() ); +} + +Scalix::Delegate DelegateDialog::delegate() const +{ + int rights = 0; + + QMap<int, QCheckBox*>::ConstIterator it; + for ( it = mRights.begin(); it != mRights.end(); ++it ) + if ( it.data()->isChecked() ) + rights |= it.key(); + + return Scalix::Delegate( mEmail->text(), rights ); +} + +void DelegateDialog::selectEmail() +{ + LdapDialog dlg( this ); + if ( !dlg.exec() ) + return; + + const QString email = dlg.selectedUser(); + if ( email.isEmpty() ) + return; + + mEmail->setText( email ); +} + +#include "delegatedialog.moc" diff --git a/kresources/scalix/scalixadmin/delegatedialog.h b/kresources/scalix/scalixadmin/delegatedialog.h new file mode 100644 index 000000000..b5503a4f3 --- /dev/null +++ b/kresources/scalix/scalixadmin/delegatedialog.h @@ -0,0 +1,53 @@ +/* + * This file is part of ScalixAdmin. + * + * Copyright (C) 2007 Trolltech ASA. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef DELEGATEDIALOG_H +#define DELEGATEDIALOG_H + +#include <qmap.h> + +#include <kdialogbase.h> + +class QCheckBox; +class QLineEdit; + +namespace Scalix { +class Delegate; +} + +class DelegateDialog : public KDialogBase +{ + Q_OBJECT + + public: + DelegateDialog( QWidget *parent = 0 ); + + void setDelegate( const Scalix::Delegate &delegate ); + Scalix::Delegate delegate() const; + + private slots: + void selectEmail(); + + private: + QLineEdit *mEmail; + QMap<int, QCheckBox*> mRights; +}; + +#endif diff --git a/kresources/scalix/scalixadmin/delegatemanager.cpp b/kresources/scalix/scalixadmin/delegatemanager.cpp new file mode 100644 index 000000000..686370d77 --- /dev/null +++ b/kresources/scalix/scalixadmin/delegatemanager.cpp @@ -0,0 +1,49 @@ +/* + * This file is part of ScalixAdmin. + * + * Copyright (C) 2007 Trolltech ASA. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "delegatemanager.h" + +DelegateManager::DelegateManager() +{ +} + +DelegateManager::~DelegateManager() +{ +} + +void DelegateManager::addDelegate( const Scalix::Delegate &delegate ) +{ + mDelegates.append( delegate ); + emit changed(); +} + +void DelegateManager::clear() +{ + mDelegates.clear(); + + emit changed(); +} + +Scalix::Delegate::List DelegateManager::delegates() const +{ + return mDelegates; +} + +#include "delegatemanager.moc" diff --git a/kresources/scalix/scalixadmin/delegatemanager.h b/kresources/scalix/scalixadmin/delegatemanager.h new file mode 100644 index 000000000..f27b79a1b --- /dev/null +++ b/kresources/scalix/scalixadmin/delegatemanager.h @@ -0,0 +1,49 @@ +/* + * This file is part of ScalixAdmin. + * + * Copyright (C) 2007 Trolltech ASA. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef DELEGATEMANAGER_H +#define DELEGATEMANAGER_H + +#include <qobject.h> +#include <qstringlist.h> + +#include "jobs.h" + +class DelegateManager : public QObject +{ + Q_OBJECT + + public: + DelegateManager(); + ~DelegateManager(); + + void addDelegate( const Scalix::Delegate &delegate ); + void clear(); + + Scalix::Delegate::List delegates() const; + + signals: + void changed(); + + private: + Scalix::Delegate::List mDelegates; +}; + +#endif diff --git a/kresources/scalix/scalixadmin/delegatepage.cpp b/kresources/scalix/scalixadmin/delegatepage.cpp new file mode 100644 index 000000000..f9a9b8e7a --- /dev/null +++ b/kresources/scalix/scalixadmin/delegatepage.cpp @@ -0,0 +1,170 @@ +/* + * This file is part of ScalixAdmin. + * + * Copyright (C) 2007 Trolltech ASA. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <qlayout.h> +#include <qpushbutton.h> + +#include <kinputdialog.h> +#include <klocale.h> +#include <kmessagebox.h> + +#include <unistd.h> + +#include "delegatedialog.h" +#include "delegateview.h" +#include "jobs.h" +#include "settings.h" + +#include "delegatepage.h" + +DelegatePage::DelegatePage( QWidget *parent ) + : QWidget( parent ) +{ + QGridLayout *layout = new QGridLayout( this, 2, 3, 11, 6 ); + + mView = new DelegateView( &mManager, this ); + layout->addMultiCellWidget( mView, 0, 0, 0, 2 ); + + mAddButton = new QPushButton( i18n( "Add Delegate..." ), this ); + layout->addWidget( mAddButton, 1, 0 ); + + mEditButton = new QPushButton( i18n( "Edit Delegate..." ), this ); + mEditButton->setEnabled( false ); + layout->addWidget( mEditButton, 1, 1 ); + + mRemoveButton = new QPushButton( i18n( "Remove Delegate" ), this ); + mRemoveButton->setEnabled( false ); + layout->addWidget( mRemoveButton, 1, 2 ); + + connect( mView, SIGNAL( selectionChanged() ), SLOT( selectionChanged() ) ); + connect( mAddButton, SIGNAL( clicked() ), SLOT( addDelegate() ) ); + connect( mEditButton, SIGNAL( clicked() ), SLOT( editDelegate() ) ); + connect( mRemoveButton, SIGNAL( clicked() ), SLOT( removeDelegate() ) ); + + loadAllDelegates(); +} + +DelegatePage::~DelegatePage() +{ +} + +void DelegatePage::loadAllDelegates() +{ + Scalix::GetDelegatesJob *job = Scalix::getDelegates( Settings::self()->globalSlave(), + Settings::self()->accountUrl() ); + connect( job, SIGNAL( result( KIO::Job* ) ), SLOT( allDelegates( KIO::Job* ) ) ); +} + +void DelegatePage::addDelegate() +{ + DelegateDialog dlg( this ); + dlg.setCaption( i18n( "Add Delegate" ) ); + + if ( !dlg.exec() ) + return; + + const Scalix::Delegate delegate = dlg.delegate(); + + if ( !delegate.isValid() ) + return; + + Scalix::SetDelegateJob *job = Scalix::setDelegate( Settings::self()->globalSlave(), + Settings::self()->accountUrl(), + delegate.email(), delegate.rights() ); + connect( job, SIGNAL( result( KIO::Job* ) ), SLOT( delegateAdded( KIO::Job* ) ) ); +} + +void DelegatePage::editDelegate() +{ + const Scalix::Delegate oldDelegate = mView->selectedDelegate(); + if ( !oldDelegate.isValid() ) + return; + + DelegateDialog dlg( this ); + dlg.setCaption( i18n( "Edit Delegate" ) ); + + dlg.setDelegate( oldDelegate ); + + if ( !dlg.exec() ) + return; + + const Scalix::Delegate delegate = dlg.delegate(); + + if ( !delegate.isValid() ) + return; + + Scalix::SetDelegateJob *job = Scalix::setDelegate( Settings::self()->globalSlave(), + Settings::self()->accountUrl(), + delegate.email(), delegate.rights() ); + connect( job, SIGNAL( result( KIO::Job* ) ), SLOT( delegateAdded( KIO::Job* ) ) ); +} + +void DelegatePage::removeDelegate() +{ + const Scalix::Delegate delegate = mView->selectedDelegate(); + if ( !delegate.isValid() ) + return; + + Scalix::DeleteDelegateJob *job = Scalix::deleteDelegate( Settings::self()->globalSlave(), + Settings::self()->accountUrl(), delegate.email() ); + connect( job, SIGNAL( result( KIO::Job* ) ), SLOT( delegateRemoved( KIO::Job* ) ) ); +} + +void DelegatePage::allDelegates( KIO::Job *job ) +{ + if ( job->error() ) + KMessageBox::error( this, job->errorString() ); + + Scalix::GetDelegatesJob *delegateJob = static_cast<Scalix::GetDelegatesJob*>( job ); + + mManager.clear(); + + const Scalix::Delegate::List delegates = delegateJob->delegates(); + for ( uint i = 0; i < delegates.count(); ++i ) + mManager.addDelegate( delegates[ i ] ); + + selectionChanged(); +} + +void DelegatePage::delegateAdded( KIO::Job *job ) +{ + if ( job->error() ) + KMessageBox::error( this, job->errorString() ); + else + loadAllDelegates(); // update the GUI +} + +void DelegatePage::delegateRemoved( KIO::Job *job ) +{ + if ( job->error() ) + KMessageBox::error( this, job->errorString() ); + else + loadAllDelegates(); // update the GUI +} + +void DelegatePage::selectionChanged() +{ + bool state = ( mView->selectedItem() != 0 ); + + mEditButton->setEnabled( state ); + mRemoveButton->setEnabled( state ); +} + +#include "delegatepage.moc" diff --git a/kresources/scalix/scalixadmin/delegatepage.h b/kresources/scalix/scalixadmin/delegatepage.h new file mode 100644 index 000000000..243c0f0d3 --- /dev/null +++ b/kresources/scalix/scalixadmin/delegatepage.h @@ -0,0 +1,60 @@ +/* + * This file is part of ScalixAdmin. + * + * Copyright (C) 2007 Trolltech ASA. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef DELEGATEPAGE_H +#define DELEGATEPAGE_H + +#include <qwidget.h> + +#include "delegatemanager.h" + +class QPushButton; +class DelegateView; + +class DelegatePage : public QWidget +{ + Q_OBJECT + + public: + DelegatePage( QWidget *parent = 0 ); + ~DelegatePage(); + + private slots: + void loadAllDelegates(); + void addDelegate(); + void editDelegate(); + void removeDelegate(); + + void delegateAdded( KIO::Job* ); + void delegateRemoved( KIO::Job* ); + void allDelegates( KIO::Job* ); + + void selectionChanged(); + + private: + QPushButton *mAddButton; + QPushButton *mEditButton; + QPushButton *mRemoveButton; + + DelegateManager mManager; + DelegateView *mView; +}; + +#endif diff --git a/kresources/scalix/scalixadmin/delegateview.cpp b/kresources/scalix/scalixadmin/delegateview.cpp new file mode 100644 index 000000000..9ea16cf1a --- /dev/null +++ b/kresources/scalix/scalixadmin/delegateview.cpp @@ -0,0 +1,74 @@ +/* + * This file is part of ScalixAdmin. + * + * Copyright (C) 2007 Trolltech ASA. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <klocale.h> + +#include "delegatemanager.h" + +#include "delegateview.h" + +class DelegateItem : public QListViewItem +{ + public: + DelegateItem( QListView *parent, const Scalix::Delegate &delegate ) + : QListViewItem( parent ), mDelegate( delegate ) + { + setText( 0, mDelegate.email() ); + setText( 1, Scalix::Delegate::rightsAsString( mDelegate.rights() ) ); + } + + Scalix::Delegate delegate() const { return mDelegate; } + + private: + Scalix::Delegate mDelegate; +}; + +DelegateView::DelegateView( DelegateManager *manager, QWidget *parent ) + : KListView( parent ), mManager( manager ) +{ + addColumn( i18n( "Delegate" ) ); + addColumn( i18n( "Rights" ) ); + setFullWidth( true ); + setAllColumnsShowFocus( true ); + + connect( mManager, SIGNAL( changed() ), SLOT( delegateChanged() ) ); + + delegateChanged(); +} + +Scalix::Delegate DelegateView::selectedDelegate() const +{ + DelegateItem *item = dynamic_cast<DelegateItem*>( selectedItem() ); + if ( item ) + return item->delegate(); + + return Scalix::Delegate(); +} + +void DelegateView::delegateChanged() +{ + clear(); + + const Scalix::Delegate::List delegates = mManager->delegates(); + for ( uint i = 0; i < delegates.count(); ++i ) + new DelegateItem( this, delegates[ i ] ); +} + +#include "delegateview.moc" diff --git a/kresources/scalix/scalixadmin/delegateview.h b/kresources/scalix/scalixadmin/delegateview.h new file mode 100644 index 000000000..61725be29 --- /dev/null +++ b/kresources/scalix/scalixadmin/delegateview.h @@ -0,0 +1,48 @@ +/* + * This file is part of ScalixAdmin. + * + * Copyright (C) 2007 Trolltech ASA. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef DELEGATEVIEW_H +#define DELEGATEVIEW_H + +#include <klistview.h> + +namespace Scalix { +class Delegate; +} + +class DelegateManager; + +class DelegateView : public KListView +{ + Q_OBJECT + + public: + DelegateView( DelegateManager *manager, QWidget *parent = 0 ); + + Scalix::Delegate selectedDelegate() const; + + private slots: + void delegateChanged(); + + private: + DelegateManager *mManager; +}; + +#endif diff --git a/kresources/scalix/scalixadmin/jobs.cpp b/kresources/scalix/scalixadmin/jobs.cpp new file mode 100644 index 000000000..c463463d2 --- /dev/null +++ b/kresources/scalix/scalixadmin/jobs.cpp @@ -0,0 +1,306 @@ +/* + * This file is part of ScalixAdmin. + * + * Copyright (C) 2007 Trolltech ASA. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <kio/scheduler.h> +#include <klocale.h> + +#include "jobs.h" + +using namespace Scalix; + +Delegate::Delegate() + : mRights( -1 ) +{ +} + +Delegate::Delegate( const QString &email, int rights ) + : mEmail( email ), mRights( rights ) +{ +} + +bool Delegate::isValid() const +{ + return ( !mEmail.isEmpty() && mRights != -1 ); +} + +QString Delegate::email() const +{ + return mEmail; +} + +int Delegate::rights() const +{ + return mRights; +} + +QString Delegate::rightsAsString( int rights ) +{ + QStringList rightNames; + + if ( rights & SendOnBehalfOf ) + rightNames.append( i18n( "Send on behalf of" ) ); + if ( rights & SeePrivate ) + rightNames.append( i18n( "See private" ) ); + if ( rights & GetMeetings ) + rightNames.append( i18n( "Get meetings" ) ); + if ( rights & InsteadOfMe ) + rightNames.append( i18n( "Instead of me" ) ); + + return rightNames.join( ", " ); +} + + +SetPasswordJob* Scalix::setPassword( KIO::Slave* slave, const KURL& url, + const QString &oldPassword, const QString& newPassword ) +{ + QByteArray packedArgs; + QDataStream stream( packedArgs, IO_WriteOnly ); + stream << (int)'X' << (int)'N' + << QString( "X-SCALIX-PASSWORD" ) << QString( "%1 %2" ).arg( oldPassword ).arg( newPassword ); + + SetPasswordJob* job = new SetPasswordJob( url, packedArgs, false ); + KIO::Scheduler::assignJobToSlave( slave, job ); + return job; +} + +SetDelegateJob* Scalix::setDelegate( KIO::Slave* slave, const KURL& url, const QString& email, int params ) +{ + QStringList types; + if ( params & SendOnBehalfOf ) + types.append( "SOBO" ); + if ( params & SeePrivate ) + types.append( "SEEPRIVATE" ); + if ( params & GetMeetings ) + types.append( "GETMEETINGS" ); + if ( params & InsteadOfMe ) + types.append( "INSTEADOFME" ); + + QByteArray packedArgs; + QDataStream stream( packedArgs, IO_WriteOnly ); + stream << (int)'X' << (int)'N' + << QString( "X-SET-DELEGATE" ) << QString( "%1 %2" ).arg( email ).arg( types.join( " " ) ); + + SetDelegateJob* job = new SetDelegateJob( url, packedArgs, false ); + KIO::Scheduler::assignJobToSlave( slave, job ); + return job; +} + +DeleteDelegateJob* Scalix::deleteDelegate( KIO::Slave* slave, const KURL& url, const QString& email ) +{ + QByteArray packedArgs; + QDataStream stream( packedArgs, IO_WriteOnly ); + stream << (int)'X' << (int)'N' + << QString( "X-DELETE-DELEGATE" ) << email; + + DeleteDelegateJob* job = new DeleteDelegateJob( url, packedArgs, false ); + KIO::Scheduler::assignJobToSlave( slave, job ); + return job; +} + +GetDelegatesJob* Scalix::getDelegates( KIO::Slave* slave, const KURL& url ) +{ + QByteArray packedArgs; + QDataStream stream( packedArgs, IO_WriteOnly ); + stream << (int)'X' << (int)'N' << QString( "X-GET-DELEGATES" ) << QString(); + + GetDelegatesJob* job = new GetDelegatesJob( url, packedArgs, false ); + KIO::Scheduler::assignJobToSlave( slave, job ); + return job; +} + +AddOtherUserJob* Scalix::addOtherUser( KIO::Slave* slave, const KURL& url, const QString& email ) +{ + QByteArray packedArgs; + QDataStream stream( packedArgs, IO_WriteOnly ); + stream << (int)'X' << (int)'N' + << QString( "X-ADD-OTHER-USER" ) << email; + + AddOtherUserJob* job = new AddOtherUserJob( url, packedArgs, false ); + KIO::Scheduler::assignJobToSlave( slave, job ); + return job; +} + +DeleteOtherUserJob* Scalix::deleteOtherUser( KIO::Slave* slave, const KURL& url, const QString& email ) +{ + QByteArray packedArgs; + QDataStream stream( packedArgs, IO_WriteOnly ); + stream << (int)'X' << (int)'N' + << QString( "X-DELETE-OTHER-USER" ) << email; + + DeleteOtherUserJob* job = new DeleteOtherUserJob( url, packedArgs, false ); + KIO::Scheduler::assignJobToSlave( slave, job ); + return job; +} + +GetOtherUsersJob* Scalix::getOtherUsers( KIO::Slave* slave, const KURL& url ) +{ + QByteArray packedArgs; + QDataStream stream( packedArgs, IO_WriteOnly ); + stream << (int)'X' << (int)'N' + << QString( "X-GET-OTHER-USERS" ) << QString(); + + GetOtherUsersJob* job = new GetOtherUsersJob( url, packedArgs, false ); + KIO::Scheduler::assignJobToSlave( slave, job ); + return job; +} + +SetOutOfOfficeJob* Scalix::setOutOfOffice( KIO::Slave* slave, const KURL& url, bool enabled, const QString& msg ) +{ + const QString argument = msg; + const QString command = QString( "X-SET-OUT-OF-OFFICE %1 %2 {%3}" ).arg( enabled ? "ENABLED" : "DISABLED" ) + .arg( "UTF-8" ) + .arg( msg.utf8().length() ); + + QByteArray packedArgs; + QDataStream stream( packedArgs, IO_WriteOnly ); + stream << (int) 'X' << (int)'E' << command << argument; + + SetOutOfOfficeJob* job = new SetOutOfOfficeJob( url, packedArgs, false ); + KIO::Scheduler::assignJobToSlave( slave, job ); + return job; +} + +GetOutOfOfficeJob* Scalix::getOutOfOffice( KIO::Slave* slave, const KURL& url ) +{ + QByteArray packedArgs; + QDataStream stream( packedArgs, IO_WriteOnly ); + stream << (int)'X' << (int)'N' + << QString( "X-GET-OUT-OF-OFFICE" ) << QString(); + + GetOutOfOfficeJob* job = new GetOutOfOfficeJob( url, packedArgs, false ); + KIO::Scheduler::assignJobToSlave( slave, job ); + return job; +} + +SetPasswordJob::SetPasswordJob( const KURL& url, const QByteArray &packedArgs, bool showProgressInfo ) + : KIO::SimpleJob( url, KIO::CMD_SPECIAL, packedArgs, showProgressInfo ) +{ +} + +SetDelegateJob::SetDelegateJob( const KURL& url, const QByteArray &packedArgs, bool showProgressInfo ) + : KIO::SimpleJob( url, KIO::CMD_SPECIAL, packedArgs, showProgressInfo ) +{ +} + +DeleteDelegateJob::DeleteDelegateJob( const KURL& url, const QByteArray &packedArgs, bool showProgressInfo ) + : KIO::SimpleJob( url, KIO::CMD_SPECIAL, packedArgs, showProgressInfo ) +{ +} + +GetDelegatesJob::GetDelegatesJob( const KURL& url, const QByteArray &packedArgs, bool showProgressInfo ) + : KIO::SimpleJob( url, KIO::CMD_SPECIAL, packedArgs, showProgressInfo ) +{ + connect( this, SIGNAL( infoMessage( KIO::Job*, const QString& ) ), + this, SLOT( slotInfoMessage( KIO::Job*, const QString& ) ) ); +} + +Delegate::List GetDelegatesJob::delegates() const +{ + return mDelegates; +} + +void GetDelegatesJob::slotInfoMessage( KIO::Job*, const QString &data ) +{ + /** + * The passed data have the following form: + * + * "[email protected]:right1,right2,right4 [email protected]:right3,right5" + */ + QStringList delegates = QStringList::split( ' ', data ); + for ( uint i = 0; i < delegates.count(); ++i ) { + QStringList delegate = QStringList::split( ':', delegates[ i ] ); + + const QString email = delegate[ 0 ]; + int rights = 0; + + QStringList rightsList = QStringList::split( ',', delegate[ 1 ] ); + for ( uint j = 0; j < rightsList.count(); ++j ) { + if ( rightsList[ j ] == "SOBO" ) + rights |= SendOnBehalfOf; + else if ( rightsList[ j ] == "SEEPRIVATE" ) + rights |= SeePrivate; + else if ( rightsList[ j ] == "GETMEETINGS" ) + rights |= GetMeetings; + else if ( rightsList[ j ] == "INSTEADOFME" ) + rights |= InsteadOfMe; + } + + mDelegates.append( Delegate( email, rights ) ); + } +} + +AddOtherUserJob::AddOtherUserJob( const KURL& url, const QByteArray &packedArgs, bool showProgressInfo ) + : KIO::SimpleJob( url, KIO::CMD_SPECIAL, packedArgs, showProgressInfo ) +{ +} + +DeleteOtherUserJob::DeleteOtherUserJob( const KURL& url, const QByteArray &packedArgs, bool showProgressInfo ) + : KIO::SimpleJob( url, KIO::CMD_SPECIAL, packedArgs, showProgressInfo ) +{ +} + +GetOtherUsersJob::GetOtherUsersJob( const KURL& url, const QByteArray &packedArgs, bool showProgressInfo ) + : KIO::SimpleJob( url, KIO::CMD_SPECIAL, packedArgs, showProgressInfo ) +{ + connect( this, SIGNAL( infoMessage( KIO::Job*, const QString& ) ), + this, SLOT( slotInfoMessage( KIO::Job*, const QString& ) ) ); +} + +QStringList GetOtherUsersJob::otherUsers() const +{ + return mOtherUsers; +} + +void GetOtherUsersJob::slotInfoMessage( KIO::Job*, const QString &data ) +{ + mOtherUsers = QStringList::split( ' ', data ); +} + +SetOutOfOfficeJob::SetOutOfOfficeJob( const KURL& url, const QByteArray &packedArgs, bool showProgressInfo ) + : KIO::SimpleJob( url, KIO::CMD_SPECIAL, packedArgs, showProgressInfo ) +{ +} + +GetOutOfOfficeJob::GetOutOfOfficeJob( const KURL& url, const QByteArray &packedArgs, bool showProgressInfo ) + : KIO::SimpleJob( url, KIO::CMD_SPECIAL, packedArgs, showProgressInfo ) +{ + connect( this, SIGNAL( infoMessage( KIO::Job*, const QString& ) ), + this, SLOT( slotInfoMessage( KIO::Job*, const QString& ) ) ); +} + +bool GetOutOfOfficeJob::enabled() const +{ + return mEnabled; +} + +QString GetOutOfOfficeJob::message() const +{ + return mMessage; +} + +void GetOutOfOfficeJob::slotInfoMessage( KIO::Job*, const QString &data ) +{ + const QStringList fields = QStringList::split( '^', data ); + + mEnabled = ( fields[ 0 ] == "ENABLED" ); + mMessage = fields[ 1 ]; +} + +#include "jobs.moc" diff --git a/kresources/scalix/scalixadmin/jobs.h b/kresources/scalix/scalixadmin/jobs.h new file mode 100644 index 000000000..3b5a1b81f --- /dev/null +++ b/kresources/scalix/scalixadmin/jobs.h @@ -0,0 +1,202 @@ +/* + * This file is part of ScalixAdmin. + * + * Copyright (C) 2007 Trolltech ASA. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <kio/job.h> + +#ifndef JOBS_H +#define JOBS_H + +namespace Scalix { + + enum DelegateTypes + { + SendOnBehalfOf = 1, + SeePrivate = 2, + GetMeetings = 4, + InsteadOfMe = 8 + }; + + class SetPasswordJob; + class SetDelegateJob; + class DeleteDelegateJob; + class GetDelegatesJob; + class AddOtherUserJob; + class DeleteOtherUserJob; + class GetOtherUsersJob; + class SetOutOfOfficeJob; + class GetOutOfOfficeJob; + + class Delegate + { + public: + typedef QValueList<Delegate> List; + + Delegate(); + Delegate( const QString &email, int rights ); + + bool isValid() const; + + QString email() const; + int rights() const; + + static QString rightsAsString( int rights ); + + private: + QString mEmail; + int mRights; + }; + + /** + * Sets/Changes the password of the user encoded in @p url. + */ + SetPasswordJob* setPassword( KIO::Slave* slave, const KURL& url, const QString& oldPassword, const QString& newPassword ); + + /** + * Adds a delegate represented by @p email with the given @p params for the user encoded in @p url. + */ + SetDelegateJob* setDelegate( KIO::Slave* slave, const KURL& url, const QString& email, int params ); + + /** + * Deletes the delegate represented by @p email for the user encoded in @p url. + */ + DeleteDelegateJob* deleteDelegate( KIO::Slave* slave, const KURL& url, const QString& email ); + + /** + * Retrieves the delegates for the user encoded in @p url. + */ + GetDelegatesJob* getDelegates( KIO::Slave* slave, const KURL& url ); + + /** + * Adds the mailbox of another user represented by @p email to the users 'Other Users' namespace. + */ + AddOtherUserJob* addOtherUser( KIO::Slave* slave, const KURL& url, const QString& email ); + + /** + * Deletes the mailbox of another user represented by @p email from the users 'Other Users' namespace. + */ + DeleteOtherUserJob* deleteOtherUser( KIO::Slave* slave, const KURL& url, const QString& email ); + + /** + * Retrieves the list of all other users. + */ + GetOtherUsersJob* getOtherUsers( KIO::Slave* slave, const KURL& url ); + + /** + * Sets the out-of-office data. + * + * @param enabled Whether the out-of-office functionality is enabled. + * @param msg The out-of-office message. + */ + SetOutOfOfficeJob* setOutOfOffice( KIO::Slave* slave, const KURL& url, bool enabled, const QString& msg ); + + /** + * Retrieves the out-of-office data. + */ + GetOutOfOfficeJob* getOutOfOffice( KIO::Slave* slave, const KURL& url ); + + + class SetPasswordJob : public KIO::SimpleJob + { + public: + SetPasswordJob( const KURL& url, const QByteArray &packedArgs, bool showProgressInfo ); + }; + + class SetDelegateJob : public KIO::SimpleJob + { + public: + SetDelegateJob( const KURL& url, const QByteArray &packedArgs, bool showProgressInfo ); + }; + + class DeleteDelegateJob : public KIO::SimpleJob + { + public: + DeleteDelegateJob( const KURL& url, const QByteArray &packedArgs, bool showProgressInfo ); + }; + + class GetDelegatesJob : public KIO::SimpleJob + { + Q_OBJECT + + public: + GetDelegatesJob( const KURL& url, const QByteArray &packedArgs, bool showProgressInfo ); + + Delegate::List delegates() const; + + private slots: + void slotInfoMessage( KIO::Job*, const QString& ); + + private: + Delegate::List mDelegates; + }; + + class AddOtherUserJob : public KIO::SimpleJob + { + public: + AddOtherUserJob( const KURL& url, const QByteArray &packedArgs, bool showProgressInfo ); + }; + + class DeleteOtherUserJob : public KIO::SimpleJob + { + public: + DeleteOtherUserJob( const KURL& url, const QByteArray &packedArgs, bool showProgressInfo ); + }; + + class GetOtherUsersJob : public KIO::SimpleJob + { + Q_OBJECT + + public: + GetOtherUsersJob( const KURL& url, const QByteArray &packedArgs, bool showProgressInfo ); + + QStringList otherUsers() const; + + private slots: + void slotInfoMessage( KIO::Job*, const QString& ); + + private: + QStringList mOtherUsers; + }; + + class SetOutOfOfficeJob : public KIO::SimpleJob + { + public: + SetOutOfOfficeJob( const KURL& url, const QByteArray &packedArgs, bool showProgressInfo ); + }; + + class GetOutOfOfficeJob : public KIO::SimpleJob + { + Q_OBJECT + + public: + GetOutOfOfficeJob( const KURL& url, const QByteArray &packedArgs, bool showProgressInfo ); + + bool enabled() const; + QString message() const; + + private slots: + void slotInfoMessage( KIO::Job*, const QString& ); + + private: + bool mEnabled; + QString mMessage; + }; +} + +#endif diff --git a/kresources/scalix/scalixadmin/ldapdialog.cpp b/kresources/scalix/scalixadmin/ldapdialog.cpp new file mode 100644 index 000000000..be624f131 --- /dev/null +++ b/kresources/scalix/scalixadmin/ldapdialog.cpp @@ -0,0 +1,43 @@ +/* + * This file is part of ScalixAdmin. + * + * Copyright (C) 2007 Trolltech ASA. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <klocale.h> + +#include "ldapview.h" + +#include "ldapdialog.h" + +LdapDialog::LdapDialog( QWidget *parent ) + : KDialogBase( parent, "", true, "", Ok | Cancel, Ok, true ) +{ + setCaption( i18n( "User Account Selection" ) ); + + mView = new LdapView( this ); + setMainWidget( mView ); + + mView->setQuery( "cn=*" ); + + resize( 400, 250 ); +} + +QString LdapDialog::selectedUser() const +{ + return mView->selectedUser(); +} diff --git a/kresources/scalix/scalixadmin/ldapdialog.h b/kresources/scalix/scalixadmin/ldapdialog.h new file mode 100644 index 000000000..6b326f550 --- /dev/null +++ b/kresources/scalix/scalixadmin/ldapdialog.h @@ -0,0 +1,39 @@ +/* + * This file is part of ScalixAdmin. + * + * Copyright (C) 2007 Trolltech ASA. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef LDAPDIALOG_H +#define LDAPDIALOG_H + +#include <kdialogbase.h> + +class LdapView; + +class LdapDialog : public KDialogBase +{ + public: + LdapDialog( QWidget *parent = 0 ); + + QString selectedUser() const; + + + private: + LdapView *mView; +}; + +#endif diff --git a/kresources/scalix/scalixadmin/ldapview.cpp b/kresources/scalix/scalixadmin/ldapview.cpp new file mode 100644 index 000000000..660f1944a --- /dev/null +++ b/kresources/scalix/scalixadmin/ldapview.cpp @@ -0,0 +1,99 @@ +/* + * This file is part of ScalixAdmin. + * + * Copyright (C) 2007 Trolltech ASA. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <kabc/ldapclient.h> +#include <klocale.h> +#include <kmessagebox.h> + +#include "settings.h" + +#include "ldapview.h" + +class LdapItem : public QListViewItem +{ + public: + LdapItem( QListView *parent, const QString &text, const QString &email ) + : QListViewItem( parent ) + { + setText( 0, text ); + setText( 1, email ); + } +}; + + +LdapView::LdapView( QWidget *parent ) + : KListView( parent ) +{ + addColumn( i18n( "User" ) ); + setFullWidth( true ); + + mClient = new KABC::LdapClient; + + mClient->setHost( Settings::self()->ldapHost() ); + mClient->setPort( Settings::self()->ldapPort() ); + mClient->setBase( Settings::self()->ldapBase() ); + mClient->setBindDN( Settings::self()->ldapBindDn() ); + mClient->setPwdBindDN( Settings::self()->ldapPassword() ); + + QStringList attrs; + attrs << "surname" << "mail"; + mClient->setAttrs( attrs ); + + connect( mClient, SIGNAL( result( const KABC::LdapObject& ) ), + this, SLOT( entryAdded( const KABC::LdapObject& ) ) ); + connect( mClient, SIGNAL( error( const QString& ) ), + this, SLOT( error( const QString& ) ) ); +} + +LdapView::~LdapView() +{ + mClient->cancelQuery(); + delete mClient; +} + +QString LdapView::selectedUser() const +{ + QListViewItem *item = selectedItem(); + if ( !item ) + return QString(); + else + return item->text( 1 ); +} + +void LdapView::setQuery( const QString &query ) +{ + clear(); + mClient->startQuery( query ); +} + +void LdapView::entryAdded( const KABC::LdapObject &obj ) +{ + const QString text = QString( "%1 (%2)" ).arg( obj.attrs[ "surname" ].first() ) + .arg( obj.attrs[ "mail" ].first() ); + + new LdapItem( this, text, obj.attrs[ "mail" ].first() ); +} + +void LdapView::error( const QString &msg ) +{ + KMessageBox::error( this, msg ); +} + +#include "ldapview.moc" diff --git a/kresources/scalix/scalixadmin/ldapview.h b/kresources/scalix/scalixadmin/ldapview.h new file mode 100644 index 000000000..0acb3602c --- /dev/null +++ b/kresources/scalix/scalixadmin/ldapview.h @@ -0,0 +1,51 @@ +/* + * This file is part of ScalixAdmin. + * + * Copyright (C) 2007 Trolltech ASA. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef LDAPVIEW_H +#define LDAPVIEW_H + +#include <klistview.h> + +namespace KABC { +class LdapClient; +class LdapObject; +} + +class LdapView : public KListView +{ + Q_OBJECT + + public: + LdapView( QWidget *parent = 0 ); + ~LdapView(); + + QString selectedUser() const; + + public slots: + void setQuery( const QString &query ); + + private slots: + void entryAdded( const KABC::LdapObject& ); + void error( const QString& ); + + private: + KABC::LdapClient *mClient; +}; + +#endif diff --git a/kresources/scalix/scalixadmin/main.cpp b/kresources/scalix/scalixadmin/main.cpp new file mode 100644 index 000000000..d27399210 --- /dev/null +++ b/kresources/scalix/scalixadmin/main.cpp @@ -0,0 +1,53 @@ +/* + * This file is part of ScalixAdmin. + * + * Copyright (C) 2007 Trolltech ASA. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <kaboutdata.h> +#include <kapplication.h> +#include <kcmdlineargs.h> +#include <klocale.h> + +#include "mainwindow.h" + +static const char description[] = I18N_NOOP("Configuration Tool for Scalix Groupware Konnector"); + +static KCmdLineOptions options[] = +{ + KCmdLineLastOption +}; + +int main( int argc, char **argv ) +{ + KAboutData aboutData( "scalixadmin", I18N_NOOP("ScalixAdmin"), "1.0", description, + KAboutData::License_GPL, "(c) 2007, Tobias Koenig" ); + aboutData.addAuthor( "Tobias Koenig",0, "[email protected]" ); + KCmdLineArgs::init( argc, argv, &aboutData ); + KCmdLineArgs::addCmdLineOptions( options ); + + KApplication app; + + KGlobal::locale()->insertCatalogue( "scalixadmin" ); + + MainWindow *window = new MainWindow; + window->show(); + + app.setMainWidget( window ); + + return app.exec(); +} diff --git a/kresources/scalix/scalixadmin/mainwindow.cpp b/kresources/scalix/scalixadmin/mainwindow.cpp new file mode 100644 index 000000000..e6cac550d --- /dev/null +++ b/kresources/scalix/scalixadmin/mainwindow.cpp @@ -0,0 +1,59 @@ +/* + * This file is part of ScalixAdmin. + * + * Copyright (C) 2007 Trolltech ASA. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <qvbox.h> + +#include <kglobal.h> +#include <kiconloader.h> +#include <kjanuswidget.h> +#include <klocale.h> + +#include "delegatepage.h" +#include "otheruserpage.h" +#include "outofofficepage.h" +#include "passwordpage.h" + +#include "mainwindow.h" + +MainWindow::MainWindow() + : KMainWindow( 0 ) +{ + KJanusWidget *wdg = new KJanusWidget( this, "", KJanusWidget::IconList ); + + QPixmap icon = KGlobal::iconLoader()->loadIcon( "folder_yellow", KIcon::Desktop ); + QVBox *page = wdg->addVBoxPage( i18n( "Other Accounts" ), i18n( "Register other accounts" ), icon ); + new OtherUserPage( page ); + + icon = KGlobal::iconLoader()->loadIcon( "edu_languages", KIcon::Desktop ); + page = wdg->addVBoxPage( i18n( "Delegates" ), i18n( "Setup delegates for my account" ), icon ); + new DelegatePage( page ); + + icon = KGlobal::iconLoader()->loadIcon( "kontact_summary_green", KIcon::Desktop ); + page = wdg->addVBoxPage( i18n( "Out of Office..." ), i18n( "Setup Out of Office Message" ), icon ); + new OutOfOfficePage( page ); + + icon = KGlobal::iconLoader()->loadIcon( "password", KIcon::Desktop ); + page = wdg->addVBoxPage( i18n( "Password" ), i18n( "Change the password" ), icon ); + new PasswordPage( page ); + + setCentralWidget( wdg ); + + resize( 540, 450 ); +} diff --git a/kresources/scalix/scalixadmin/mainwindow.h b/kresources/scalix/scalixadmin/mainwindow.h new file mode 100644 index 000000000..38c955980 --- /dev/null +++ b/kresources/scalix/scalixadmin/mainwindow.h @@ -0,0 +1,32 @@ +/* + * This file is part of ScalixAdmin. + * + * Copyright (C) 2007 Trolltech ASA. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include <kmainwindow.h> + +class MainWindow : public KMainWindow +{ + public: + MainWindow(); +}; + +#endif diff --git a/kresources/scalix/scalixadmin/otherusermanager.cpp b/kresources/scalix/scalixadmin/otherusermanager.cpp new file mode 100644 index 000000000..b5b3d3ccf --- /dev/null +++ b/kresources/scalix/scalixadmin/otherusermanager.cpp @@ -0,0 +1,51 @@ +/* + * This file is part of ScalixAdmin. + * + * Copyright (C) 2007 Trolltech ASA. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "otherusermanager.h" + +OtherUserManager::OtherUserManager() +{ +} + +OtherUserManager::~OtherUserManager() +{ +} + +void OtherUserManager::addOtherUser( const QString &email ) +{ + if ( !mOtherUsers.contains( email ) ) { + mOtherUsers.append( email ); + emit changed(); + } +} + +void OtherUserManager::clear() +{ + mOtherUsers.clear(); + + emit changed(); +} + +QStringList OtherUserManager::otherUsers() const +{ + return mOtherUsers; +} + +#include "otherusermanager.moc" diff --git a/kresources/scalix/scalixadmin/otherusermanager.h b/kresources/scalix/scalixadmin/otherusermanager.h new file mode 100644 index 000000000..6f7f9ac77 --- /dev/null +++ b/kresources/scalix/scalixadmin/otherusermanager.h @@ -0,0 +1,47 @@ +/* + * This file is part of ScalixAdmin. + * + * Copyright (C) 2007 Trolltech ASA. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef OTHERUSERMANAGER_H +#define OTHERUSERMANAGER_H + +#include <qobject.h> +#include <qstringlist.h> + +class OtherUserManager : public QObject +{ + Q_OBJECT + + public: + OtherUserManager(); + ~OtherUserManager(); + + void addOtherUser( const QString &email ); + void clear(); + + QStringList otherUsers() const; + + signals: + void changed(); + + private: + QStringList mOtherUsers; +}; + +#endif diff --git a/kresources/scalix/scalixadmin/otheruserpage.cpp b/kresources/scalix/scalixadmin/otheruserpage.cpp new file mode 100644 index 000000000..ae12290c7 --- /dev/null +++ b/kresources/scalix/scalixadmin/otheruserpage.cpp @@ -0,0 +1,173 @@ +/* + * This file is part of ScalixAdmin. + * + * Copyright (C) 2007 Trolltech ASA. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <qapplication.h> +#include <qlayout.h> +#include <qpushbutton.h> + +#include <dcopref.h> +#include <kdcopservicestarter.h> +#include <kinputdialog.h> +#include <klocale.h> +#include <kmessagebox.h> + +#include <unistd.h> + +#include "jobs.h" +#include "ldapdialog.h" +#include "otheruserview.h" +#include "settings.h" + +#include "otheruserpage.h" + +OtherUserPage::OtherUserPage( QWidget *parent ) + : QWidget( parent ) +{ + QGridLayout *layout = new QGridLayout( this, 2, 2, 11, 6 ); + + mView = new OtherUserView( &mManager, this ); + layout->addMultiCellWidget( mView, 0, 0, 0, 1 ); + + mAddButton = new QPushButton( i18n( "Add Account..." ), this ); + layout->addWidget( mAddButton, 1, 0 ); + + mDeleteButton = new QPushButton( i18n( "Remove Account" ), this ); + mDeleteButton->setEnabled( false ); + layout->addWidget( mDeleteButton, 1, 1 ); + + connect( mView, SIGNAL( selectionChanged() ), SLOT( selectionChanged() ) ); + connect( mAddButton, SIGNAL( clicked() ), SLOT( addUser() ) ); + connect( mDeleteButton, SIGNAL( clicked() ), SLOT( removeUser() ) ); + + loadAllUsers(); +} + +OtherUserPage::~OtherUserPage() +{ +} + +void OtherUserPage::loadAllUsers() +{ + Scalix::GetOtherUsersJob *job = Scalix::getOtherUsers( Settings::self()->globalSlave(), + Settings::self()->accountUrl() ); + connect( job, SIGNAL( result( KIO::Job* ) ), SLOT( allUsers( KIO::Job* ) ) ); +} + +void OtherUserPage::addUser() +{ + LdapDialog dlg( this ); + if ( !dlg.exec() ) + return; + + const QString email = dlg.selectedUser(); + if ( email.isEmpty() ) + return; + + Scalix::AddOtherUserJob *job = Scalix::addOtherUser( Settings::self()->globalSlave(), + Settings::self()->accountUrl(), email ); + connect( job, SIGNAL( result( KIO::Job* ) ), SLOT( userAdded( KIO::Job* ) ) ); +} + +void OtherUserPage::removeUser() +{ + const QString email = mView->selectedUser(); + if ( email.isEmpty() ) + return; + + Scalix::DeleteOtherUserJob *job = Scalix::deleteOtherUser( Settings::self()->globalSlave(), + Settings::self()->accountUrl(), email ); + connect( job, SIGNAL( result( KIO::Job* ) ), SLOT( userRemoved( KIO::Job* ) ) ); +} + +void OtherUserPage::allUsers( KIO::Job *job ) +{ + if ( job->error() ) + KMessageBox::error( this, job->errorString() ); + + Scalix::GetOtherUsersJob *userJob = static_cast<Scalix::GetOtherUsersJob*>( job ); + + mManager.clear(); + + const QStringList users = userJob->otherUsers(); + for ( uint i = 0; i < users.count(); ++i ) + mManager.addOtherUser( users[ i ] ); + + selectionChanged(); +} + +void OtherUserPage::userAdded( KIO::Job *job ) +{ + if ( job->error() ) + KMessageBox::error( this, job->errorString() ); + else + loadAllUsers(); // update the GUI + + updateKmail(); +} + +void OtherUserPage::userRemoved( KIO::Job *job ) +{ + if ( job->error() ) + KMessageBox::error( this, job->errorString() ); + else + loadAllUsers(); // update the GUI + + updateKmail(); +} + +void OtherUserPage::selectionChanged() +{ + mDeleteButton->setEnabled( mView->selectedItem() != 0 ); +} + +void OtherUserPage::updateKmail() +{ + QMessageBox *msg = new QMessageBox( qApp->mainWidget() ); + msg->setText( i18n( "Updating account..." ) ); + msg->show(); + qApp->processEvents(); + sleep( 1 ); + qApp->processEvents(); + + QString error; + QCString dcopService; + int result = KDCOPServiceStarter::self()-> + findServiceFor( "DCOP/ResourceBackend/IMAP", QString::null, + QString::null, &error, &dcopService ); + if ( result != 0 ) { + KMessageBox::error( 0, i18n( "Unable to start KMail to trigger account update with Scalix server" ) ); + delete msg; + return; + } + + DCOPRef ref( dcopService, "KMailIface" ); + + // loop until dcop iface is set up correctly + QStringList list; + while ( list.isEmpty() ) { + ref.call( "accounts()" ).get( list ); + } + + ref.call( "checkAccount(QString)", i18n( "Scalix Server" ) ); + + delete msg; +} + +#include "otheruserpage.moc" diff --git a/kresources/scalix/scalixadmin/otheruserpage.h b/kresources/scalix/scalixadmin/otheruserpage.h new file mode 100644 index 000000000..f847a05d3 --- /dev/null +++ b/kresources/scalix/scalixadmin/otheruserpage.h @@ -0,0 +1,60 @@ +/* + * This file is part of ScalixAdmin. + * + * Copyright (C) 2007 Trolltech ASA. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef OTHERUSERPAGE_H +#define OTHERUSERPAGE_H + +#include <qwidget.h> + +#include "otherusermanager.h" + +class QPushButton; +class OtherUserView; + +class OtherUserPage : public QWidget +{ + Q_OBJECT + + public: + OtherUserPage( QWidget *parent = 0 ); + ~OtherUserPage(); + + private slots: + void loadAllUsers(); + void addUser(); + void removeUser(); + + void userAdded( KIO::Job* ); + void userRemoved( KIO::Job* ); + void allUsers( KIO::Job* ); + + void selectionChanged(); + + private: + void updateKmail(); + + QPushButton *mAddButton; + QPushButton *mDeleteButton; + + OtherUserManager mManager; + OtherUserView *mView; +}; + +#endif diff --git a/kresources/scalix/scalixadmin/otheruserview.cpp b/kresources/scalix/scalixadmin/otheruserview.cpp new file mode 100644 index 000000000..70bc9e3d5 --- /dev/null +++ b/kresources/scalix/scalixadmin/otheruserview.cpp @@ -0,0 +1,71 @@ +/* + * This file is part of ScalixAdmin. + * + * Copyright (C) 2007 Trolltech ASA. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <klocale.h> + +#include "otherusermanager.h" + +#include "otheruserview.h" + +class OtherUserItem : public QListViewItem +{ + public: + OtherUserItem( QListView *parent, const QString &user ) + : QListViewItem( parent ), mUser( user ) + { + setText( 0, mUser ); + } + + QString user() const { return mUser; } + + private: + QString mUser; +}; + +OtherUserView::OtherUserView( OtherUserManager *manager, QWidget *parent ) + : KListView( parent ), mManager( manager ) +{ + addColumn( i18n( "Registered Accounts" ) ); + setFullWidth( true ); + + connect( mManager, SIGNAL( changed() ), SLOT( userChanged() ) ); + + userChanged(); +} + +QString OtherUserView::selectedUser() const +{ + OtherUserItem *item = dynamic_cast<OtherUserItem*>( selectedItem() ); + if ( item ) + return item->user(); + + return QString(); +} + +void OtherUserView::userChanged() +{ + clear(); + + QStringList users = mManager->otherUsers(); + for ( uint i = 0; i < users.count(); ++i ) + new OtherUserItem( this, users[ i ] ); +} + +#include "otheruserview.moc" diff --git a/kresources/scalix/scalixadmin/otheruserview.h b/kresources/scalix/scalixadmin/otheruserview.h new file mode 100644 index 000000000..6eacc93c9 --- /dev/null +++ b/kresources/scalix/scalixadmin/otheruserview.h @@ -0,0 +1,44 @@ +/* + * This file is part of ScalixAdmin. + * + * Copyright (C) 2007 Trolltech ASA. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef OTHERUSERVIEW_H +#define OTHERUSERVIEW_H + +#include <klistview.h> + +class OtherUserManager; + +class OtherUserView : public KListView +{ + Q_OBJECT + + public: + OtherUserView( OtherUserManager *manager, QWidget *parent = 0 ); + + QString selectedUser() const; + + private slots: + void userChanged(); + + private: + OtherUserManager *mManager; +}; + +#endif diff --git a/kresources/scalix/scalixadmin/outofofficepage.cpp b/kresources/scalix/scalixadmin/outofofficepage.cpp new file mode 100644 index 000000000..0b8d3f803 --- /dev/null +++ b/kresources/scalix/scalixadmin/outofofficepage.cpp @@ -0,0 +1,125 @@ +/* + * This file is part of ScalixAdmin. + * + * Copyright (C) 2007 Trolltech ASA. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <qbuttongroup.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qpushbutton.h> +#include <qradiobutton.h> +#include <qtextedit.h> + +#include <klocale.h> +#include <kmessagebox.h> + +#include "jobs.h" +#include "settings.h" + +#include "outofofficepage.h" + +OutOfOfficePage::OutOfOfficePage( QWidget *parent ) + : QWidget( parent ) +{ + QGridLayout *layout = new QGridLayout( this, 4, 2, 11, 6 ); + + QButtonGroup *group = new QButtonGroup( 1, Qt::Vertical, this ); + + mDisabled = new QRadioButton( i18n( "I am in the office" ), group ); + mDisabled->setChecked( true ); + mEnabled = new QRadioButton( i18n( "I am out of the office" ), group ); + + mLabel = new QLabel( i18n( "Auto-reply once to each sender with the following text:" ), this ); + mMessage = new QTextEdit( this ); + mSaveButton = new QPushButton( i18n( "Save" ), this ); + + layout->addMultiCellWidget( group, 0, 0, 0, 1 ); + layout->addMultiCellWidget( mLabel, 1, 1, 0, 1 ); + layout->addMultiCellWidget( mMessage, 2, 2, 0, 1 ); + layout->addWidget( mSaveButton, 3, 1 ); + + statusChanged(); + + connect( mEnabled, SIGNAL( toggled( bool ) ), this, SLOT( statusChanged() ) ); + connect( mEnabled, SIGNAL( toggled( bool ) ), this, SLOT( changed() ) ); + connect( mSaveButton, SIGNAL( clicked() ), this, SLOT( store() ) ); + connect( mMessage, SIGNAL( textChanged() ), this, SLOT( changed() ) ); + + load(); +} + +OutOfOfficePage::~OutOfOfficePage() +{ +} + +void OutOfOfficePage::load() +{ + Scalix::GetOutOfOfficeJob *job = Scalix::getOutOfOffice( Settings::self()->globalSlave(), + Settings::self()->accountUrl() ); + connect( job, SIGNAL( result( KIO::Job* ) ), SLOT( loaded( KIO::Job* ) ) ); +} + +void OutOfOfficePage::loaded( KIO::Job* job ) +{ + if ( job->error() ) { + KMessageBox::error( this, job->errorString() ); + return; + } + + Scalix::GetOutOfOfficeJob *outOfOfficeJob = static_cast<Scalix::GetOutOfOfficeJob*>( job ); + + mEnabled->setChecked( outOfOfficeJob->enabled() ); + mMessage->setText( outOfOfficeJob->message() ); + + statusChanged(); + + mSaveButton->setEnabled( false ); +} + +void OutOfOfficePage::store() +{ + Scalix::SetOutOfOfficeJob *job = Scalix::setOutOfOffice( Settings::self()->globalSlave(), + Settings::self()->accountUrl(), + mEnabled->isChecked(), + mMessage->text() ); + + connect( job, SIGNAL( result( KIO::Job* ) ), SLOT( stored( KIO::Job* ) ) ); + + mSaveButton->setEnabled( false ); +} + +void OutOfOfficePage::stored( KIO::Job* job ) +{ + if ( job->error() ) + KMessageBox::error( this, job->errorString() ); +} + +void OutOfOfficePage::statusChanged() +{ + bool state = mEnabled->isChecked(); + + mLabel->setEnabled( state ); + mMessage->setEnabled( state ); +} + +void OutOfOfficePage::changed() +{ + mSaveButton->setEnabled( true ); +} + +#include "outofofficepage.moc" diff --git a/kresources/scalix/scalixadmin/outofofficepage.h b/kresources/scalix/scalixadmin/outofofficepage.h new file mode 100644 index 000000000..cc5b2591a --- /dev/null +++ b/kresources/scalix/scalixadmin/outofofficepage.h @@ -0,0 +1,57 @@ +/* + * This file is part of ScalixAdmin. + * + * Copyright (C) 2007 Trolltech ASA. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef OUTOFOFFICEPAGE_H +#define OUTOFOFFICEPAGE_H + +#include <qwidget.h> + +class QLabel; +class QPushButton; +class QRadioButton; +class QTextEdit; + +class OutOfOfficePage : public QWidget +{ + Q_OBJECT + + public: + OutOfOfficePage( QWidget *parent = 0 ); + ~OutOfOfficePage(); + + private slots: + void load(); + void loaded( KIO::Job* ); + void store(); + void stored( KIO::Job* ); + void statusChanged(); + void changed(); + + private: + QRadioButton *mEnabled; + QRadioButton *mDisabled; + QLabel *mLabel; + QTextEdit *mMessage; + QPushButton *mSaveButton; + + bool mChanged; +}; + +#endif diff --git a/kresources/scalix/scalixadmin/passwordpage.cpp b/kresources/scalix/scalixadmin/passwordpage.cpp new file mode 100644 index 000000000..7d4182348 --- /dev/null +++ b/kresources/scalix/scalixadmin/passwordpage.cpp @@ -0,0 +1,190 @@ +/* + * This file is part of ScalixAdmin. + * + * Copyright (C) 2007 Trolltech ASA. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <qapplication.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qlineedit.h> +#include <qpushbutton.h> + +#include <kconfig.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kstringhandler.h> +#include <kwallet.h> + +#include "jobs.h" +#include "settings.h" + +#include "passwordpage.h" + +PasswordPage::PasswordPage( QWidget *parent ) + : QWidget( parent ), mJob( 0 ) +{ + QGridLayout *layout = new QGridLayout( this, 2, 3, 11, 6 ); + + QLabel *label = new QLabel( i18n( "New password:" ), this ); + layout->addWidget( label, 0, 0 ); + + mPassword = new QLineEdit( this ); + mPassword->setEchoMode( QLineEdit::Password ); + label->setBuddy( mPassword ); + layout->addWidget( mPassword, 0, 1 ); + + label = new QLabel( i18n( "Retype new password:" ), this ); + layout->addWidget( label, 1, 0 ); + + mPasswordRetype = new QLineEdit( this ); + mPasswordRetype->setEchoMode( QLineEdit::Password ); + label->setBuddy( mPasswordRetype ); + layout->addWidget( mPasswordRetype, 1, 1 ); + + mButton = new QPushButton( i18n( "Change" ), this ); + mButton->setEnabled( false ); + layout->addWidget( mButton, 2, 1 ); + + layout->setRowSpacing( 3, 1 ); + + connect( mPassword, SIGNAL( textChanged( const QString& ) ), this, SLOT( textChanged() ) ); + connect( mPasswordRetype, SIGNAL( textChanged( const QString& ) ), this, SLOT( textChanged() ) ); + connect( mButton, SIGNAL( clicked() ), this, SLOT( buttonClicked() ) ); +} + +void PasswordPage::buttonClicked() +{ + if ( !mJob ) { + if ( mPassword->text() != mPasswordRetype->text() ) { + KMessageBox::error( this, i18n( "The two passwords differ!" ) ); + return; + } + + mJob = Scalix::setPassword( Settings::self()->globalSlave(), Settings::self()->accountUrl(), + Settings::self()->accountPassword(), mPassword->text() ); + connect( mJob, SIGNAL( result( KIO::Job* ) ), this, SLOT( finished( KIO::Job* ) ) ); + + updateState( true ); + } else { + mJob->kill(); + mJob = 0; + + updateState( false ); + } +} + +void PasswordPage::updateState( bool isWorking ) +{ + if ( isWorking ) { + mPassword->setEnabled( false ); + mPasswordRetype->setEnabled( false ); + mButton->setText( i18n( "Stop" ) ); + } else { + mPassword->setEnabled( true ); + mPasswordRetype->setEnabled( true ); + mButton->setText( i18n( "Change" ) ); + } +} + +void PasswordPage::textChanged() +{ + mButton->setEnabled( !mPassword->text().isEmpty() && + !mPasswordRetype->text().isEmpty() ); +} + +void PasswordPage::finished( KIO::Job* job ) +{ + mJob = 0; + + updateState( false ); + + if ( job->error() ) { + KMessageBox::error( this, i18n( "Unable to change the password" ) + "\n" + job->errorString() ); + return; + } + + // Update configuration files to the new password as well + + const QString newPassword = mPassword->text(); + + { // ScalixAdmin config + KConfig config( "scalixadminrc" ); + KConfigGroup group( &config, "Account" ); + group.writeEntry( "pass", KStringHandler::obscure( newPassword ) ); + } + + { // ScalixWizard config + KConfig config( "scalixrc" ); + KConfigGroup group( &config, "General" ); + group.writeEntry( "Password", KStringHandler::obscure( newPassword ) ); + } + + { // KMail config + KConfig config( "kmailrc" ); + + // Try to find account group for Scalix + QString scalixAccount; + const QStringList groupList = config.groupList(); + for ( uint i = 0; i < groupList.count(); ++i ) { + if ( groupList[ i ].startsWith( "Account " ) ) { + KConfigGroup group( &config, groupList[ i ] ); + if ( group.hasKey( "groupwareType" ) && group.readNumEntry( "groupwareType" ) == 2 ) { + scalixAccount = groupList[ i ]; + break; + } + } + } + + if ( scalixAccount.isEmpty() ) { + qWarning( "No Scalix Groupware Account found in kmailrc!" ); + return; + } + + const int accountId = scalixAccount.mid( 8 ).toInt(); + + KConfigGroup group( &config, scalixAccount ); + + // Save only if the user choose it before + bool storePassword = group.readBoolEntry( "store-passwd", false ); + if ( storePassword ) { + // First try to store in KWallet + if ( KWallet::Wallet::isEnabled() ) { + WId window = 0; + if ( qApp->activeWindow() ) + window = qApp->activeWindow()->winId(); + + KWallet::Wallet *wallet = KWallet::Wallet::openWallet( KWallet::Wallet::NetworkWallet(), window ); + if ( wallet ) { + if ( !wallet->hasFolder( "kmail" ) ) + wallet->createFolder( "kmail" ); + wallet->setFolder( "kmail" ); + wallet->writePassword( "account-" + QString::number( accountId ), newPassword ); + } + } else { + group.writeEntry( "pass", KStringHandler::obscure( newPassword ) ); + } + + KConfigGroup fileGroup( &config, QString( "Folder-%1" ).arg( group.readNumEntry( "Folder" ) ) ); + fileGroup.writeEntry( "pass", KStringHandler::obscure( newPassword ) ); + } + } + + KMessageBox::information( this, i18n( "Password was changed successfully" ) ); +} + +#include "passwordpage.moc" diff --git a/kresources/scalix/scalixadmin/passwordpage.h b/kresources/scalix/scalixadmin/passwordpage.h new file mode 100644 index 000000000..a397be416 --- /dev/null +++ b/kresources/scalix/scalixadmin/passwordpage.h @@ -0,0 +1,55 @@ +/* + * This file is part of ScalixAdmin. + * + * Copyright (C) 2007 Trolltech ASA. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef PASSWORDPAGE_H +#define PASSWORDPAGE_H + +#include <qwidget.h> + +class QLineEdit; +class QPushButton; + +namespace KIO { +class Job; +} + +class PasswordPage : public QWidget +{ + Q_OBJECT + + public: + PasswordPage( QWidget *parent = 0 ); + + private slots: + void buttonClicked(); + void finished( KIO::Job* ); + void textChanged(); + + private: + void updateState( bool ); + + QLineEdit *mPassword; + QLineEdit *mPasswordRetype; + QPushButton *mButton; + + KIO::Job *mJob; +}; + +#endif diff --git a/kresources/scalix/scalixadmin/settings.cpp b/kresources/scalix/scalixadmin/settings.cpp new file mode 100644 index 000000000..2f6b49bad --- /dev/null +++ b/kresources/scalix/scalixadmin/settings.cpp @@ -0,0 +1,136 @@ +/* + * This file is part of ScalixAdmin. + * + * Copyright (C) 2007 Trolltech ASA. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <kconfig.h> +#include <kio/scheduler.h> +#include <kstringhandler.h> + +#include "settings.h" + +Settings* Settings::mSelf = 0; + +Settings::Settings() +{ + mSlave = KIO::Scheduler::getConnectedSlave( accountUrl(), + accountData() ); +} + +Settings::~Settings() +{ +} + +Settings* Settings::self() +{ + if ( !mSelf ) + mSelf = new Settings; + + return mSelf; +} + +KIO::MetaData Settings::accountData() const +{ + KConfig config( "scalixadminrc" ); + KConfigGroup group( &config, "Account" ); + + KIO::MetaData data; + data.insert( "auth", group.readEntry( "auth" ) ); + data.insert( "tls", group.readBoolEntry( "use-tls" ) ? "on" : "off" ); + + return data; +} + +KURL Settings::accountUrl() const +{ + KConfig config( "scalixadminrc" ); + KConfigGroup group( &config, "Account" ); + + KURL url; + url.setProtocol( group.readBoolEntry( "use-ssl" ) ? "imaps" : "imap" ); + url.setUser( group.readEntry( "user" ) ); + url.setPass( KStringHandler::obscure( group.readEntry( "pass" ) ) ); + url.setHost( group.readEntry( "host" ) ); + url.setPort( group.readNumEntry( "port" ) ); + + return url; +} + +QString Settings::accountPassword() const +{ + KConfig config( "scalixadminrc" ); + KConfigGroup group( &config, "Account" ); + + return KStringHandler::obscure( group.readEntry( "pass" ) ); +} + +KIO::Slave* Settings::globalSlave() const +{ + return mSlave; +} + +QString Settings::rulesWizardUrl() const +{ + KConfig config( "scalixadminrc" ); + KConfigGroup group( &config, "Misc" ); + + QString url = group.readEntry( "rulesWizardUrl" ); + if ( url.isEmpty() ) { + KConfigGroup group( &config, "Account" ); + url = QString( "http://%1/Scalix/rw/?username=%2" ).arg( group.readEntry( "host" ) ) + .arg( group.readEntry( "user" ) ); + } + + return url; +} + +QString Settings::ldapHost() const +{ + KConfig config( "scalixadminrc" ); + KConfigGroup group( &config, "LDAP" ); + return group.readEntry( "host" ); +} + +QString Settings::ldapPort() const +{ + KConfig config( "scalixadminrc" ); + KConfigGroup group( &config, "LDAP" ); + return group.readEntry( "port" ); +} + +QString Settings::ldapBase() const +{ + KConfig config( "scalixadminrc" ); + KConfigGroup group( &config, "LDAP" ); + return group.readEntry( "base" ); +} + +QString Settings::ldapBindDn() const +{ + KConfig config( "scalixadminrc" ); + KConfigGroup group( &config, "LDAP" ); + return group.readEntry( "bindDn" ); +} + +QString Settings::ldapPassword() const +{ + KConfig config( "scalixadminrc" ); + KConfigGroup group( &config, "LDAP" ); + return group.readEntry( "password" ); +} + diff --git a/kresources/scalix/scalixadmin/settings.h b/kresources/scalix/scalixadmin/settings.h new file mode 100644 index 000000000..17ed9a2c9 --- /dev/null +++ b/kresources/scalix/scalixadmin/settings.h @@ -0,0 +1,56 @@ +/* + * This file is part of ScalixAdmin. + * + * Copyright (C) 2007 Trolltech ASA. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef SETTINGS_H +#define SETTINGS_H + +#include <kurl.h> +#include <kio/global.h> +#include <kio/slave.h> + +class Settings +{ + public: + ~Settings(); + + static Settings* self(); + + KIO::MetaData accountData() const; + KURL accountUrl() const; + QString accountPassword() const; + + KIO::Slave *globalSlave() const; + + QString rulesWizardUrl() const; + + QString ldapHost() const; + QString ldapPort() const; + QString ldapBase() const; + QString ldapBindDn() const; + QString ldapPassword() const; + + private: + Settings(); + KIO::Slave *mSlave; + + static Settings* mSelf; +}; + +#endif diff --git a/kresources/scalix/shared/Makefile.am b/kresources/scalix/shared/Makefile.am new file mode 100644 index 000000000..4aaa9304e --- /dev/null +++ b/kresources/scalix/shared/Makefile.am @@ -0,0 +1,17 @@ +INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/kresources/lib $(all_includes) + +noinst_HEADERS = resourcescalixbase.h scalixbase.h subresource.h + +noinst_LTLIBRARIES = libresourcescalixshared.la + +libresourcescalixshared_la_SOURCES = \ + resourcescalixbase.cpp kmailconnection.cpp scalixbase.cpp \ + subresource.cpp \ + kmailconnection.skel kmailicalIface.stub +libresourcescalixshared_la_METASOURCES = AUTO +libresourcescalixshared_la_LIBADD = $(top_builddir)/libkcal/libkcal.la $(top_builddir)/libkdepim/libkdepim.la ../../lib/libkgroupwaredav.la +libresourcescalixshared_la_LDFLAGS = -no-undefined + +kmailicalIface_DCOPIDLNG = true + +kmailicalIface_DIR = $(top_srcdir)/kmail diff --git a/kresources/scalix/shared/kmailconnection.cpp b/kresources/scalix/shared/kmailconnection.cpp new file mode 100644 index 000000000..af32cd74b --- /dev/null +++ b/kresources/scalix/shared/kmailconnection.cpp @@ -0,0 +1,281 @@ +/* + This file is part of the scalix resource - based on the kolab resource. + + Copyright (c) 2004 Bo Thorsen <[email protected]> + + 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 "kmailconnection.h" +#include "resourcescalixbase.h" + +#include <kdebug.h> +#include <dcopclient.h> +#include <kapplication.h> +#include <kdcopservicestarter.h> +#include <klocale.h> + +#include "kmailicalIface_stub.h" + + +using namespace Scalix; + + +KMailConnection::KMailConnection( ResourceScalixBase* resource, + const QCString& objId ) + : DCOPObject( objId ), mResource( resource ), mKMailIcalIfaceStub( 0 ) +{ + // Make the connection to KMail ready + mDCOPClient = new DCOPClient(); + mDCOPClient->attach(); + mDCOPClient->registerAs( objId, true ); + + kapp->dcopClient()->setNotifications( true ); + connect( kapp->dcopClient(), SIGNAL( applicationRemoved( const QCString& ) ), + this, SLOT( unregisteredFromDCOP( const QCString& ) ) ); +} + +KMailConnection::~KMailConnection() +{ + kapp->dcopClient()->setNotifications( false ); + delete mKMailIcalIfaceStub; + mKMailIcalIfaceStub = 0; + delete mDCOPClient; + mDCOPClient = 0; +} + +static const QCString dcopObjectId = "KMailICalIface"; +bool KMailConnection::connectToKMail() +{ + if ( !mKMailIcalIfaceStub ) { + QString error; + QCString dcopService; + int result = KDCOPServiceStarter::self()-> + findServiceFor( "DCOP/ResourceBackend/IMAP", QString::null, + QString::null, &error, &dcopService ); + if ( result != 0 ) { + kdError(5650) << "Couldn't connect to the IMAP resource backend\n"; + // TODO: You might want to show "error" (if not empty) here, + // using e.g. KMessageBox + return false; + } + + mKMailIcalIfaceStub = new KMailICalIface_stub( kapp->dcopClient(), + dcopService, dcopObjectId ); + + // Attach to the KMail signals + if ( !connectKMailSignal( "incidenceAdded(QString,QString,Q_UINT32,int,QString)", + "fromKMailAddIncidence(QString,QString,Q_UINT32,int,QString)" ) ) + kdError(5650) << "DCOP connection to incidenceAdded failed" << endl; + if ( !connectKMailSignal( "incidenceDeleted(QString,QString,QString)", + "fromKMailDelIncidence(QString,QString,QString)" ) ) + kdError(5650) << "DCOP connection to incidenceDeleted failed" << endl; + if ( !connectKMailSignal( "signalRefresh(QString,QString)", + "fromKMailRefresh(QString,QString)" ) ) + kdError(5650) << "DCOP connection to signalRefresh failed" << endl; + if ( !connectKMailSignal( "subresourceAdded( QString, QString, QString )", + "fromKMailAddSubresource( QString, QString, QString )" ) ) + kdError(5650) << "DCOP connection to subresourceAdded failed" << endl; + if ( !connectKMailSignal( "subresourceDeleted(QString,QString)", + "fromKMailDelSubresource(QString,QString)" ) ) + kdError(5650) << "DCOP connection to subresourceDeleted failed" << endl; + if ( !connectKMailSignal( "asyncLoadResult(QMap<Q_UINT32, QString>, QString, QString)", + "fromKMailAsyncLoadResult(QMap<Q_UINT32, QString>, QString, QString)" ) ) + kdError(5650) << "DCOP connection to asyncLoadResult failed" << endl; + } + + return ( mKMailIcalIfaceStub != 0 ); +} + +bool KMailConnection::fromKMailAddIncidence( const QString& type, + const QString& folder, + Q_UINT32 sernum, + int format, + const QString& data ) +{ + if ( format != KMailICalIface::StorageXML + && format != KMailICalIface::StorageIcalVcard ) + return false; +// kdDebug(5650) << "KMailConnection::fromKMailAddIncidence( " << type << ", " +// << folder << " ). iCal:\n" << ical << endl; + return mResource->fromKMailAddIncidence( type, folder, sernum, format, data ); +} + +void KMailConnection::fromKMailDelIncidence( const QString& type, + const QString& folder, + const QString& xml ) +{ +// kdDebug(5650) << "KMailConnection::fromKMailDelIncidence( " << type << ", " +// << folder << ", " << uid << " )\n"; + mResource->fromKMailDelIncidence( type, folder, xml ); +} + +void KMailConnection::fromKMailRefresh( const QString& type, const QString& folder ) +{ +// kdDebug(5650) << "KMailConnection::fromKMailRefresh( " << type << ", " +// << folder << " )\n"; + mResource->fromKMailRefresh( type, folder ); +} + +void KMailConnection::fromKMailAddSubresource( const QString& type, + const QString& resource, + const QString& label ) +{ +// kdDebug(5650) << "KMailConnection::fromKMailAddSubresource( " << type << ", " +// << resource << " )\n"; + bool writable = true; + + // TODO: This should be told by KMail right away + if ( connectToKMail() ) + writable = mKMailIcalIfaceStub->isWritableFolder( type, resource ); + + mResource->fromKMailAddSubresource( type, resource, label, writable ); +} + +void KMailConnection::fromKMailDelSubresource( const QString& type, + const QString& resource ) +{ +// kdDebug(5650) << "KMailConnection::fromKMailDelSubresource( " << type << ", " +// << resource << " )\n"; + mResource->fromKMailDelSubresource( type, resource ); +} + +void KMailConnection::fromKMailAsyncLoadResult( const QMap<Q_UINT32, QString>& map, + const QString& type, + const QString& folder ) +{ + mResource->fromKMailAsyncLoadResult( map, type, folder ); +} + +bool KMailConnection::connectKMailSignal( const QCString& signal, + const QCString& method ) +{ + return connectDCOPSignal( "kmail", dcopObjectId, signal, method, false ) + && connectDCOPSignal( "kontact", dcopObjectId, signal, method, false ); +} + +bool KMailConnection::kmailSubresources( QValueList<KMailICalIface::SubResource>& lst, + const QString& contentsType ) +{ + if ( !connectToKMail() ) + return false; + + lst = mKMailIcalIfaceStub->subresourcesKolab( contentsType ); + return mKMailIcalIfaceStub->ok(); +} + +bool KMailConnection::kmailIncidencesCount( int& count, + const QString& mimetype, + const QString& resource ) +{ + if ( !connectToKMail() ) + return false; + + count = mKMailIcalIfaceStub->incidencesKolabCount( mimetype, resource ); + return mKMailIcalIfaceStub->ok(); +} + +bool KMailConnection::kmailIncidences( QMap<Q_UINT32, QString>& lst, + const QString& mimetype, + const QString& resource, + int startIndex, + int nbMessages ) +{ + if ( !connectToKMail() ) + return false; + + lst = mKMailIcalIfaceStub->incidencesKolab( mimetype, resource, startIndex, nbMessages ); + return mKMailIcalIfaceStub->ok(); +} + + +bool KMailConnection::kmailGetAttachment( KURL& url, + const QString& resource, + Q_UINT32 sernum, + const QString& filename ) +{ + if ( !connectToKMail() ) + return false; + + url = mKMailIcalIfaceStub->getAttachment( resource, sernum, filename ); + return mKMailIcalIfaceStub->ok(); +} + +bool KMailConnection::kmailDeleteIncidence( const QString& resource, + Q_UINT32 sernum ) +{ + return connectToKMail() + && mKMailIcalIfaceStub->deleteIncidenceKolab( resource, sernum ) + && mKMailIcalIfaceStub->ok(); +} + +bool KMailConnection::kmailUpdate( const QString& resource, + Q_UINT32& sernum, + const QString& subject, + const QString& plainTextBody, + const QMap<QCString, QString>& customHeaders, + const QStringList& attachmentURLs, + const QStringList& attachmentMimetypes, + const QStringList& attachmentNames, + const QStringList& deletedAttachments ) +{ + //kdDebug(5006) << kdBacktrace() << endl; + if ( connectToKMail() ) { + sernum = mKMailIcalIfaceStub->update( resource, sernum, subject, plainTextBody, customHeaders, + attachmentURLs, attachmentMimetypes, attachmentNames, + deletedAttachments ); + return sernum && mKMailIcalIfaceStub->ok(); + } else + return false; +} + +bool KMailConnection::kmailStorageFormat( KMailICalIface::StorageFormat& type, + const QString& folder ) +{ + bool ok = connectToKMail(); + type = mKMailIcalIfaceStub->storageFormat( folder ); + return ok && mKMailIcalIfaceStub->ok(); +} + + +bool KMailConnection::kmailTriggerSync( const QString &contentsType ) +{ + bool ok = connectToKMail(); + return ok && mKMailIcalIfaceStub->triggerSync( contentsType ); +} + +void KMailConnection::unregisteredFromDCOP( const QCString& appId ) +{ + if ( mKMailIcalIfaceStub && mKMailIcalIfaceStub->app() == appId ) { + // Delete the stub so that the next time we need to talk to kmail, + // we'll know that we need to start a new one. + delete mKMailIcalIfaceStub; + mKMailIcalIfaceStub = 0; + } +} + +#include "kmailconnection.moc" diff --git a/kresources/scalix/shared/kmailconnection.h b/kresources/scalix/shared/kmailconnection.h new file mode 100644 index 000000000..ea57857a8 --- /dev/null +++ b/kresources/scalix/shared/kmailconnection.h @@ -0,0 +1,117 @@ +/* + This file is part of the scalix resource - based on the kolab resource. + + Copyright (c) 2004 Bo Thorsen <[email protected]> + + 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 KMAILCONNECTION_H +#define KMAILCONNECTION_H + +#include <dcopobject.h> +#include <kmail/kmailicalIface.h> + +class KURL; +class DCOPClient; +class KMailICalIface_stub; + +namespace Scalix { + +class ResourceScalixBase; + +/** + This class provides the kmail connectivity for IMAP resources. +*/ +class KMailConnection : public QObject, public DCOPObject { + Q_OBJECT + K_DCOP + + // These are the methods called by KMail when the resource changes +k_dcop: + bool fromKMailAddIncidence( const QString& type, const QString& resource, + Q_UINT32 sernum, int format, const QString& xml ); + void fromKMailDelIncidence( const QString& type, const QString& resource, + const QString& xml ); + void fromKMailRefresh( const QString& type, const QString& resource ); + void fromKMailAddSubresource( const QString& type, const QString& resource, const QString& label ); + void fromKMailDelSubresource( const QString& type, const QString& resource ); + void fromKMailAsyncLoadResult( const QMap<Q_UINT32, QString>& map, const QString& type, + const QString& folder ); + +public: + KMailConnection( ResourceScalixBase* resource, const QCString& objId ); + virtual ~KMailConnection(); + + /** + * Do the connection to KMail. + */ + bool connectToKMail(); + + // Call the DCOP methods + bool kmailSubresources( QValueList<KMailICalIface::SubResource>& lst, + const QString& contentsType ); + bool kmailIncidencesCount( int& count, + const QString& mimetype, + const QString& resource ); + bool kmailIncidences( QMap<Q_UINT32, QString>& lst, const QString& mimetype, + const QString& resource, + int startIndex, + int nbMessages ); + + bool kmailGetAttachment( KURL& url, const QString& resource, Q_UINT32 sernum, + const QString& filename ); + bool kmailDeleteIncidence( const QString& resource, Q_UINT32 sernum ); + bool kmailUpdate( const QString& resource, + Q_UINT32& sernum, + const QString& subject, + const QString& plainTextBody, + const QMap<QCString, QString>& customHeaders, + const QStringList& attachmentURLs, + const QStringList& attachmentMimetypes, + const QStringList& attachmentNames, + const QStringList& deletedAttachments ); + + bool kmailStorageFormat( KMailICalIface::StorageFormat& type, const QString& folder); + + bool kmailTriggerSync( const QString& contentsType ); + +private slots: + virtual void unregisteredFromDCOP( const QCString& ); + +private: + /** Connect a signal from KMail to a local slot. */ + bool connectKMailSignal( const QCString&, const QCString& ); + + ResourceScalixBase* mResource; + DCOPClient* mDCOPClient; + KMailICalIface_stub* mKMailIcalIfaceStub; +}; + +} + +#endif // KMAILCONNECTION_H diff --git a/kresources/scalix/shared/resourcescalixbase.cpp b/kresources/scalix/shared/resourcescalixbase.cpp new file mode 100644 index 000000000..e91e58787 --- /dev/null +++ b/kresources/scalix/shared/resourcescalixbase.cpp @@ -0,0 +1,179 @@ +/* + This file is part of the scalix resource - based on the kolab resource. + + Copyright (c) 2004 Bo Thorsen <[email protected]> + + 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 "resourcescalixbase.h" +#include "kmailconnection.h" + +#include <folderselectdialog.h> + +#include <klocale.h> +#include <kstandarddirs.h> +#include <kinputdialog.h> +#include <kurl.h> +#include <ktempfile.h> +#include <kmessagebox.h> +#include <qtextstream.h> +#include <kdebug.h> + +using namespace Scalix; + +static unsigned int uniquifier = 0; + +ResourceScalixBase::ResourceScalixBase( const QCString& objId ) + : mSilent( false ) +{ + KGlobal::locale()->insertCatalogue( "kres_scalix" ); + KGlobal::locale()->insertCatalogue( "libkcal" ); + QString uniqueObjId = QString( objId ) + QString::number( uniquifier++ ); + mConnection = new KMailConnection( this, uniqueObjId.utf8() ); +} + +ResourceScalixBase::~ResourceScalixBase() +{ + delete mConnection; +} + + +bool ResourceScalixBase::kmailSubresources( QValueList<KMailICalIface::SubResource>& lst, + const QString& contentsType ) const +{ + return mConnection->kmailSubresources( lst, contentsType ); +} + +bool ResourceScalixBase::kmailTriggerSync( const QString& contentsType ) const +{ + return mConnection->kmailTriggerSync( contentsType ); +} + + +bool ResourceScalixBase::kmailIncidencesCount( int &count, + const QString& mimetype, + const QString& resource ) const +{ + return mConnection->kmailIncidencesCount( count, mimetype, resource ); +} + +bool ResourceScalixBase::kmailIncidences( QMap<Q_UINT32, QString>& lst, + const QString& mimetype, + const QString& resource, + int startIndex, + int nbMessages ) const +{ + return mConnection->kmailIncidences( lst, mimetype, resource, startIndex, nbMessages ); +} + +bool ResourceScalixBase::kmailGetAttachment( KURL& url, const QString& resource, + Q_UINT32 sernum, + const QString& filename ) const +{ + return mConnection->kmailGetAttachment( url, resource, sernum, filename ); +} + +bool ResourceScalixBase::kmailDeleteIncidence( const QString& resource, + Q_UINT32 sernum ) +{ + return mSilent || mConnection->kmailDeleteIncidence( resource, sernum ); +} + +bool ResourceScalixBase::kmailUpdate( const QString& resource, + Q_UINT32& sernum, + const QString& xml, + const QString& mimetype, + const QString& subject, + const CustomHeaderMap& _customHeaders, + const QStringList& _attachmentURLs, + const QStringList& _attachmentMimetypes, + const QStringList& _attachmentNames, + const QStringList& deletedAttachments ) +{ + if ( mSilent ) + return true; + + QString subj = subject; + if ( subj.isEmpty() ) + subj = i18n("Internal kolab data: Do not delete this mail."); + + // ical style, simply put the data inline + return mConnection->kmailUpdate( resource, sernum, subj, xml, _customHeaders, + _attachmentURLs, _attachmentMimetypes, _attachmentNames, deletedAttachments ); +} + +QString ResourceScalixBase::configFile( const QString& type ) const +{ + return locateLocal( "config", + QString( "kresources/scalix/%1rc" ).arg( type ) ); +} + +bool ResourceScalixBase::connectToKMail() const +{ + return mConnection->connectToKMail(); +} + +QString ResourceScalixBase::findWritableResource( const ResourceMap& resources ) +{ + // I have to use the label (shown in the dialog) as key here. But given how the + // label is made up, it should be unique. If it's not, well the dialog would suck anyway... + QMap<QString, QString> possible; + QStringList labels; + ResourceMap::ConstIterator it; + for ( it = resources.begin(); it != resources.end(); ++it ) { + if ( it.data().writable() && it.data().active() ) { + // Writable and active possibility + possible[ it.data().label() ] = it.key(); + } + } + + if ( possible.isEmpty() ) { // None found!! + kdWarning(5650) << "No writable resource found!" << endl; + KMessageBox::error( 0, i18n( "No writable resource was found, saving will not be possible. Reconfigure KMail first." ) ); + return QString::null; + } + if ( possible.count() == 1 ) + // Just one found + return possible.begin().data(); // yes this is the subresource key, i.e. location + + // Several found, ask the user + QString chosenLabel = KPIM::FolderSelectDialog::getItem( i18n( "Select Resource Folder" ), + i18n( "You have more than one writable resource folder. " + "Please select the one you want to write to." ), + possible.keys() ); + if ( chosenLabel.isEmpty() ) // cancelled + return QString::null; + return possible[chosenLabel]; +} + +KMailICalIface::StorageFormat ResourceScalixBase::kmailStorageFormat( const QString &folder ) const +{ + KMailICalIface::StorageFormat format = (KMailICalIface::StorageFormat) 3; + mConnection->kmailStorageFormat( format, folder ); + return format; +} diff --git a/kresources/scalix/shared/resourcescalixbase.h b/kresources/scalix/shared/resourcescalixbase.h new file mode 100644 index 000000000..3c32c1dfd --- /dev/null +++ b/kresources/scalix/shared/resourcescalixbase.h @@ -0,0 +1,180 @@ +/* + This file is part of the scalix resource - based on the kolab resource. + + Copyright (c) 2004 Bo Thorsen <[email protected]> + + 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 RESOURCESCALIXBASE_H +#define RESOURCESCALIXBASE_H + +#include <qstring.h> +#include <qmap.h> +#include <qstringlist.h> + +#include "subresource.h" +#include <kmail/kmailicalIface.h> + +class QCString; +class KURL; + +namespace Scalix { + +class KMailConnection; + +/** + This class provides the kmail connectivity for IMAP resources. + + The main methods are: + + fromKMail...() : calls made _by_ KMail to add/delete data representation in the resource. + + kmail...() : calls _into_ KMail made by the resource. + + e.g. fromKMailAddIncidence() is called by KMail + when a new iCard is there after an IMAP sync. + + By calling fromKMailAddIncidence() KMail notifies + the resource about the new incidence, so in the + addressbook a new address will appear like magic. + + e.g. kmailAddIncidence() is called by the resource when + iCard must be stored by KMail because the user has added + an address in the addressbook. + + By calling kmailAddIncidence() the resource causes + KMail to store the new address in the (IMAP) folder. +*/ +class ResourceScalixBase { +public: + ResourceScalixBase( const QCString& objId ); + virtual ~ResourceScalixBase(); + + // These are the methods called by KMail when the resource changes + virtual bool fromKMailAddIncidence( const QString& type, + const QString& resource, + Q_UINT32 sernum, + int format, + const QString& data ) = 0; + virtual void fromKMailDelIncidence( const QString& type, + const QString& resource, + const QString& xml ) = 0; + virtual void fromKMailRefresh( const QString& type, + const QString& resource ) = 0; + virtual void fromKMailAddSubresource( const QString& type, + const QString& resource, + const QString& label, + bool writable ) = 0; + virtual void fromKMailDelSubresource( const QString& type, + const QString& resource ) = 0; + + virtual void fromKMailAsyncLoadResult( const QMap<Q_UINT32, QString>& map, + const QString& type, + const QString& folder ) = 0; +protected: + /// Do the connection to KMail. + bool connectToKMail() const; + + // These are the KMail dcop function connections. The docs here say + // "Get", which here means that the first argument is the return arg + + /// List all folders with a certain contentsType. Returns a QMap with + /// resourcename/writable pairs + bool kmailSubresources( QValueList<KMailICalIface::SubResource>& lst, + const QString& contentsType ) const; + + /// Get the number of messages in this folder. + /// Used to iterate over kmailIncidences by chunks + bool kmailIncidencesCount( int& count, const QString& mimetype, + const QString& resource ) const; + + /// Get the mimetype attachments from a chunk of messages from this folder. + /// Returns a QMap with serialNumber/attachment pairs. + bool kmailIncidences( QMap<Q_UINT32, QString>& lst, const QString& mimetype, + const QString& resource, + int startIndex, + int nbMessages ) const; + + bool kmailTriggerSync( const QString& contentType ) const; + +public: // for Contact + /// Get an attachment from a mail. Returns a URL to it. This can + /// be called by the resource after obtaining the incidence. + /// The resource must delete the temp file. + bool kmailGetAttachment( KURL& url, const QString& resource, + Q_UINT32 sernum, + const QString& filename ) const; + +protected: + /// Delete an incidence. + bool kmailDeleteIncidence( const QString& resource, Q_UINT32 sernum ); + + KMailICalIface::StorageFormat kmailStorageFormat( const QString& folder ) const; + + typedef QMap<QCString, QString> CustomHeaderMap; + + /// Update an incidence. The list of attachments are URLs. + /// The parameter sernum is updated with the right KMail serial number + bool kmailUpdate( const QString& resource, Q_UINT32& sernum, + const QString& xml, + const QString& mimetype, + const QString& subject, + const CustomHeaderMap& customHeaders = CustomHeaderMap(), + const QStringList& attachmentURLs = QStringList(), + const QStringList& attachmentMimetypes = QStringList(), + const QStringList& attachmentNames = QStringList(), + const QStringList& deletedAttachments = QStringList() ); + + /// Get the full path of the config file. + QString configFile( const QString& type ) const; + + /// If only one of these is writable, return that. Otherwise return null. + QString findWritableResource( const ResourceMap& resources ); + + bool mSilent; + + /** + * This is used to store a mapping from the XML UID to the KMail + * serial number of the mail it's stored in. That provides a quick way + * to access the storage in KMail. + */ + UidMap mUidMap; + + /// This is used to distinguish operations triggered by the user, + /// from operations triggered by KMail + QStringList mUidsPendingAdding; + QStringList mUidsPendingDeletion; + QStringList mUidsPendingUpdate; + +private: + mutable KMailConnection* mConnection; +}; + +} + +#endif // RESOURCEKOLABBASE_H diff --git a/kresources/scalix/shared/scalixbase.cpp b/kresources/scalix/shared/scalixbase.cpp new file mode 100644 index 000000000..ab38500e2 --- /dev/null +++ b/kresources/scalix/shared/scalixbase.cpp @@ -0,0 +1,446 @@ +/* + This file is part of the scalix resource - based on the kolab resource. + + Copyright (c) 2004 Bo Thorsen <[email protected]> + + 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 "scalixbase.h" + +#include <kabc/addressee.h> +#include <libkcal/journal.h> +#include <libkdepim/kpimprefs.h> +#include <kdebug.h> +#include <qfile.h> + +using namespace Scalix; + + +ScalixBase::ScalixBase( const QString& tz ) + : mCreationDate( QDateTime::currentDateTime() ), + mLastModified( QDateTime::currentDateTime() ), + mSensitivity( Public ), mTimeZoneId( tz ), + mHasPilotSyncId( false ), mHasPilotSyncStatus( false ) +{ +} + +ScalixBase::~ScalixBase() +{ +} + +void ScalixBase::setFields( const KCal::Incidence* incidence ) +{ + // So far unhandled KCal::IncidenceBase fields: + // mPilotID, mSyncStatus, mFloats + + setUid( incidence->uid() ); + setBody( incidence->description() ); + setCategories( incidence->categoriesStr() ); + setCreationDate( localToUTC( incidence->created() ) ); + setLastModified( localToUTC( incidence->lastModified() ) ); + setSensitivity( static_cast<Sensitivity>( incidence->secrecy() ) ); + // TODO: Attachments +} + +void ScalixBase::saveTo( KCal::Incidence* incidence ) const +{ + incidence->setUid( uid() ); + incidence->setDescription( body() ); + incidence->setCategories( categories() ); + incidence->setCreated( utcToLocal( creationDate() ) ); + incidence->setLastModified( utcToLocal( lastModified() ) ); + incidence->setSecrecy( sensitivity() ); + // TODO: Attachments +} + +void ScalixBase::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" ); + kdDebug(5006) << "Creation time string: " << creationString << endl; + QDateTime creationDate; + if ( creationString.isEmpty() ) { + creationDate = QDateTime::currentDateTime(); + kdDebug(5006) << "Creation date set to current time\n"; + } + else { + creationDate = stringToDateTime( creationString ); + kdDebug(5006) << "Creation date loaded\n"; + } + QDateTime modified = addressee->revision(); + if ( !modified.isValid() ) + modified = QDateTime::currentDateTime(); + setLastModified( modified ); + if ( modified < creationDate ) { + // It's not possible that the modification date is earlier than creation + creationDate = modified; + kdDebug(5006) << "Creation date set to modification date\n"; + } + setCreationDate( creationDate ); + const 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 ); + kdDebug(5006) << "Creation date modified. New one: " << newCreationDate << endl; + } + + switch( addressee->secrecy().type() ) { + case KABC::Secrecy::Private: + setSensitivity( Private ); + break; + case KABC::Secrecy::Confidential: + setSensitivity( Confidential ); + break; + default: + setSensitivity( Public ); + } + + // TODO: Attachments +} + +void ScalixBase::saveTo( KABC::Addressee* addressee ) const +{ + addressee->setUid( uid() ); + addressee->setNote( body() ); + addressee->setCategories( QStringList::split( ',', categories() ) ); + addressee->setRevision( lastModified() ); + addressee->insertCustom( "KOLAB", "CreationDate", + dateTimeToString( creationDate() ) ); + + switch( sensitivity() ) { + case Private: + addressee->setSecrecy( KABC::Secrecy( KABC::Secrecy::Private ) ); + break; + case Confidential: + addressee->setSecrecy( KABC::Secrecy( KABC::Secrecy::Confidential ) ); + break; + default: + addressee->setSecrecy( KABC::Secrecy( KABC::Secrecy::Public ) ); + break; + } + + // TODO: Attachments +} + +void ScalixBase::setUid( const QString& uid ) +{ + mUid = uid; +} + +QString ScalixBase::uid() const +{ + return mUid; +} + +void ScalixBase::setBody( const QString& body ) +{ + mBody = body; +} + +QString ScalixBase::body() const +{ + return mBody; +} + +void ScalixBase::setCategories( const QString& categories ) +{ + mCategories = categories; +} + +QString ScalixBase::categories() const +{ + return mCategories; +} + +void ScalixBase::setCreationDate( const QDateTime& date ) +{ + mCreationDate = date; +} + +QDateTime ScalixBase::creationDate() const +{ + return mCreationDate; +} + +void ScalixBase::setLastModified( const QDateTime& date ) +{ + mLastModified = date; +} + +QDateTime ScalixBase::lastModified() const +{ + return mLastModified; +} + +void ScalixBase::setSensitivity( Sensitivity sensitivity ) +{ + mSensitivity = sensitivity; +} + +ScalixBase::Sensitivity ScalixBase::sensitivity() const +{ + return mSensitivity; +} + +void ScalixBase::setPilotSyncId( unsigned long id ) +{ + mHasPilotSyncId = true; + mPilotSyncId = id; +} + +bool ScalixBase::hasPilotSyncId() const +{ + return mHasPilotSyncId; +} + +unsigned long ScalixBase::pilotSyncId() const +{ + return mPilotSyncId; +} + +void ScalixBase::setPilotSyncStatus( int status ) +{ + mHasPilotSyncStatus = true; + mPilotSyncStatus = status; +} + +bool ScalixBase::hasPilotSyncStatus() const +{ + return mHasPilotSyncStatus; +} + +int ScalixBase::pilotSyncStatus() const +{ + return mPilotSyncStatus; +} + +bool ScalixBase::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(); + 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 + kdDebug() << "Warning: Unhandled tag " << e.tagName() << endl; + } else + kdDebug() << "Node is not a comment or an element???" << endl; + } + + return true; +} + +void ScalixBase::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 ScalixBase::loadAttribute( QDomElement& element ) +{ + QString tagName = element.tagName(); + + if ( tagName == "uid" ) + setUid( element.text() ); + else if ( tagName == "body" ) + setBody( element.text() ); + else if ( tagName == "categories" ) + setCategories( element.text() ); + else if ( tagName == "creation-date" ) + setCreationDate( stringToDateTime( element.text() ) ); + else if ( tagName == "last-modification-date" ) + setLastModified( stringToDateTime( element.text() ) ); + else if ( tagName == "sensitivity" ) + setSensitivity( stringToSensitivity( element.text() ) ); + else if ( tagName == "product-id" ) + return true; // ignore this field + else if ( tagName == "pilot-sync-id" ) + setPilotSyncId( element.text().toULong() ); + else if ( tagName == "pilot-sync-status" ) + setPilotSyncStatus( element.text().toInt() ); + else + return false; + + // Handled here + return true; +} + +bool ScalixBase::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() ) ); + writeString( element, "last-modification-date", + dateTimeToString( lastModified() ) ); + 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 ScalixBase::load( const QString& xml ) +{ + QString errorMsg; + int errorLine, errorColumn; + QDomDocument document; + bool ok = document.setContent( xml, &errorMsg, &errorLine, &errorColumn ); + + if ( !ok ) { + qWarning( "Error loading document: %s, line %d, column %d", + errorMsg.latin1(), errorLine, errorColumn ); + return false; + } + + // XML file loaded into tree. Now parse it + return loadXML( document ); +} + +bool ScalixBase::load( QFile& xml ) +{ + QString errorMsg; + int errorLine, errorColumn; + QDomDocument document; + bool ok = document.setContent( &xml, &errorMsg, &errorLine, &errorColumn ); + + if ( !ok ) { + qWarning( "Error loading document: %s, line %d, column %d", + errorMsg.latin1(), errorLine, errorColumn ); + return false; + } + + // XML file loaded into tree. Now parse it + return loadXML( document ); +} + +QDomDocument ScalixBase::domTree() +{ + QDomDocument document; + + QString p = "version=\"1.0\" encoding=\"UTF-8\""; + document.appendChild(document.createProcessingInstruction( "xml", p ) ); + + return document; +} + + +QString ScalixBase::dateTimeToString( const QDateTime& time ) +{ + return time.toString( Qt::ISODate ) + 'Z'; +} + +QString ScalixBase::dateToString( const QDate& date ) +{ + return date.toString( Qt::ISODate ); +} + +QDateTime ScalixBase::stringToDateTime( const QString& _date ) +{ + QString date( _date ); + if ( date.endsWith( "Z" ) ) + date.truncate( date.length() - 1 ); + return QDateTime::fromString( date, Qt::ISODate ); +} + +QDate ScalixBase::stringToDate( const QString& date ) +{ + return QDate::fromString( date, Qt::ISODate ); +} + +QString ScalixBase::sensitivityToString( Sensitivity s ) +{ + switch( s ) { + case Private: return "private"; + case Confidential: return "confidential"; + case Public: return "public"; + } + + return "What what what???"; +} + +ScalixBase::Sensitivity ScalixBase::stringToSensitivity( const QString& s ) +{ + if ( s == "private" ) + return Private; + if ( s == "confidential" ) + return Confidential; + return Public; +} + +QString ScalixBase::colorToString( const QColor& color ) +{ + // Color is in the format "#RRGGBB" + return color.name(); +} + +QColor ScalixBase::stringToColor( const QString& s ) +{ + return QColor( s ); +} + +void ScalixBase::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 ); + } +} + +QDateTime ScalixBase::localToUTC( const QDateTime& time ) const +{ + return KPimPrefs::localTimeToUtc( time, mTimeZoneId ); +} + +QDateTime ScalixBase::utcToLocal( const QDateTime& time ) const +{ + return KPimPrefs::utcToLocalTime( time, mTimeZoneId ); +} diff --git a/kresources/scalix/shared/scalixbase.h b/kresources/scalix/shared/scalixbase.h new file mode 100644 index 000000000..efed7e27a --- /dev/null +++ b/kresources/scalix/shared/scalixbase.h @@ -0,0 +1,176 @@ +/* + This file is part of the scalix resource - based on the kolab resource. + + Copyright (c) 2004 Bo Thorsen <[email protected]> + + 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 SCALIXBASE_H +#define SCALIXBASE_H + +#include <qdom.h> +#include <qdatetime.h> +#include <qcolor.h> + +class QFile; + +namespace KCal { + class Incidence; +} + +namespace KABC { + class Addressee; +} + +namespace Scalix { + +class ScalixBase { +public: + struct Email { + public: + Email( const QString& name = QString::null, + const QString& email = QString::null ) + : displayName( name ), smtpAddress( email ) + { + } + + QString displayName; + QString smtpAddress; + }; + + enum Sensitivity { Public = 0, Private = 1, Confidential = 2 }; + + explicit ScalixBase( const QString& timezone = QString::null ); + virtual ~ScalixBase(); + + // 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 QDateTime& date ); + virtual QDateTime creationDate() const; + + virtual void setLastModified( const QDateTime& date ); + virtual QDateTime 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 QDateTime& time ); + static QString dateToString( const QDate& date ); + static QDateTime 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 ); + bool load( QFile& xml ); + + // 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 KCal::Incidence* ); + + /// Save all known fields into this ical incidence + void saveTo( KCal::Incidence* ) const; + + /// Read all known fields from this contact + void setFields( const KABC::Addressee* ); + + /// Save all known fields into this contact + void saveTo( KABC::Addressee* ) const; + + // This just makes the initial dom tree with version and doctype + static 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& ); + + QDateTime localToUTC( const QDateTime& time ) const; + QDateTime utcToLocal( const QDateTime& time ) const; + + QString mUid; + QString mBody; + QString mCategories; + QDateTime mCreationDate; + QDateTime mLastModified; + Sensitivity mSensitivity; + QString mTimeZoneId; + + // KPilot synchronization stuff + bool mHasPilotSyncId, mHasPilotSyncStatus; + unsigned long mPilotSyncId; + int mPilotSyncStatus; +}; + +} + +#endif // SCALIXBASE_H diff --git a/kresources/scalix/shared/subresource.cpp b/kresources/scalix/shared/subresource.cpp new file mode 100644 index 000000000..6653e0f06 --- /dev/null +++ b/kresources/scalix/shared/subresource.cpp @@ -0,0 +1,116 @@ +/* + This file is part of the scalix resource - based on the kolab resource. + + Copyright (c) 2004 Klar�lvdalens Datakonsult AB + + 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 "subresource.h" + +using namespace Scalix; + +SubResource::SubResource( bool active, bool writable, const QString& label, + int completionWeight ) + : mActive( active ), mWritable( writable ), mLabel( label ), + mCompletionWeight( completionWeight ) +{ +} + +SubResource::~SubResource() +{ +} + +void SubResource::setActive( bool active ) +{ + mActive = active; +} + +bool SubResource::active() const +{ + return mActive; +} + +void SubResource::setWritable( bool writable ) +{ + mWritable = writable; +} + +bool SubResource::writable() const +{ + return mWritable; +} + +void SubResource::setLabel( const QString& label ) +{ + mLabel = label; +} + +QString SubResource::label() const +{ + return mLabel; +} + +void SubResource::setCompletionWeight( int completionWeight ) +{ + mCompletionWeight = completionWeight; +} + +int SubResource::completionWeight() const +{ + return mCompletionWeight; +} + +StorageReference::StorageReference( const QString& resource, Q_UINT32 sernum ) + : mResource( resource ), mSerialNumber( sernum ) +{ +} + +StorageReference::~StorageReference() +{ +} + +void StorageReference::setResource( const QString& resource ) +{ + mResource = resource; +} + +QString StorageReference::resource() const +{ + return mResource; +} + +void StorageReference::setSerialNumber( Q_UINT32 serialNumber ) +{ + mSerialNumber = serialNumber; +} + +Q_UINT32 StorageReference::serialNumber() const +{ + return mSerialNumber; +} diff --git a/kresources/scalix/shared/subresource.h b/kresources/scalix/shared/subresource.h new file mode 100644 index 000000000..3cfc4429e --- /dev/null +++ b/kresources/scalix/shared/subresource.h @@ -0,0 +1,110 @@ +/* + This file is part of the scalix resource - based on the kolab resource. + + Copyright (c) 2004 Klar�lvdalens Datakonsult AB + + 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 SUBRESOURCE_H +#define SUBRESOURCE_H + +#include <qstring.h> +#include <qmap.h> + + +namespace Scalix { + +/** + * This class is used to store in a map from resource id to this, providing + * a lookup of the subresource settings. + */ +class SubResource { +public: + // This is just for QMap + SubResource() {} + + SubResource( bool active, bool writable, const QString& label, + int completionWeight = 100 ); + virtual ~SubResource(); + + virtual void setActive( bool active ); + virtual bool active() const; + + virtual void setWritable( bool writable ); + virtual bool writable() const; + + virtual void setLabel( const QString& label ); + virtual QString label() const; + + virtual void setCompletionWeight( int completionWeight ); + virtual int completionWeight() const; + +private: + bool mActive; // Controlled by the applications + bool mWritable; // Set if the KMail folder is writable + QString mLabel; // The GUI name of this resource + + // This is just for the abc plugin. But as long as only this is here, + // it's just as cheap to have it in here as making a d-pointer that + // subclasses could add to. If more are added, then we should refactor + // to a d-pointer instead. + int mCompletionWeight; +}; + +typedef QMap<QString, SubResource> ResourceMap; + +/** + * This class is used to store a mapping from the XML UID to the KMail + * serial number of the mail it's stored in and the resource. That provides + * a quick way to access the storage in KMail. + */ +class StorageReference { +public: + // Just for QMap + StorageReference() {} + + StorageReference( const QString& resource, Q_UINT32 sernum ); + virtual ~StorageReference(); + + virtual void setResource( const QString& resource ); + virtual QString resource() const; + + virtual void setSerialNumber( Q_UINT32 serialNumber ); + virtual Q_UINT32 serialNumber() const; + +private: + QString mResource; + Q_UINT32 mSerialNumber; +}; + +typedef QMap<QString, StorageReference> UidMap; + +} + +#endif // SUBRESOURCE_H diff --git a/kresources/scalix/uninstall.desktop b/kresources/scalix/uninstall.desktop new file mode 100644 index 000000000..e1e3e1732 --- /dev/null +++ b/kresources/scalix/uninstall.desktop @@ -0,0 +1,2 @@ +[Desktop Entry] +Hidden=true |