From cc29364f06178f8f6b457384f2ec37a042bd9d43 Mon Sep 17 00:00:00 2001 From: tpearson Date: Wed, 1 Sep 2010 00:37:02 +0000 Subject: * Massive set of changes to bring in all fixes and enhancements from the Enterprise PIM branch * Ensured that the Trinity changes were applied on top of those enhancements, and any redundancy removed * Added journal read support to the CalDAV resource * Fixed CalDAV resource to use events URL for tasks and journals when separate URL checkbox unchecked git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdepim@1170461 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- kresources/Makefile.am | 2 +- kresources/birthdays/kabc.desktop | 1 - kresources/birthdays/resourcekabc.cpp | 60 ++- kresources/birthdays/resourcekabc.h | 10 +- kresources/blogging/blogging.desktop | 1 - kresources/blogging/kcal_resourceblogging.cpp | 6 +- kresources/caldav/config.cpp | 38 +- kresources/caldav/config.h | 3 + kresources/caldav/job.cpp | 31 ++ kresources/caldav/job.h | 64 +++ kresources/caldav/preferences.cpp | 29 +- kresources/caldav/preferences.h | 5 + kresources/caldav/prefsskel.kcfg | 10 + kresources/caldav/reader.cpp | 39 ++ kresources/caldav/reader.h | 10 + kresources/caldav/resource.cpp | 142 ++++++- kresources/caldav/resource.h | 23 +- kresources/caldav/writer.cpp | 37 ++ kresources/caldav/writer.h | 46 +++ kresources/egroupware/kabc_resourcexmlrpc.cpp | 5 +- kresources/egroupware/kabc_xmlrpc.desktop | 1 - kresources/egroupware/kcal_resourcexmlrpc.cpp | 5 +- kresources/egroupware/kcal_xmlrpc.desktop | 1 - kresources/egroupware/knotes_resourcexmlrpc.cpp | 5 +- kresources/egroupware/knotes_xmlrpc.desktop | 1 - kresources/exchange/exchange.desktop | 1 - kresources/exchange/exchange_deprecated.desktop | 1 - kresources/exchange/resourceexchange.cpp | 36 +- kresources/exchange/resourceexchange.h | 10 +- kresources/groupware/kabc_groupware.desktop | 1 - kresources/groupware/kabc_resourcegroupware.cpp | 2 + kresources/groupware/kcal_groupware.desktop | 1 - kresources/groupware/kcal_resourcegroupware.cpp | 6 +- kresources/kolab/kabc/contact.cpp | 72 ++-- kresources/kolab/kabc/contact.h | 7 +- kresources/kolab/kabc/kolab.desktop | 1 - kresources/kolab/kabc/resourcekolab.cpp | 64 ++- kresources/kolab/kabc/resourcekolab.h | 3 + kresources/kolab/kcal/event.cpp | 7 +- kresources/kolab/kcal/incidence.cpp | 248 ++++++++++-- kresources/kolab/kcal/incidence.h | 9 +- kresources/kolab/kcal/kolab.desktop | 1 - kresources/kolab/kcal/resourcekolab.cpp | 437 +++++++++++++++------ kresources/kolab/kcal/resourcekolab.h | 64 ++- kresources/kolab/kcal/task.cpp | 171 ++++++-- kresources/kolab/kcal/task.h | 16 +- kresources/kolab/knotes/kolabresource.desktop | 1 - kresources/kolab/knotes/note.cpp | 41 +- kresources/kolab/knotes/resourcekolab.cpp | 92 +++-- kresources/kolab/knotes/resourcekolab.h | 3 + kresources/kolab/shared/kmailconnection.cpp | 40 +- kresources/kolab/shared/kolabbase.cpp | 19 +- kresources/kolab/shared/resourcekolabbase.cpp | 38 +- kresources/kolab/shared/resourcekolabbase.h | 12 +- kresources/lib/addressbookadaptor.cpp | 16 +- kresources/lib/folderselectdialog.cpp | 7 +- kresources/lib/folderselectdialog.h | 1 + kresources/lib/kcal_resourcegroupwarebase.cpp | 40 +- .../newexchange/exchangeconvertercontact.cpp | 122 +++--- kresources/newexchange/kabc_newexchange.desktop | 1 - .../newexchange/kabc_newexchange_final.desktop | 1 - kresources/newexchange/kabc_resourceexchange.cpp | 8 +- kresources/newexchange/kcal_newexchange.desktop | 1 - .../newexchange/kcal_newexchange_final.desktop | 1 - kresources/newexchange/kcal_resourceexchange.cpp | 7 +- kresources/remote/remote.desktop | 1 - kresources/remote/resourceremote.cpp | 2 + kresources/scalix/kcal/resourcescalix.cpp | 18 + kresources/scalix/kcal/resourcescalix.h | 3 + kresources/slox/kabc_ox.desktop | 1 - kresources/slox/kabc_slox.desktop | 1 - kresources/slox/kabcresourceslox.cpp | 11 + kresources/slox/kcal_ox.desktop | 1 - kresources/slox/kcal_slox.desktop | 1 - kresources/slox/kcalresourceslox.cpp | 2 + 75 files changed, 1760 insertions(+), 465 deletions(-) (limited to 'kresources') diff --git a/kresources/Makefile.am b/kresources/Makefile.am index eb2178697..1ae15a7d8 100644 --- a/kresources/Makefile.am +++ b/kresources/Makefile.am @@ -1,5 +1,5 @@ if include_exchange_SUBDIR -EXCHANGE_SUBDIR=exchange +EXCHANGE_SUBDIR=exchange endif SUBDIRS = lib remote egroupware $(EXCHANGE_SUBDIR) kolab slox groupwise featureplan groupdav birthdays newexchange scalix caldav carddav diff --git a/kresources/birthdays/kabc.desktop b/kresources/birthdays/kabc.desktop index aec8d565c..cea676fa6 100644 --- a/kresources/birthdays/kabc.desktop +++ b/kresources/birthdays/kabc.desktop @@ -28,7 +28,6 @@ Name[hu]=Születésnapok a KAddressBookból Name[is]=Afmælisdagar úr KAddressBook Name[it]=Compleanni da KAddessBook Name[ja]=アドレス帳の誕生日 -Name[ka]=დაბადების დღეები KDE წიგნაკიდან Name[kk]=KAddressBook-тағы туған күндер Name[km]=ថ្ងៃ​ខួប​កំណើត​ពី KAddressBook Name[lt]=Gimtadieniai iš KAddressBook diff --git a/kresources/birthdays/resourcekabc.cpp b/kresources/birthdays/resourcekabc.cpp index dc902c5bf..65830782e 100644 --- a/kresources/birthdays/resourcekabc.cpp +++ b/kresources/birthdays/resourcekabc.cpp @@ -46,6 +46,8 @@ #include "libkcal/filestorage.h" #include "libkcal/alarm.h" +#include + #include #include "resourcekabcconfig.h" @@ -70,6 +72,8 @@ ResourceKABC::ResourceKABC( const KConfig* config ) { if ( config ) { readConfig( config ); + } else { + setResourceName( i18n( "Birthdays" ) ); } init(); @@ -227,7 +231,8 @@ bool ResourceKABC::doLoad() bool found = false; for ( addrIt = anniversaries.begin(); addrIt != anniversaries.end(); ++addrIt ) { if ( name == (*addrIt).realName() ) { - TQDateTime spouseAnniversary = TQDate::fromString( (*addrIt).custom( "KADDRESSBOOK", "X-Anniversary" ), Qt::ISODate ); + TQDate spouseAnniversary = + TQDate::fromString( (*addrIt).custom( "KADDRESSBOOK", "X-Anniversary" ), Qt::ISODate ); if ( anniversary == spouseAnniversary ) { found = true; break; @@ -255,22 +260,30 @@ bool ResourceKABC::doLoad() TQString spouseName = (*addrIt).custom( "KADDRESSBOOK", "X-SpousesName" ); TQString name_2,email_2,uid_2; if ( !spouseName.isEmpty() ) { - //TODO: find a KABC:Addressee of the spouse - // Probably easiest would be to use a TQMap (as the spouse's entry was already searched above! + TQString tname, temail; + KPIM::getNameAndMail( spouseName, tname, temail ); + tname = KPIM::quoteNameIfNecessary( tname ); + if ( ( tname[0] == '"' ) && ( tname[tname.length() - 1] == '"' ) ) { + tname.remove( 0, 1 ); + tname.truncate( tname.length() - 1 ); + } KABC::Addressee spouse; - spouse.setNameFromString( spouseName ); + spouse.setNameFromString( tname ); + name_2 = spouse.nickName(); uid_2 = spouse.uid(); email_2 = spouse.fullEmail(); - name_2 = spouse.nickName(); - if ( name_2.isEmpty() ) - name_2 = spouse.givenName(); - summary = i18n("insert names of both spouses", "%1's & %2's anniversary").arg( name_1 ).arg( name_2 ); + if ( name_2.isEmpty() ) { + name_2 = spouse.realName(); + } + summary = i18n("insert names of both spouses", + "%1's & %2's anniversary").arg( name_1 ).arg( name_2 ); } else { - summary = i18n("only one spouse in addressbook, insert the name", "%1's anniversary").arg( name_1 ); + summary = i18n("only one spouse in addressbook, insert the name", + "%1's anniversary").arg( name_1 ); } Event *ev = new Event(); - ev->setUid( uid_1+"_KABC_Anniversary" ); + ev->setUid( uid_1+"_KABC_Anniversary" ); ev->setDtStart(anniversary); ev->setDtEnd(anniversary); @@ -378,12 +391,17 @@ KABC::Lock *ResourceKABC::lock() } -bool ResourceKABC::addEvent(Event*) +bool ResourceKABC::addEvent( Event * ) +{ + return false; +} + +bool ResourceKABC::addEvent( Event *, const TQString & ) { return false; } -bool ResourceKABC::deleteEvent(Event*) +bool ResourceKABC::deleteEvent( Event * ) { return false; } @@ -417,12 +435,17 @@ Event::List ResourceKABC::rawEvents( EventSortField sortField, SortDirection sor return mCalendar.rawEvents( sortField, sortDirection ); } -bool ResourceKABC::addTodo(Todo*) +bool ResourceKABC::addTodo( Todo * ) { return false; } -bool ResourceKABC::deleteTodo(Todo*) +bool ResourceKABC::addTodo( Todo *, const TQString & ) +{ + return false; +} + +bool ResourceKABC::deleteTodo( Todo * ) { return false; } @@ -444,12 +467,17 @@ Todo::List ResourceKABC::rawTodosForDate( const TQDate &date ) } -bool ResourceKABC::addJournal(Journal*) +bool ResourceKABC::addJournal( Journal * ) +{ + return false; +} + +bool ResourceKABC::addJournal( Journal *, const TQString & ) { return false; } -bool ResourceKABC::deleteJournal(Journal*) +bool ResourceKABC::deleteJournal( Journal * ) { return false; } diff --git a/kresources/birthdays/resourcekabc.h b/kresources/birthdays/resourcekabc.h index eebe087e9..9dedd0ab6 100644 --- a/kresources/birthdays/resourcekabc.h +++ b/kresources/birthdays/resourcekabc.h @@ -76,7 +76,8 @@ class KDE_EXPORT ResourceKABC : public ResourceCalendar KABC::Lock *lock(); /** Add Event to calendar. */ - bool addEvent(Event *anEvent); + KDE_DEPRECATED bool addEvent(Event *event); + bool addEvent( Event *event, const TQString &subresource ); /** deletes an event from this calendar. */ bool deleteEvent(Event *); @@ -107,7 +108,8 @@ class KDE_EXPORT ResourceKABC : public ResourceCalendar /** Add a todo to the todolist. */ - bool addTodo( Todo *todo ); + KDE_DEPRECATED bool addTodo( Todo *todo ); + bool addTodo( Todo *todo, const TQString &subresource ); /** Remove a todo from the todolist. */ @@ -126,7 +128,9 @@ class KDE_EXPORT ResourceKABC : public ResourceCalendar */ Todo::List rawTodosForDate( const TQDate &date ); /** Add a Journal entry to calendar */ - virtual bool addJournal(Journal *); + KDE_DEPRECATED bool addJournal( Journal *journal ); + bool addJournal( Journal *journal, const TQString &subresource ); + /** Remove journal from the calendar. */ bool deleteJournal( Journal * ); /** Return Journal with given UID */ diff --git a/kresources/blogging/blogging.desktop b/kresources/blogging/blogging.desktop index 061b06341..23b367a93 100644 --- a/kresources/blogging/blogging.desktop +++ b/kresources/blogging/blogging.desktop @@ -19,7 +19,6 @@ Name[hu]=Naplók blogként tárolása a kiszolgálón Name[is]=Dagbækur sem blogg á þjóni Name[it]=Diari come blog su un server Name[ja]=サーバ上のブログとしてのジャーナル -Name[ka]=ბლოგისმაგვარი ჟურნალები სერვერზე Name[kk]=Сервердегі күнделік блог ретінде Name[km]=ទិនានុប្បវត្តិ​ជា​កំណត់ហេតុ​បណ្ដាញ​នៅ​លើ​ម៉ាស៊ីន​បម្រើ Name[lt]=Dienynai kaip Blog'ai serveryje diff --git a/kresources/blogging/kcal_resourceblogging.cpp b/kresources/blogging/kcal_resourceblogging.cpp index 6f7ed46ec..07d097db9 100644 --- a/kresources/blogging/kcal_resourceblogging.cpp +++ b/kresources/blogging/kcal_resourceblogging.cpp @@ -38,7 +38,11 @@ ResourceBlogging::ResourceBlogging( const KConfig *config ) : ResourceGroupwareBase( config ) { init(); - if ( config ) readConfig( config ); + if ( config ) { + readConfig( config ); + } else { + setResourceName( i18n( "Blogs" ) ); + } } void ResourceBlogging::init() diff --git a/kresources/caldav/config.cpp b/kresources/caldav/config.cpp index 550e00c97..84a4798c6 100644 --- a/kresources/caldav/config.cpp +++ b/kresources/caldav/config.cpp @@ -89,7 +89,9 @@ void ResourceCalDavConfig::loadSettings( KRES::Resource *resource ) { mRememberPassword->setChecked(p->rememberPassword()); mPassword->setText(p->password()); mTasksUrl->setText(p->tasksUrl()); + mJournalsUrl->setText(p->journalsUrl()); mUseSTasks->setChecked(p->useSTasks()); + mUseSJournals->setChecked(p->useSJournals()); mReloadConfig->loadSettings(res); mSaveConfig->loadSettings(res); @@ -110,6 +112,8 @@ void ResourceCalDavConfig::saveSettings( KRES::Resource *resource ) { p->setPassword(mPassword->text()); p->setTasksUrl(mTasksUrl->text()); p->setUseSTasks(mUseSTasks->isChecked()); + p->setJournalsUrl(mJournalsUrl->text()); + p->setUseSJournals(mUseSJournals->isChecked()); } } } @@ -128,34 +132,48 @@ void ResourceCalDavConfig::setupUI() { // Tasks URL TQLabel *tlabel = new TQLabel( i18n( "Tasks URL:" ), this ); mTasksUrl = new TQLineEdit( this ); - mainLayout->addWidget( tlabel, 2, 0 ); - mainLayout->addWidget( mTasksUrl, 2, 1 ); + mainLayout->addWidget( tlabel, 3, 0 ); + mainLayout->addWidget( mTasksUrl, 3, 1 ); // Use Task URL checkbox mUseSTasks = new TQCheckBox( i18n("Use separate Tasks URL"), this ); - mainLayout->addWidget(mUseSTasks, 3, 0 ); + mainLayout->addWidget(mUseSTasks, 2, 0 ); + + // Journals URL + TQLabel *jlabel = new TQLabel( i18n( "Journals URL:" ), this ); + mJournalsUrl = new TQLineEdit( this ); + mainLayout->addWidget( jlabel, 5, 0 ); + mainLayout->addWidget( mJournalsUrl, 5, 1 ); + + // Use Journal URL checkbox + mUseSJournals = new TQCheckBox( i18n("Use separate Journals URL"), this ); + mainLayout->addWidget(mUseSJournals, 4, 0 ); // Username label = new TQLabel( i18n( "Username:" ), this ); mUsername = new TQLineEdit( this ); - mainLayout->addWidget( label, 4, 0 ); - mainLayout->addWidget( mUsername, 4, 1 ); + mainLayout->addWidget( label, 6, 0 ); + mainLayout->addWidget( mUsername, 6, 1 ); // Password label = new TQLabel( i18n( "Password:" ), this ); mPassword = new TQLineEdit( this ); mPassword->setEchoMode( TQLineEdit::Password ); - mainLayout->addWidget( label, 5, 0 ); - mainLayout->addWidget( mPassword, 5, 1 ); + mainLayout->addWidget( label, 7, 0 ); + mainLayout->addWidget( mPassword, 7, 1 ); // Remember password checkbox mRememberPassword = new TQCheckBox( i18n("Remember password"), this ); - mainLayout->addWidget(mRememberPassword, 6, 1); + mainLayout->addWidget(mRememberPassword, 8, 1); mTasksUrl->setEnabled(mUseSTasks->isChecked()); connect( mUseSTasks, TQT_SIGNAL( toggled( bool ) ), TQT_SLOT( slotSTasksToggled( bool ) ) ); + mJournalsUrl->setEnabled(mUseSJournals->isChecked()); + connect( mUseSJournals, TQT_SIGNAL( toggled( bool ) ), + TQT_SLOT( slotSJournalsToggled( bool ) ) ); + // configs TQHBoxLayout* horizontal = new TQHBoxLayout(this); @@ -181,4 +199,8 @@ void ResourceCalDavConfig::slotSTasksToggled( bool enabled ) { mTasksUrl->setEnabled(enabled); } +void ResourceCalDavConfig::slotSJournalsToggled( bool enabled ) { + mJournalsUrl->setEnabled(enabled); +} + // EOF ======================================================================== diff --git a/kresources/caldav/config.h b/kresources/caldav/config.h index 746c87aca..780674281 100644 --- a/kresources/caldav/config.h +++ b/kresources/caldav/config.h @@ -51,6 +51,7 @@ public slots: virtual void saveSettings(KRES::Resource *resource); void slotSTasksToggled( bool ); + void slotSJournalsToggled( bool ); protected: @@ -60,9 +61,11 @@ private: TQLineEdit *mUrl; TQLineEdit *mTasksUrl; + TQLineEdit *mJournalsUrl; TQLineEdit *mUsername; TQLineEdit *mPassword; TQCheckBox *mUseSTasks; + TQCheckBox *mUseSJournals; TQCheckBox *mRememberPassword; CalDavReloadConfig* mReloadConfig; CalDavSaveConfig* mSaveConfig; diff --git a/kresources/caldav/job.cpp b/kresources/caldav/job.cpp index 6edfbbfe8..8e49041f6 100644 --- a/kresources/caldav/job.cpp +++ b/kresources/caldav/job.cpp @@ -68,6 +68,12 @@ void CalDavJob::setTasksErrorString(const TQString& err, const long number) { mTasksErrorNumber = number; } +void CalDavJob::setJournalsErrorString(const TQString& err, const long number) { + mJournalsError = true; + mJournalsErrorString = err; + mJournalsErrorNumber = number; +} + void CalDavJob::processError(const caldav_error* err) { TQString error_string; @@ -100,6 +106,22 @@ void CalDavJob::processTasksError(const caldav_error* err) { setTasksErrorString(error_string, code); } +void CalDavJob::processJournalsError(const caldav_error* err) { + TQString error_string; + + long code = err->code; + + if (-401 == code) { // unauthorized + error_string = i18n("Unauthorized. Username or password incorrect."); + } else if (-599 <= code && code <= -300) { + error_string = i18n("HTTP error %1. Please ensure that the URL is a valid CalDAV resource.").arg(-code); + } else { + error_string = err->str; + } + + setJournalsErrorString(error_string, code); +} + void CalDavJob::run() { log("cleaning job"); @@ -107,6 +129,7 @@ void CalDavJob::run() { int res = OK; int tasksres = OK; + int journalsres = OK; runtime_info* caldav_runtime = caldav_get_runtime_info(); @@ -131,6 +154,14 @@ void CalDavJob::run() { processTasksError(caldav_runtime->error); } + log("running journals job"); + journalsres = runJournalsJob(caldav_runtime); + + if (OK != journalsres) { + log("journals job failed"); + processJournalsError(caldav_runtime->error); + } + caldav_free_runtime_info(&caldav_runtime); // Signal done diff --git a/kresources/caldav/job.h b/kresources/caldav/job.h index bad00c98d..928e38143 100644 --- a/kresources/caldav/job.h +++ b/kresources/caldav/job.h @@ -60,6 +60,13 @@ public: mTasksUrl = s; } + /** + * Sets a new Journals URL to load. + */ + virtual void setJournalsUrl(const TQString& s) { + mJournalsUrl = s; + } + /** * Sets the parent qobject. */ @@ -88,6 +95,13 @@ public: return mTasksUrl; } + /** + * @return Journals URL to load. + */ + virtual TQString journalsUrl() const { + return mJournalsUrl; + } + /** * @return parent object */ @@ -116,6 +130,13 @@ public: return mTasksError; } + /** + * @return true if journals downloading process failed. + */ + virtual bool journalsError() const { + return mJournalsError; + } + /** * @return an event error string. */ @@ -130,6 +151,13 @@ public: return mTasksErrorString; } + /** + * @return a journal error string. + */ + virtual TQString journalsErrorString() const { + return mJournalsErrorString; + } + /** * @return an event error number. */ @@ -144,6 +172,13 @@ public: return mTasksErrorNumber; } + /** + * @return a journal error number. + */ + virtual long journalsErrorNumber() const { + return mJournalsErrorNumber; + } + protected: virtual void run(); @@ -166,6 +201,15 @@ protected: */ virtual int runTasksJob(runtime_info* caldavRuntime) = 0; + /** + * Main run method for journal jobs. Jobs should not override run() method. + * Instead of this they should override this one. + * @param caldavRuntime specific libcaldav runtime information. This pointer should not be saved for the usage + * outside of runJob. + * @return libcaldav response code (see CALDAV_RESPONSE) + */ + virtual int runJournalsJob(runtime_info* caldavRuntime) = 0; + /** * Some cleaning. Jobs may (and usually should) override this method. */ @@ -176,6 +220,9 @@ protected: mTasksError = false; mTasksErrorString = ""; mTasksErrorNumber = 0; + mJournalsError = false; + mJournalsErrorString = ""; + mJournalsErrorNumber = 0; } /** @@ -188,6 +235,11 @@ protected: */ void setTasksErrorString(const TQString& str, const long number); + /** + * Sets a journal error string to @p err. Also sets an error flag. + */ + void setJournalsErrorString(const TQString& str, const long number); + /** * Process an event error. * Subclasses can overwrite this method, if some special error message handling @@ -204,16 +256,28 @@ protected: */ virtual void processTasksError(const caldav_error* err); + /** + * Process a journal error. + * Subclasses can overwrite this method, if some special error message handling + * should be done. Call setErrorString() to set the error after processing is done. + * @param err error structure. + */ + virtual void processJournalsError(const caldav_error* err); + private: TQString mUrl; TQString mTasksUrl; + TQString mJournalsUrl; bool mError; bool mTasksError; + bool mJournalsError; TQString mErrorString; TQString mTasksErrorString; + TQString mJournalsErrorString; long mErrorNumber; long mTasksErrorNumber; + long mJournalsErrorNumber; TQObject *mParent; int mType; diff --git a/kresources/caldav/preferences.cpp b/kresources/caldav/preferences.cpp index d70a35193..6eb87e450 100644 --- a/kresources/caldav/preferences.cpp +++ b/kresources/caldav/preferences.cpp @@ -234,7 +234,7 @@ TQString CalDavPrefs::getFullUrl() { TQString CalDavPrefs::getFullTasksUrl() { if (useSTasks() == 0) - return TQString(); + return getFullUrl(); TQUrl t(tasksUrl()); TQString safeURL; @@ -259,5 +259,32 @@ TQString CalDavPrefs::getFullTasksUrl() { return safeURL; } +TQString CalDavPrefs::getFullJournalsUrl() { + if (useSJournals() == 0) + return getFullUrl(); + + TQUrl t(journalsUrl()); + TQString safeURL; + int firstAt; + + t.setUser(username()); + t.setPassword(password()); + + safeURL = t.toString(); + + firstAt = safeURL.find("@") + 1; + while (safeURL.find("@", firstAt) != -1) { + safeURL.replace(safeURL.find("@", firstAt), 1, "%40"); + } + + // Unencode the username, as Zimbra stupidly rejects the %40 + safeURL.replace("%40", "@"); + + // Encode any spaces, as libcaldav stupidly fails otherwise + safeURL.replace(" ", "%20"); + + return safeURL; +} + // EOF ======================================================================== diff --git a/kresources/caldav/preferences.h b/kresources/caldav/preferences.h index 666b8ccf1..98245e6bb 100644 --- a/kresources/caldav/preferences.h +++ b/kresources/caldav/preferences.h @@ -92,6 +92,11 @@ public: */ TQString getFullTasksUrl(); + /** + * @return A full URL to connect to CalDAV Journals server (including username and password). + */ + TQString getFullJournalsUrl(); + protected: /** diff --git a/kresources/caldav/prefsskel.kcfg b/kresources/caldav/prefsskel.kcfg index bb05a75f6..7a72dd6b5 100644 --- a/kresources/caldav/prefsskel.kcfg +++ b/kresources/caldav/prefsskel.kcfg @@ -14,8 +14,18 @@ + + + + + false + + + + + false diff --git a/kresources/caldav/reader.cpp b/kresources/caldav/reader.cpp index a7956fe62..892b490c6 100644 --- a/kresources/caldav/reader.cpp +++ b/kresources/caldav/reader.cpp @@ -38,6 +38,11 @@ void CalDavReader::cleanTasksJob() { mTasksData = ""; } +void CalDavReader::cleanJournalsJob() { + CalDavJob::cleanJob(); + mJournalsData = ""; +} + int CalDavReader::runJob(runtime_info* RT) { kdDebug() << "reader::run, url: " << url(); @@ -104,4 +109,38 @@ int CalDavReader::runTasksJob(runtime_info* RT) { return tasksres; } +int CalDavReader::runJournalsJob(runtime_info* RT) { + kdDebug() << "reader::run, journalsUrl: " << journalsUrl(); + + response* result = caldav_get_response(); + CALDAV_RESPONSE journalsres = OK; + + if ((OK == journalsres) && (journalsUrl() != "")) { + kdDebug() << "reader::run, url: " << journalsUrl(); + + if (mGetAll) { + kdDebug() << "getting all objects"; + journalsres = caldav_tasks_getall_object(result, std::string(journalsUrl().ascii()).c_str(), RT); + } else { + kdDebug() << "getting object from the specified time range"; + journalsres = caldav_tasks_get_object(result, mTimeStart.toTime_t(), mTimeEnd.toTime_t(), std::string(journalsUrl().ascii()).c_str(), RT); + } + + if (OK == journalsres) { + kdDebug() << "success"; + if (result->msg) { + mJournalsData = result->msg; + } else { + kdDebug() << "empty collection"; + // empty collection + mJournalsData = ""; + } + } + + caldav_free_response(&result); + } + + return journalsres; +} + // EOF ======================================================================== diff --git a/kresources/caldav/reader.h b/kresources/caldav/reader.h index b62a5931b..9bcc8c87a 100644 --- a/kresources/caldav/reader.h +++ b/kresources/caldav/reader.h @@ -78,18 +78,28 @@ public: return mTasksData; } + /** + * @return downloaded journal data in iCal format. + */ + TQString journalsData() const { + return mJournalsData; + } + protected: virtual int runJob(runtime_info* caldavRuntime); virtual int runTasksJob(runtime_info* caldavRuntime); + virtual int runJournalsJob(runtime_info* caldavRuntime); virtual void cleanJob(); virtual void cleanTasksJob(); + virtual void cleanJournalsJob(); private: TQString mData; TQString mTasksData; + TQString mJournalsData; bool mGetAll; TQDateTime mTimeStart; TQDateTime mTimeEnd; diff --git a/kresources/caldav/resource.cpp b/kresources/caldav/resource.cpp index c0bbf1159..003633a40 100644 --- a/kresources/caldav/resource.cpp +++ b/kresources/caldav/resource.cpp @@ -160,7 +160,7 @@ bool ResourceCalDav::doLoad() { emit resourceLoaded(this); log("starting download job"); - startLoading(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl()); + startLoading(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl(), mPrefs->getFullJournalsUrl()); return true; } @@ -189,7 +189,7 @@ bool ResourceCalDav::doSave() { } log("start writing job"); - if (startWriting(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl()) == true) { + if (startWriting(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl(), mPrefs->getFullJournalsUrl()) == true) { log("clearing changes"); // FIXME: Calling clearChanges() here is not the ideal way since the // upload might fail, but there is no other place to call it... @@ -334,6 +334,7 @@ void ResourceCalDav::loadingQueuePop() { mLoader->setUrl(t->url); mLoader->setTasksUrl(t->tasksUrl); + mLoader->setJournalsUrl(t->journalsUrl); mLoader->setParent(this); mLoader->setType(0); @@ -353,10 +354,11 @@ void ResourceCalDav::loadingQueuePop() { delete t; } -void ResourceCalDav::startLoading(const TQString& url, const TQString& tasksUrl) { +void ResourceCalDav::startLoading(const TQString& url, const TQString& tasksUrl, const TQString& journalsUrl) { LoadingTask *t = new LoadingTask; t->url = url; t->tasksUrl = tasksUrl; + t->journalsUrl = journalsUrl; loadingQueuePush(t); } @@ -381,7 +383,7 @@ void ResourceCalDav::loadFinished() { else { // Set new password and try again mPrefs->setPassword(TQString(newpass)); - startLoading(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl()); + startLoading(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl(), mPrefs->getFullJournalsUrl()); } } else { @@ -429,7 +431,7 @@ void ResourceCalDav::loadFinished() { // else { // // Set new password and try again // mPrefs->setPassword(TQString(newpass)); -// startLoading(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl()); +// startLoading(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl(), mPrefs->getFullJournalsUrl()); // } } else { @@ -466,6 +468,54 @@ void ResourceCalDav::loadFinished() { } } + if (loader->journalsError()) { + if (loader->journalsErrorNumber() == -401) { + if (NULL != mPrefs) { +// TQCString newpass; +// if (KPasswordDialog::getPassword (newpass, TQString("") + i18n("Remote authorization required") + TQString("

") + i18n("Please input the password for") + TQString(" ") + mPrefs->getusername(), NULL) != 1) { +// log("load error: " + loader->journalsErrorString() ); +// loadError(TQString("[%1] ").arg(abs(loader->journalsErrorNumber())) + loader->journalsErrorString()); +// } +// else { +// // Set new password and try again +// mPrefs->setPassword(TQString(newpass)); +// startLoading(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl(), mPrefs->getFullJournalsUrl()); +// } + } + else { + log("load error: " + loader->journalsErrorString() ); + loadError(TQString("[%1] ").arg(abs(loader->journalsErrorNumber())) + loader->journalsErrorString()); + } + } + else { + log("load error: " + loader->journalsErrorString() ); + loadError(TQString("[%1] ").arg(abs(loader->journalsErrorNumber())) + loader->journalsErrorString()); + } + } else { + log("successful journals load"); + TQString journalsData = loader->journalsData(); + + if (!journalsData.isNull() && !journalsData.isEmpty()) { + // TODO: I don't know why, but some schedules on http://caldav-test.ioda.net/ (I used it for testing) + // have some lines separated by single \r rather than \n or \r\n. + // ICalFormat fails to parse that. + journalsData.replace("\r\n", "\n"); // to avoid \r\n becomes \n\n after the next line + journalsData.replace('\r', '\n'); + + log("trying to parse..."); + if (parseJournalsData(journalsData)) { + // FIXME: The agenda view can crash when a change is + // made on a remote server and a reload is requested! + log("... parsing is ok"); + log("clearing changes"); + enableChangeNotification(); + clearChanges(); + emit resourceChanged(this); + emit resourceLoaded(this); + } + } + } + // Loading queue and mLoadingQueueReady flag are not shared resources, i.e. only one thread has an access to them. // That's why no mutexes are required. mLoader->terminate(); @@ -602,6 +652,63 @@ bool ResourceCalDav::parseTasksData(const TQString& data) { return ret; } +bool ResourceCalDav::parseJournalsData(const TQString& data) { + log("parseJournalsData()"); + + bool ret = true; + + // check if the data is OK + // May be it's not efficient (parsing is done twice), but it should be safe + if (!checkData(data)) { + loadError(i18n("Parsing calendar data failed.")); + return false; + } + + log("clearing cache"); + clearJournalsCache(); + + disableChangeNotification(); + + log("actually parsing the data"); + + ICalFormat ical; + if ( !ical.fromString( &mCalendar, data ) ) { + // this should never happen, but... + ret = false; + } + + // debug code here ------------------------------------------------------- +#ifdef KCALDAV_DEBUG + const TQString fout_path = "/tmp/kcaldav_download_" + identifier() + ".tmp"; + + TQFile fout(fout_path); + if (fout.open(IO_WriteOnly | IO_Append)) { + TQTextStream sout(&fout); + sout << "---------- " << resourceName() << ": --------------------------------\n"; + sout << data << "\n"; + fout.close(); + } else { + loadError(i18n("can't open file")); + } +#endif // KCALDAV_DEBUG + // end of debug code ---------------------------------------------------- + + enableChangeNotification(); + + if (ret) { + log("parsing is ok"); + //if ( !noReadOnlyOnLoad() && readOnly() ) { + if ( readOnly() ) { + log("ensuring read only flag honored"); + ensureReadOnlyFlagHonored(); + } + log("saving to cache"); + saveCache(); + } + + return ret; +} + /*========================================================================= | WRITING METHODS ========================================================================*/ @@ -662,6 +769,7 @@ void ResourceCalDav::writingQueuePop() { mWriter->setUrl(t->url); mWriter->setTasksUrl(t->tasksUrl); + mWriter->setJournalsUrl(t->journalsUrl); mWriter->setParent(this); mWriter->setType(1); @@ -689,6 +797,10 @@ void ResourceCalDav::writingQueuePop() { mWriter->setChangedTasksObjects(t->tasksChanged); mWriter->setDeletedTasksObjects(t->tasksDeleted); + mWriter->setAddedJournalsObjects(t->journalsAdded); + mWriter->setChangedJournalsObjects(t->journalsChanged); + mWriter->setDeletedJournalsObjects(t->journalsDeleted); + mWritingQueueReady = false; log("starting actual write job"); @@ -719,7 +831,7 @@ void ResourceCalDav::releaseReadLockout() { readLockout = false; } -bool ResourceCalDav::startWriting(const TQString& url, const TQString& tasksUrl) { +bool ResourceCalDav::startWriting(const TQString& url, const TQString& tasksUrl, const TQString& journalsUrl) { log("startWriting: url = " + url); // WARNING: This will segfault if a separate read or write thread @@ -757,16 +869,22 @@ bool ResourceCalDav::startWriting(const TQString& url, const TQString& tasksUrl) t->url = url; t->tasksUrl = tasksUrl; + t->journalsUrl = journalsUrl; t->added = ""; t->changed = ""; t->deleted = ""; t->tasksAdded = ""; t->tasksChanged = ""; t->tasksDeleted = ""; + t->journalsAdded = ""; + t->journalsChanged = ""; + t->journalsDeleted = ""; if (getICalString(currentIncidence).contains("BEGIN:VEVENT") > 0) t->added = getICalString(currentIncidence); else if (getICalString(currentIncidence).contains("BEGIN:VTODO") > 0) t->tasksAdded = getICalString(currentIncidence); + else if (getICalString(currentIncidence).contains("BEGIN:VJOURNAL") > 0) + t->journalsAdded = getICalString(currentIncidence); writingQueuePush(t); } @@ -785,11 +903,16 @@ bool ResourceCalDav::startWriting(const TQString& url, const TQString& tasksUrl) t->tasksAdded = ""; t->tasksChanged = ""; t->tasksDeleted = ""; + t->journalsAdded = ""; + t->journalsChanged = ""; + t->journalsDeleted = ""; if (getICalString(currentIncidence).contains("BEGIN:VEVENT") > 0) t->changed = getICalString(currentIncidence); else if (getICalString(currentIncidence).contains("BEGIN:VTODO") > 0) t->tasksChanged = getICalString(currentIncidence); + else if (getICalString(currentIncidence).contains("BEGIN:VJOURNAL") > 0) + t->journalsChanged = getICalString(currentIncidence); writingQueuePush(t); } @@ -808,11 +931,16 @@ bool ResourceCalDav::startWriting(const TQString& url, const TQString& tasksUrl) t->tasksAdded = ""; t->tasksChanged = ""; t->tasksDeleted = ""; + t->journalsAdded = ""; + t->journalsChanged = ""; + t->journalsDeleted = ""; if (getICalString(currentIncidence).contains("BEGIN:VEVENT") > 0) t->deleted = getICalString(currentIncidence); else if (getICalString(currentIncidence).contains("BEGIN:VTODO") > 0) t->tasksDeleted = getICalString(currentIncidence); + else if (getICalString(currentIncidence).contains("BEGIN:VJOURNALS") > 0) + t->journalsDeleted = getICalString(currentIncidence); writingQueuePush(t); } @@ -839,7 +967,7 @@ void ResourceCalDav::writingFinished() { else { // Set new password and try again mPrefs->setPassword(TQString(newpass)); - startWriting(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl()); + startWriting(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl(), mPrefs->getFullJournalsUrl()); } } else { diff --git a/kresources/caldav/resource.h b/kresources/caldav/resource.h index bb69807be..033a19ce4 100644 --- a/kresources/caldav/resource.h +++ b/kresources/caldav/resource.h @@ -86,11 +86,13 @@ protected: struct LoadingTask { TQString url; TQString tasksUrl; + TQString journalsUrl; }; struct WritingTask { TQString url; TQString tasksUrl; + TQString journalsUrl; TQString added; TQString changed; @@ -99,6 +101,10 @@ protected: TQString tasksAdded; TQString tasksChanged; TQString tasksDeleted; + + TQString journalsAdded; + TQString journalsChanged; + TQString journalsDeleted; }; @@ -129,8 +135,9 @@ protected: * Initiates calendar loading process. * @param url URL to load calendar data from. * @param tasksUrl URL to load task data from. + * @param journalsUrl URL to load journal data from. */ - void startLoading(const TQString& url, const TQString& tasksUrl); + void startLoading(const TQString& url, const TQString& tasksUrl, const TQString& journalsUrl); /** * Checks if the data is correct and can be parsed. @@ -148,18 +155,26 @@ protected: /** * Parses the data and adds tasks to the calendar. - * Unlike @ref parseData, this function does NOT clear the cache. * @param data calendar data. * @return true on success, false on fail. */ bool parseTasksData(const TQString& data); + /** + * Parses the data and adds journals to the calendar. + * @param data calendar data. + * @return true on success, false on fail. + */ + bool parseJournalsData(const TQString& data); + /** * Initiates calendar writing process. - * @param url URL to save calendar data to. + * @param url URL to save event data to. + * @param tasksUrl URL to save task data to. + * @param journalsUrl URL to save journal data to. * @return true if write was queued successfully, false if not */ - bool startWriting(const TQString& url, const TQString& tasksUrl); + bool startWriting(const TQString& url, const TQString& tasksUrl, const TQString& journalsUrl); /** * Returns a list of incidences as a valid iCalendar string. diff --git a/kresources/caldav/writer.cpp b/kresources/caldav/writer.cpp index e939f3d9c..a466322eb 100644 --- a/kresources/caldav/writer.cpp +++ b/kresources/caldav/writer.cpp @@ -103,6 +103,34 @@ int CalDavWriter::runJob(runtime_info* RT) { } } + int journalsres = OK; + + if ((OK == journalsres) && (tasksUrl() != "")) { + kdDebug() << "pushing added tasks objects"; + journalsres = pushJournalsObjects(mJournalsAdded, caldav_add_object, OK, RT); + if (OK == journalsres) { +#ifdef USE_CALDAV_TASKS_MODIFY + kdDebug() << "pushing changed objects"; + journalsres = pushJournalsObjects(mJournalsChanged, caldav_tasks_modify_object, OK, RT); + if (OK == journalsres) { + kdDebug() << "pushing deleted objects"; + journalsres = pushJournalsObjects(mJournalsDeleted, caldav_tasks_delete_object, OK, RT); + } +#else // if USE_CALDAV_TASKS_MODIFY + kdDebug() << "pushing changed objects (delete)"; + journalsres = pushJournalsObjects(mJournalsChanged, caldav_tasks_delete_object, OK, RT); + if (OK == journalsres) { + kdDebug() << "pushing changed objects (add)"; + journalsres = pushJournalsObjects(mJournalsChanged, caldav_add_object, OK, RT); + if (OK == journalsres) { + kdDebug() << "pushing deleted objects"; + journalsres = pushJournalsObjects(mJournalsDeleted, caldav_tasks_delete_object, OK, RT); + } + } +#endif // if USE_CALDAV_TASKS_MODIFY + } + } + if ((OK != res) || (OK != tasksres)) { clearObjects(); } @@ -122,4 +150,13 @@ void CalDavWriter::cleanTasksJob() { // Stub function as there is no reason to split the writing jobs like the reading jobs } +int CalDavWriter::runJournalsJob(runtime_info* RT) { + // Stub function as there is no reason to split the writing jobs like the reading jobs + return OK; +} + +void CalDavWriter::cleanJournalsJob() { + // Stub function as there is no reason to split the writing jobs like the reading jobs +} + // EOF ======================================================================== diff --git a/kresources/caldav/writer.h b/kresources/caldav/writer.h index 3b8f82a81..437eeed0e 100644 --- a/kresources/caldav/writer.h +++ b/kresources/caldav/writer.h @@ -81,6 +81,15 @@ public: mTasksAdded = s; } + /** + * Sets the information about added journals writer should send to server. + * @param s icalendar-formatted string consists of all added journals plus necessary calendar info. + * May be an empty string, which means there are no added journals to send. + */ + void setAddedJournalsObjects(const TQString& s) { + mJournalsAdded = s; + } + /** * Sets the information about changed tasks writer should send to server. * @param s icalendar-formatted string consists of all changed tasks plus necessary calendar info. @@ -90,6 +99,15 @@ public: mTasksChanged = s; } + /** + * Sets the information about changed journals writer should send to server. + * @param s icalendar-formatted string consists of all changed journals plus necessary calendar info. + * May be an empty string, which means there are no changed journals to send. + */ + void setChangedJournalsObjects(const TQString& s) { + mJournalsChanged = s; + } + /** * Sets the information about deleted tasks writer should send to server. * @param s icalendar-formatted string consists of all deleted tasks plus necessary calendar info. @@ -99,6 +117,15 @@ public: mTasksDeleted = s; } + /** + * Sets the information about deleted journals writer should send to server. + * @param s icalendar-formatted string consists of all deleted journals plus necessary calendar info. + * May be an empty string, which means there are no deleted journals to send. + */ + void setDeletedJournalsObjects(const TQString& s) { + mJournalsDeleted = s; + } + /** * Clear all the information previously set. */ @@ -109,15 +136,20 @@ public: setAddedTasksObjects(""); setChangedTasksObjects(""); setDeletedTasksObjects(""); + setAddedJournalsObjects(""); + setChangedJournalsObjects(""); + setDeletedJournalsObjects(""); } protected: virtual int runJob(runtime_info* caldavRuntime); virtual int runTasksJob(runtime_info* caldavRuntime); + virtual int runJournalsJob(runtime_info* caldavRuntime); virtual void cleanJob(); virtual void cleanTasksJob(); + virtual void cleanJournalsJob(); /// Just a wrapper above libcaldav event writing functions. template @@ -139,6 +171,16 @@ protected: return r; } + /// Just a wrapper above libcaldav journal writing functions. + template + int pushJournalsObjects(const TQString& data, Operation op, int okCode, runtime_info* RT) { + int r = okCode; +// if (!data.isNull() && !data.isEmpty()) { +// r = op(std::string(data.ascii()).c_str(), std::string(journalsUrl().ascii()).c_str(), RT); +// } + return r; + } + private: TQString mAdded; @@ -148,6 +190,10 @@ private: TQString mTasksAdded; TQString mTasksChanged; TQString mTasksDeleted; + + TQString mJournalsAdded; + TQString mJournalsChanged; + TQString mJournalsDeleted; }; } // namespace KCal diff --git a/kresources/egroupware/kabc_resourcexmlrpc.cpp b/kresources/egroupware/kabc_resourcexmlrpc.cpp index ee1e74bea..115484c6a 100644 --- a/kresources/egroupware/kabc_resourcexmlrpc.cpp +++ b/kresources/egroupware/kabc_resourcexmlrpc.cpp @@ -64,8 +64,11 @@ ResourceXMLRPC::ResourceXMLRPC( const KConfig *config ) mPrefs->addGroupPrefix( identifier() ); - if ( config ) + if ( config ) { mPrefs->readConfig(); + } else { + setResourceName( i18n( "eGroupware Server" ) ); + } initEGroupware(); } diff --git a/kresources/egroupware/kabc_xmlrpc.desktop b/kresources/egroupware/kabc_xmlrpc.desktop index c7386a593..d7f8d5d62 100644 --- a/kresources/egroupware/kabc_xmlrpc.desktop +++ b/kresources/egroupware/kabc_xmlrpc.desktop @@ -20,7 +20,6 @@ Name[hu]=eGroupware-kiszolgáló (XML-RPC-n keresztül) Name[is]=eGroupware þjónn (gegnum XML-RPC) Name[it]=Server eGroupware (via XML-RPC) Name[ja]=eGroupware サーバ (XML-RPC 経由) -Name[ka]=სერბერი eGroupware (XML-RPC-ის საშუალებით) Name[kk]=eGroupware сервері (XML-RPC арқылы) Name[km]=ម៉ាស៊ីន​បម្រើ eGroupware (តាម​រយៈ XML-RPC) Name[lt]=eGroupware serveris (per XML-RPC) diff --git a/kresources/egroupware/kcal_resourcexmlrpc.cpp b/kresources/egroupware/kcal_resourcexmlrpc.cpp index bb92b2d5f..9072b1666 100644 --- a/kresources/egroupware/kcal_resourcexmlrpc.cpp +++ b/kresources/egroupware/kcal_resourcexmlrpc.cpp @@ -110,8 +110,11 @@ ResourceXMLRPC::ResourceXMLRPC( const KConfig* config ) mPrefs->addGroupPrefix( identifier() ); - if ( config ) + if ( config ) { readConfig( config ); + } else { + setResourceName( i18n( "eGroupware Server" ) ); + } initEGroupware(); } diff --git a/kresources/egroupware/kcal_xmlrpc.desktop b/kresources/egroupware/kcal_xmlrpc.desktop index 5480d86b6..93a54217f 100644 --- a/kresources/egroupware/kcal_xmlrpc.desktop +++ b/kresources/egroupware/kcal_xmlrpc.desktop @@ -20,7 +20,6 @@ Name[hu]=eGroupware-kiszolgáló (XML-RPC-n keresztül) Name[is]=eGroupware þjónn (gegnum XML-RPC) Name[it]=Server eGroupware (via XML-RPC) Name[ja]=eGroupware サーバ (XML-RPC 経由) -Name[ka]=სერბერი eGroupware (XML-RPC-ის საშუალებით) Name[kk]=eGroupware сервері (XML-RPC арқылы) Name[km]=ម៉ាស៊ីន​បម្រើ eGroupware (តាម​រយៈ XML-RPC) Name[lt]=eGroupware serveris (per XML-RPC) diff --git a/kresources/egroupware/knotes_resourcexmlrpc.cpp b/kresources/egroupware/knotes_resourcexmlrpc.cpp index b0bdb5b0d..774115d27 100644 --- a/kresources/egroupware/knotes_resourcexmlrpc.cpp +++ b/kresources/egroupware/knotes_resourcexmlrpc.cpp @@ -57,8 +57,11 @@ ResourceXMLRPC::ResourceXMLRPC( const KConfig* config ) mPrefs->addGroupPrefix( identifier() ); - if ( config ) + if ( config ) { readConfig( config ); + } else { + setResourceName( i18n( "eGroupware Server" ) ); + } } ResourceXMLRPC::ResourceXMLRPC( ) diff --git a/kresources/egroupware/knotes_xmlrpc.desktop b/kresources/egroupware/knotes_xmlrpc.desktop index 61411ce01..b3f4faa6a 100644 --- a/kresources/egroupware/knotes_xmlrpc.desktop +++ b/kresources/egroupware/knotes_xmlrpc.desktop @@ -20,7 +20,6 @@ Name[hu]=eGroupware-kiszolgáló (XML-RPC-n keresztül) Name[is]=eGroupware þjónn (gegnum XML-RPC) Name[it]=Server eGroupware (via XML-RPC) Name[ja]=eGroupware サーバ (XML-RPC 経由) -Name[ka]=სერბერი eGroupware (XML-RPC-ის საშუალებით) Name[kk]=eGroupware сервері (XML-RPC арқылы) Name[km]=ម៉ាស៊ីន​បម្រើ eGroupware (តាម​រយៈ XML-RPC) Name[lt]=eGroupware serveris (per XML-RPC) diff --git a/kresources/exchange/exchange.desktop b/kresources/exchange/exchange.desktop index 9342e3baa..5bfe8a1ed 100644 --- a/kresources/exchange/exchange.desktop +++ b/kresources/exchange/exchange.desktop @@ -26,7 +26,6 @@ Name[hu]=Exchange 2000-kiszolgáló Name[is]=Exchange 2000 þjónn Name[it]=Server Exchange 2000 Name[ja]=Exchange 2000 サーバ -Name[ka]=სერვერი Exchange 2000 Name[kk]=MS Exchange 2000 сервері Name[km]=ម៉ាស៊ីន​បម្រើ Exchange ២០០០ Name[lt]=Exchange 2000 serveris diff --git a/kresources/exchange/exchange_deprecated.desktop b/kresources/exchange/exchange_deprecated.desktop index 70ffbc63f..eba22eed2 100644 --- a/kresources/exchange/exchange_deprecated.desktop +++ b/kresources/exchange/exchange_deprecated.desktop @@ -21,7 +21,6 @@ Name[hu]=Exchange 2000-kiszolgáló (elavult) Name[is]=Exchange 2000 þjónn (úrelt) Name[it]=Server Exchange 2000 (deprecato) Name[ja]=Exchange 2000 サーバ (廃止予定) -Name[ka]=სერვერი Exchange 2000 (მოძველებული) Name[kk]=MS Exchange 2000 сервері (ескірген) Name[km]=ម៉ាស៊ីន​បម្រើ Exchange ២០០០ (មិន​សូវ​ល្អ) Name[lt]=Exchange 2000 serveris (deprecated) diff --git a/kresources/exchange/resourceexchange.cpp b/kresources/exchange/resourceexchange.cpp index 8e877f9b0..82c0ab07d 100644 --- a/kresources/exchange/resourceexchange.cpp +++ b/kresources/exchange/resourceexchange.cpp @@ -91,6 +91,7 @@ ResourceExchange::ResourceExchange( const KConfig *config ) mCachedSeconds = config->readNumEntry( "ExchangeCacheTimeout", 600 ); mAutoMailbox = config->readBoolEntry( "ExchangeAutoMailbox", true ); } else { + setResourceName( i18n( "Exchange Server" ) ); mAccount = new ExchangeAccount( "", "", "", "" ); mCachedSeconds = 600; } @@ -248,19 +249,26 @@ void ResourceExchange::slotMonitorError( int errorCode, const TQString& moreInfo } -bool ResourceExchange::addEvent(Event *anEvent) +bool ResourceExchange::addEvent( Event *event ) { + return addEvent( event, TQString() ); +} + +bool ResourceExchange::addEvent( Event *event, const TQString &subresource ) +{ + Q_UNUSED( subresource ); //subresources are not supported + if( !mCache ) return false; kdDebug() << "ResourceExchange::addEvent" << endl; // FIXME: first check of upload finished successfully, only then // add to cache - mCache->addEvent( anEvent ); + mCache->addEvent( event ); - uploadEvent( anEvent ); -// insertEvent(anEvent); + uploadEvent( event ); +// insertEvent( event ); - anEvent->registerObserver( this ); + event->registerObserver( this ); // setModified( true ); return true; @@ -341,8 +349,14 @@ void ResourceExchange::unsubscribeEvents( const TQDate &/*start*/, const TQDate kdDebug() << "ResourceExchange::unsubscribeEvents()" << endl; } -bool ResourceExchange::addTodo(Todo */*todo*/) +bool ResourceExchange::addTodo( Todo *todo ) +{ + return addTodo( todo, TQString() ); +} + +bool ResourceExchange::addTodo( Todo */*todo*/, const TQString &subresource ) { + Q_UNUSED( subresource ); //subresources are not supported // This resource doesn't handle todos yet! return false; /* if( !mCache) @@ -356,6 +370,7 @@ bool ResourceExchange::addTodo(Todo */*todo*/) return true;*/ } + bool ResourceExchange::deleteTodo(Todo */*todo*/) { // We don't handle todos yet @@ -530,8 +545,15 @@ Event::List ResourceExchange::rawEvents( EventSortField sortField, SortDirection return mCache->rawEvents( sortField, sortDirection ); } -bool ResourceExchange::addJournal(Journal */*journal*/) +bool ResourceExchange::addJournal( Journal *journal ) +{ + return addJournal( journal, TQString() ); +} + +bool ResourceExchange::addJournal( Journal */*journal*/, const TQString &subresource ) { + Q_UNUSED( subresource ); //subresources are not supported + // This resource doesn't handle journals yet return false; /* kdDebug(5800) << "Adding Journal on " << journal->dtStart().toString() << endl; diff --git a/kresources/exchange/resourceexchange.h b/kresources/exchange/resourceexchange.h index d3492cf00..7328a27b0 100644 --- a/kresources/exchange/resourceexchange.h +++ b/kresources/exchange/resourceexchange.h @@ -83,7 +83,9 @@ class ResourceExchange : public ResourceCalendar, public IncidenceBase::Observer // void close(); /** Add Event to calendar. */ - bool addEvent(Event *anEvent); + KDE_DEPRECATED bool addEvent( Event *event ); + bool addEvent( Event *event, const TQString &subresource ); + /** deletes an event from this calendar. */ bool deleteEvent(Event *); @@ -118,7 +120,8 @@ class ResourceExchange : public ResourceCalendar, public IncidenceBase::Observer /** Add a todo to the todolist. */ - bool addTodo( Todo *todo ); + KDE_DEPRECATED bool addTodo( Todo *todo ); + bool addTodo( Todo *todo, const TQString &subresource ); /** Remove a todo from the todolist. */ @@ -138,7 +141,8 @@ class ResourceExchange : public ResourceCalendar, public IncidenceBase::Observer Todo::List rawTodosForDate( const TQDate &date ); /** Add a Journal entry to calendar */ - virtual bool addJournal(Journal *); + KDE_DEPRECATED bool addJournal( Journal *journal ); + bool addJournal( Journal *journal, const TQString &subresource ); /** deletes an event from this calendar. */ virtual bool deleteJournal(Journal *); /** Return Journals for given date */ diff --git a/kresources/groupware/kabc_groupware.desktop b/kresources/groupware/kabc_groupware.desktop index 6750248b7..f2c56b26a 100644 --- a/kresources/groupware/kabc_groupware.desktop +++ b/kresources/groupware/kabc_groupware.desktop @@ -20,7 +20,6 @@ Name[hu]=Groupware kiszolgáló Name[is]=Groupware þjónn Name[it]=Server Groupware Name[ja]=グループウェアサーバ -Name[ka]=სერვერი Groupware Name[kk]=Groupware сервері Name[km]=ម៉ាស៊ីន​បម្រើ​កម្មវិធី​ពហុ​អ្នកប្រើ Name[lt]=Grupinio darbo serveris diff --git a/kresources/groupware/kabc_resourcegroupware.cpp b/kresources/groupware/kabc_resourcegroupware.cpp index c04988aa0..c9fef7a0c 100644 --- a/kresources/groupware/kabc_resourcegroupware.cpp +++ b/kresources/groupware/kabc_resourcegroupware.cpp @@ -43,6 +43,8 @@ ResourceGroupware::ResourceGroupware( const KConfig *config ) if ( config ) { readConfig( config ); + } else { + setResourceName( i18n( "Groupware Server" ) ); } } diff --git a/kresources/groupware/kcal_groupware.desktop b/kresources/groupware/kcal_groupware.desktop index 0b43536be..9692900dd 100644 --- a/kresources/groupware/kcal_groupware.desktop +++ b/kresources/groupware/kcal_groupware.desktop @@ -20,7 +20,6 @@ Name[hu]=Groupware kiszolgáló Name[is]=Groupware þjónn Name[it]=Server Groupware Name[ja]=グループウェアサーバ -Name[ka]=სერვერი Groupware Name[kk]=Groupware сервері Name[km]=ម៉ាស៊ីន​បម្រើ​កម្មវិធី​ពហុ​អ្នកប្រើ Name[lt]=Grupinio darbo serveris diff --git a/kresources/groupware/kcal_resourcegroupware.cpp b/kresources/groupware/kcal_resourcegroupware.cpp index b651d7390..01a51684f 100644 --- a/kresources/groupware/kcal_resourcegroupware.cpp +++ b/kresources/groupware/kcal_resourcegroupware.cpp @@ -62,7 +62,11 @@ ResourceGroupware::ResourceGroupware( const KConfig *config ) mPrefs->addGroupPrefix( identifier() ); - if ( config ) readConfig( config ); + if ( config ) { + readConfig( config ); + } else { + setResourceName( i18n( "Groupware Server" ) ); + } } ResourceGroupware::~ResourceGroupware() diff --git a/kresources/kolab/kabc/contact.cpp b/kresources/kolab/kabc/contact.cpp index fc9087316..26a91e679 100644 --- a/kresources/kolab/kabc/contact.cpp +++ b/kresources/kolab/kabc/contact.cpp @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -222,15 +223,15 @@ TQString Contact::profession() const return mProfession; } -// void Contact::setJobTitle( const TQString& title ) -// { -// mJobTitle = title; -// } +void Contact::setJobTitle( const TQString& title ) +{ + mJobTitle = title; +} -// TQString Contact::jobTitle() const -// { -// return mJobTitle; -// } +TQString Contact::jobTitle() const +{ + return mJobTitle; +} void Contact::setManagerName( const TQString& name ) { @@ -485,6 +486,11 @@ void Contact::saveCustomAttributes( TQDomElement& element ) const if ( (*it).app == s_unhandledTagAppName ) { writeString( element, (*it).name, (*it).value ); } else { + // skip writing the freebusyurl as it is a hack we need to remove eventually + if ( (*it).name == TQString::fromLatin1( "FreeBusyURL" ) ) { + continue; + } + // Let's use attributes so that other tag-preserving-code doesn't need sub-elements TQDomElement e = element.ownerDocument().createElement( "x-custom" ); element.appendChild( e ); @@ -659,7 +665,7 @@ bool Contact::loadAttribute( TQDomElement& element ) case 'j': if ( tagName == "job-title" ) { // see saveAttributes: is mapped to the Role field - setRole( element.text() ); + setJobTitle( element.text() ); return true; } break; @@ -766,7 +772,6 @@ bool Contact::saveAttributes( TQDomElement& element ) const { // Save the base class elements KolabBase::saveAttributes( element ); - if ( mIsDistributionList ) { writeString( element, "display-name", fullName() ); saveDistrListMembers( element ); @@ -779,11 +784,8 @@ bool Contact::saveAttributes( TQDomElement& element ) const writeString( element, "department", department() ); writeString( element, "office-location", officeLocation() ); writeString( element, "profession", profession() ); - // is gone; jobTitle() is not shown in the addresseeeditor, - // so let's bind to role() - //writeString( element, "role", role() ); - //writeString( element, "job-title", jobTitle() ); - writeString( element, "job-title", role() ); + writeString( element, "role", role() ); + writeString( element, "job-title", jobTitle() ); writeString( element, "manager-name", managerName() ); writeString( element, "assistant", assistant() ); writeString( element, "nick-name", nickName() ); @@ -891,28 +893,28 @@ static TQStringList phoneTypeToString( int /*KABC::PhoneNumber::Types*/ type ) type = type & ~KABC::PhoneNumber::Work; } - // To support both "home1" and "home2", map Home+Pref to home1 + // To support both "home1" and "home2", map Home+Pref to home2 if ( ( type & KABC::PhoneNumber::Home ) && ( type & KABC::PhoneNumber::Pref ) ) { - types << "home1"; + types << "home2"; type = type & ~KABC::PhoneNumber::Home; type = type & ~KABC::PhoneNumber::Pref; } - // To support both "business1" and "business2", map Work+Pref to business1 + // To support both "business1" and "business2", map Work+Pref to business2 if ( ( type & KABC::PhoneNumber::Work ) && ( type & KABC::PhoneNumber::Pref ) ) { - types << "business1"; + types << "business2"; type = type & ~KABC::PhoneNumber::Work; type = type & ~KABC::PhoneNumber::Pref; } if ( type & KABC::PhoneNumber::Home ) - types << "home2"; + types << "home1"; if ( type & KABC::PhoneNumber::Msg ) // Msg==messaging types << "company"; if ( type & KABC::PhoneNumber::Work ) - types << "business2"; + types << "business1"; if ( type & KABC::PhoneNumber::Pref ) types << "primary"; if ( type & KABC::PhoneNumber::Voice ) @@ -942,13 +944,13 @@ static int /*KABC::PhoneNumber::Types*/ phoneTypeFromString( const TQString& typ return KABC::PhoneNumber::Home | KABC::PhoneNumber::Fax; if ( type == "businessfax" ) return KABC::PhoneNumber::Work | KABC::PhoneNumber::Fax; - if ( type == "business1" ) - return KABC::PhoneNumber::Work | KABC::PhoneNumber::Pref; if ( type == "business2" ) + return KABC::PhoneNumber::Work | KABC::PhoneNumber::Pref; + if ( type == "business1" ) return KABC::PhoneNumber::Work; - if ( type == "home1" ) - return KABC::PhoneNumber::Home | KABC::PhoneNumber::Pref; if ( type == "home2" ) + return KABC::PhoneNumber::Home | KABC::PhoneNumber::Pref; + if ( type == "home1" ) return KABC::PhoneNumber::Home; if ( type == "company" ) return KABC::PhoneNumber::Msg; @@ -1019,11 +1021,15 @@ void Contact::setFields( const KABC::Addressee* addressee ) setOrganization( addressee->organization() ); setWebPage( addressee->url().url() ); setIMAddress( addressee->custom( "KADDRESSBOOK", "X-IMAddress" ) ); +#if KDE_IS_VERSION(3,5,8) + setDepartment( addressee->department()); +#else setDepartment( addressee->custom( "KADDRESSBOOK", "X-Department" ) ); +#endif setOfficeLocation( addressee->custom( "KADDRESSBOOK", "X-Office" ) ); setProfession( addressee->custom( "KADDRESSBOOK", "X-Profession" ) ); setRole( addressee->role() ); - //setJobTitle( addressee->title() ); + setJobTitle( addressee->title() ); setManagerName( addressee->custom( "KADDRESSBOOK", "X-ManagersName" ) ); setAssistant( addressee->custom( "KADDRESSBOOK", "X-AssistantsName" ) ); setNickName( addressee->nickName() ); @@ -1129,6 +1135,11 @@ void Contact::setFields( const KABC::Addressee* addressee ) } } + TQString url = KCal::FreeBusyUrlStore::self()->readUrl( addressee->preferredEmail() ); + if ( !url.isEmpty() ) { + setFreeBusyUrl( url ); + } + // Those fields, although defined in Addressee, are not used in KDE // (e.g. not visible in kaddressbook/addresseeeditorwidget.cpp) // So it doesn't matter much if we don't have them in the XML. @@ -1136,9 +1147,6 @@ void Contact::setFields( const KABC::Addressee* addressee ) // Things KAddressBook can't handle, so they are saved as unhandled tags: // initials, children, gender, language - - // TODO: Free/Busy URL. This is done rather awkward in KAddressBook - - // it stores it in a local file through a korganizer file :-( } // The loading is: xml -> Contact -> addressee, this is the second part @@ -1173,11 +1181,15 @@ void Contact::saveTo( KABC::Addressee* addressee ) addressee->setOrganization( organization() ); addressee->setUrl( webPage() ); addressee->insertCustom( "KADDRESSBOOK", "X-IMAddress", imAddress() ); +#if KDE_IS_VERSION(3,5,8) + addressee->setDepartment( department() ); +#else addressee->insertCustom( "KADDRESSBOOK", "X-Department", department() ); +#endif addressee->insertCustom( "KADDRESSBOOK", "X-Office", officeLocation() ); addressee->insertCustom( "KADDRESSBOOK", "X-Profession", profession() ); addressee->setRole( role() ); - //addressee->setTitle( jobTitle() ); + addressee->setTitle( jobTitle() ); addressee->insertCustom( "KADDRESSBOOK", "X-ManagersName", managerName() ); addressee->insertCustom( "KADDRESSBOOK", "X-AssistantsName", assistant() ); addressee->setNickName( nickName() ); diff --git a/kresources/kolab/kabc/contact.h b/kresources/kolab/kabc/contact.h index 39a235cc2..a9465642f 100644 --- a/kresources/kolab/kabc/contact.h +++ b/kresources/kolab/kabc/contact.h @@ -121,9 +121,8 @@ public: void setProfession( const TQString& profession ); TQString profession() const; - // not shown in the kaddressbook GUI - //void setJobTitle( const TQString& title ); - //TQString jobTitle() const; + void setJobTitle( const TQString& title ); + TQString jobTitle() const; void setManagerName( const TQString& name ); TQString managerName() const; @@ -245,7 +244,7 @@ private: TQString mDepartment; TQString mOfficeLocation; TQString mProfession; - //TQString mJobTitle; + TQString mJobTitle; TQString mManagerName; TQString mAssistant; TQString mNickName; diff --git a/kresources/kolab/kabc/kolab.desktop b/kresources/kolab/kabc/kolab.desktop index d75090a7a..8339f9c22 100644 --- a/kresources/kolab/kabc/kolab.desktop +++ b/kresources/kolab/kabc/kolab.desktop @@ -21,7 +21,6 @@ Name[hu]=IMAP-kiszolgálón tárolt címjegyzék a KMailen keresztül Name[is]=Vistfangaskrá á IMAP þjóni gegnum KMail Name[it]=Rubrica indirizzi su server IMAP via KMail Name[ja]=KMail 経由 IMAP サーバのアドレス帳 -Name[ka]=წიგნაკი IMAP-ის სერვერზე KMail-ის საშუალებით Name[kk]=KMail арқылы IMAP серверіндегі адрестік кітапша Name[km]=សៀវភៅ​អាសយដ្ឋាន​លើ​ម៉ាស៊ីន​បម្រើ IMAP តាម​រយៈ KMail Name[lt]=Adresų knygelė IMAP serveryje per KMail diff --git a/kresources/kolab/kabc/resourcekolab.cpp b/kresources/kolab/kabc/resourcekolab.cpp index 034c32d78..ae8e225fb 100644 --- a/kresources/kolab/kabc/resourcekolab.cpp +++ b/kresources/kolab/kabc/resourcekolab.cpp @@ -79,9 +79,12 @@ static const char* s_inlineMimeType = "text/x-vcard"; KABC::ResourceKolab::ResourceKolab( const KConfig *config ) : KPIM::ResourceABC( config ), Kolab::ResourceKolabBase( "ResourceKolab-KABC" ), - mCachedSubresource( TQString::null ), mLocked( false ) + mCachedSubresource( TQString::null ), mCachedSubresourceNotFound( false ), mLocked( false ) { setType( "imap" ); + if ( !config ) { + setResourceName( i18n( "Kolab Server" ) ); + } } KABC::ResourceKolab::~ResourceKolab() @@ -124,14 +127,7 @@ bool KABC::ResourceKolab::doOpen() void KABC::ResourceKolab::doClose() { - KConfig config( configFile() ); - - Kolab::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() ); - } + writeConfig(); } KABC::Ticket * KABC::ResourceKolab::requestSaveTicket() @@ -149,6 +145,7 @@ void KABC::ResourceKolab::releaseSaveTicket( Ticket* ticket ) { mLocked = false; mCachedSubresource = TQString::null; + mCachedSubresourceNotFound = false; delete ticket; } @@ -163,7 +160,11 @@ TQString KABC::ResourceKolab::loadContact( const TQString& contactData, contact.saveTo( &addr ); } else { KABC::VCardConverter converter; +#if defined(KABC_VCARD_ENCODING_FIX) + addr = converter.parseVCardRaw( contactData.utf8() ); +#else addr = converter.parseVCard( contactData ); +#endif } addr.setResource( this ); @@ -301,11 +302,11 @@ void AttachmentList::updatePictureAttachment( const TQImage& image, const TQStri { assert( !name.isEmpty() ); if ( !image.isNull() ) { - KTempFile* tempFile = new KTempFile; - image.save( tempFile->file(), "PNG" ); - tempFile->close(); + KTempFile tempFile; + image.save( tempFile.file(), "PNG" ); + tempFile.close(); KURL url; - url.setPath( tempFile->name() ); + url.setPath( tempFile.name() ); kdDebug(5650) << "picture saved to " << url.path() << endl; addAttachment( url.url(), name, "image/png" ); } else { @@ -317,11 +318,11 @@ void AttachmentList::updateAttachment( const TQByteArray& data, const TQString& { assert( !name.isEmpty() ); if ( !data.isNull() ) { - KTempFile* tempFile = new KTempFile; - tempFile->file()->writeBlock( data ); - tempFile->close(); + KTempFile tempFile; + tempFile.file()->writeBlock( data ); + tempFile.close(); KURL url; - url.setPath( tempFile->name() ); + url.setPath( tempFile.name() ); kdDebug(5650) << "data saved to " << url.path() << endl; addAttachment( url.url(), name, mimetype ); } else { @@ -342,14 +343,20 @@ bool KABC::ResourceKolab::kmailUpdateAddressee( const Addressee& addr ) } sernum = mUidMap[ uid ].serialNumber(); } else { - if ( !mCachedSubresource.isNull() ) { + if ( !mCachedSubresource.isNull() || mCachedSubresourceNotFound ) { subResource = mCachedSubresource; } else { - subResource = findWritableResource( mSubResources ); + subResource = findWritableResource( Kolab::Contacts, mSubResources ); // We were locked, remember the subresource we are working with until // we are unlocked - if ( mLocked ) + if ( mLocked ) { mCachedSubresource = subResource; + + // If the subresource is empty here, it means findWritableResource() failed, for example + // because the user cancelled the resource selection dialog. Remember that, so we avoid + // asking multiple times when locked. + mCachedSubresourceNotFound = subResource.isEmpty(); + } } if ( subResource.isEmpty() ) return false; @@ -374,7 +381,11 @@ bool KABC::ResourceKolab::kmailUpdateAddressee( const Addressee& addr ) } else { mimetype = s_inlineMimeType; KABC::VCardConverter converter; +#if defined(KABC_VCARD_ENCODING_FIX) + data = TQString::fromUtf8( converter.createVCardRaw( addr ) ); +#else data = converter.createVCard( addr ); +#endif subject.prepend( "vCard " ); // as per kolab1 spec } bool rc = kmailUpdate( subResource, sernum, data, mimetype, subject, @@ -652,6 +663,7 @@ void KABC::ResourceKolab::setSubresourceActive( const TQString &subresource, boo } else { kdDebug(5650) << "setSubresourceCompletionWeight: subresource " << subresource << " not found" << endl; } + writeConfig(); } @@ -667,4 +679,16 @@ bool KABC::ResourceKolab::removeSubresource( const TQString& id ) return kmailRemoveSubresource( id ); } +void KABC::ResourceKolab::writeConfig() +{ + KConfig config( configFile() ); + + Kolab::ResourceMap::ConstIterator it; + for ( it = mSubResources.constBegin(); it != mSubResources.constEnd(); ++it ) { + config.setGroup( it.key() ); + config.writeEntry( "Active", it.data().active() ); + config.writeEntry( "CompletionWeight", it.data().completionWeight() ); + } +} + #include "resourcekolab.moc" diff --git a/kresources/kolab/kabc/resourcekolab.h b/kresources/kolab/kabc/resourcekolab.h index 1da472015..9158375a1 100644 --- a/kresources/kolab/kabc/resourcekolab.h +++ b/kresources/kolab/kabc/resourcekolab.h @@ -164,9 +164,12 @@ protected: return Kolab::ResourceKolabBase::configFile( "kabc" ); } + void writeConfig(); + // The list of subresources Kolab::ResourceMap mSubResources; TQString mCachedSubresource; + bool mCachedSubresourceNotFound; bool mLocked; }; diff --git a/kresources/kolab/kcal/event.cpp b/kresources/kolab/kcal/event.cpp index 0f25eb73d..e1d58a13c 100644 --- a/kresources/kolab/kcal/event.cpp +++ b/kresources/kolab/kcal/event.cpp @@ -190,7 +190,9 @@ void Event::setFields( const KCal::Event* event ) { Incidence::setFields( event ); - if ( event->hasEndDate() ) { + // note: if hasEndDate() is false and hasDuration() is true + // dtEnd() returns start+duration + if ( event->hasEndDate() || event->hasDuration() ) { if ( event->doesFloat() ) { // This is a floating event. Don't timezone move this one mFloatingStatus = AllDay; @@ -199,8 +201,9 @@ void Event::setFields( const KCal::Event* event ) mFloatingStatus = HasTime; setEndDate( localToUTC( event->dtEnd() ) ); } - } else + } else { mHasEndDate = false; + } setTransparency( event->transparency() ); } diff --git a/kresources/kolab/kcal/incidence.cpp b/kresources/kolab/kcal/incidence.cpp index 74f41fd8d..de076eb98 100644 --- a/kresources/kolab/kcal/incidence.cpp +++ b/kresources/kolab/kcal/incidence.cpp @@ -39,6 +39,8 @@ #include #include +#include + #include #include #include @@ -50,7 +52,6 @@ using namespace Kolab; Incidence::Incidence( KCal::ResourceKolab *res, const TQString &subResource, Q_UINT32 sernum, const TQString& tz ) : KolabBase( tz ), mFloatingStatus( Unset ), mHasAlarm( false ), - mRevision( 0 ), mResource( res ), mSubResource( subResource ), mSernum( sernum ) @@ -163,16 +164,6 @@ TQString Incidence::internalUID() const return mInternalUID; } -void Incidence::setRevision( int revision ) -{ - mRevision = revision; -} - -int Incidence::revision() const -{ - return mRevision; -} - bool Incidence::loadAttendeeAttribute( TQDomElement& element, Attendee& attendee ) { @@ -183,8 +174,16 @@ bool Incidence::loadAttendeeAttribute( TQDomElement& element, TQDomElement e = n.toElement(); TQString tagName = e.tagName(); - if ( tagName == "display-name" ) - attendee.displayName = e.text(); + if ( tagName == "display-name" ) { + // Quote the text in case it contains commas or other quotable chars. + TQString tusername = KPIM::quoteNameIfNecessary( e.text() ); + + TQString tname, temail; + // ignore the return value because it will always be false since + // tusername does not contain "@domain". + KPIM::getNameAndMail( tusername, tname, temail ); + attendee.displayName = tname; + } else if ( tagName == "smtp-address" ) attendee.smtpAddress = e.text(); else if ( tagName == "status" ) @@ -249,6 +248,69 @@ void Incidence::saveAttachments( TQDomElement& element ) const } } +void Incidence::saveAlarms( TQDomElement& element ) const +{ + if ( mAlarms.isEmpty() ) return; + + TQDomElement list = element.ownerDocument().createElement( "advanced-alarms" ); + element.appendChild( list ); + for ( KCal::Alarm::List::ConstIterator it = mAlarms.constBegin(); it != mAlarms.constEnd(); ++it ) { + KCal::Alarm* a = *it; + TQDomElement e = list.ownerDocument().createElement( "alarm" ); + list.appendChild( e ); + + writeString( e, "enabled", a->enabled() ? "1" : "0" ); + if ( a->hasStartOffset() ) { + writeString( e, "start-offset", TQString::number( a->startOffset().asSeconds()/60 ) ); + } + if ( a->hasEndOffset() ) { + writeString( e, "end-offset", TQString::number( a->endOffset().asSeconds()/60 ) ); + } + if ( a->repeatCount() ) { + writeString( e, "repeat-count", TQString::number( a->repeatCount() ) ); + writeString( e, "repeat-interval", TQString::number( a->snoozeTime() ) ); + } + + switch ( a->type() ) { + case KCal::Alarm::Invalid: + break; + case KCal::Alarm::Display: + e.setAttribute( "type", "display" ); + writeString( e, "text", a->text() ); + break; + case KCal::Alarm::Procedure: + e.setAttribute( "type", "procedure" ); + writeString( e, "program", a->programFile() ); + writeString( e, "arguments", a->programArguments() ); + break; + case KCal::Alarm::Email: + { + e.setAttribute( "type", "email" ); + TQDomElement addresses = e.ownerDocument().createElement( "addresses" ); + e.appendChild( addresses ); + for ( TQValueList::ConstIterator it = a->mailAddresses().constBegin(); it != a->mailAddresses().constEnd(); ++it ) { + writeString( addresses, "address", (*it).fullName() ); + } + writeString( e, "subject", a->mailSubject() ); + writeString( e, "mail-text", a->mailText() ); + TQDomElement attachments = e.ownerDocument().createElement( "attachments" ); + e.appendChild( attachments ); + for ( TQStringList::ConstIterator it = a->mailAttachments().constBegin(); it != a->mailAttachments().constEnd(); ++it ) { + writeString( attachments, "attachment", *it ); + } + break; + } + case KCal::Alarm::Audio: + e.setAttribute( "type", "audio" ); + writeString( e, "file", a->audioFile() ); + break; + default: + kdWarning() << "Unhandled alarm type:" << a->type() << endl; + break; + } + } +} + void Incidence::saveRecurrence( TQDomElement& element ) const { TQDomElement e = element.ownerDocument().createElement( "recurrence" ); @@ -289,8 +351,14 @@ void Incidence::loadRecurrence( const TQDomElement& element ) TQDomElement e = n.toElement(); TQString tagName = e.tagName(); - if ( tagName == "interval" ) - mRecurrence.interval = e.text().toInt(); + if ( tagName == "interval" ) { + //kolab/issue4229, sometimes the interval value can be empty + if ( e.text().isEmpty() || e.text().toInt() <= 0 ) { + mRecurrence.interval = 1; + } else { + mRecurrence.interval = e.text().toInt(); + } + } else if ( tagName == "day" ) // can be present multiple times mRecurrence.days.append( e.text() ); else if ( tagName == "daynumber" ) @@ -309,6 +377,118 @@ void Incidence::loadRecurrence( const TQDomElement& element ) } } +static void loadAddressesHelper( const TQDomElement& element, KCal::Alarm* a ) +{ + for ( TQDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) { + if ( n.isComment() ) + continue; + if ( n.isElement() ) { + TQDomElement e = n.toElement(); + TQString tagName = e.tagName(); + + if ( tagName == "address" ) { + a->addMailAddress( KCal::Person( e.text() ) ); + } else { + kdWarning() << "Unhandled tag" << tagName << endl; + } + } + } +} + +static void loadAttachmentsHelper( const TQDomElement& element, KCal::Alarm* a ) +{ + for ( TQDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) { + if ( n.isComment() ) + continue; + if ( n.isElement() ) { + TQDomElement e = n.toElement(); + TQString tagName = e.tagName(); + + if ( tagName == "attachment" ) { + a->addMailAttachment( e.text() ); + } else { + kdWarning() << "Unhandled tag" << tagName << endl; + } + } + } +} + +static void loadAlarmHelper( const TQDomElement& element, KCal::Alarm* a ) +{ + for ( TQDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) { + if ( n.isComment() ) + continue; + if ( n.isElement() ) { + TQDomElement e = n.toElement(); + TQString tagName = e.tagName(); + + if ( tagName == "start-offset" ) { + a->setStartOffset( e.text().toInt()*60 ); + } else if ( tagName == "end-offset" ) { + a->setEndOffset( e.text().toInt()*60 ); + } else if ( tagName == "repeat-count" ) { + a->setRepeatCount( e.text().toInt() ); + } else if ( tagName == "repeat-interval" ) { + a->setSnoozeTime( e.text().toInt() ); + } else if ( tagName == "text" ) { + a->setText( e.text() ); + } else if ( tagName == "program" ) { + a->setProgramFile( e.text() ); + } else if ( tagName == "arguments" ) { + a->setProgramArguments( e.text() ); + } else if ( tagName == "addresses" ) { + loadAddressesHelper( e, a ); + } else if ( tagName == "subject" ) { + a->setMailSubject( e.text() ); + } else if ( tagName == "mail-text" ) { + a->setMailText( e.text() ); + } else if ( tagName == "attachments" ) { + loadAttachmentsHelper( e, a ); + } else if ( tagName == "file" ) { + a->setAudioFile( e.text() ); + } else if ( tagName == "enabled" ) { + a->setEnabled( e.text().toInt() != 0 ); + } else { + kdWarning() << "Unhandled tag" << tagName << endl; + } + } + } +} + +void Incidence::loadAlarms( const TQDomElement& element ) +{ + for ( TQDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) { + if ( n.isComment() ) + continue; + if ( n.isElement() ) { + TQDomElement e = n.toElement(); + TQString tagName = e.tagName(); + + if ( tagName == "alarm" ) { + KCal::Alarm *a = new KCal::Alarm( 0 ); + a->setEnabled( true ); // default to enabled, unless some XML attribute says otherwise. + TQString type = e.attribute( "type" ); + if ( type == "display" ) { + a->setType( KCal::Alarm::Display ); + } else if ( type == "procedure" ) { + a->setType( KCal::Alarm::Procedure ); + } else if ( type == "email" ) { + a->setType( KCal::Alarm::Email ); + } else if ( type == "audio" ) { + a->setType( KCal::Alarm::Audio ); + } else { + kdWarning() << "Unhandled alarm type:" << type << endl; + } + + loadAlarmHelper( e, a ); + mAlarms << a; + } else { + kdWarning() << "Unhandled tag" << tagName << endl; + } + } + } +} + bool Incidence::loadAttribute( TQDomElement& element ) { TQString tagName = element.tagName(); @@ -340,20 +520,17 @@ bool Incidence::loadAttribute( TQDomElement& element ) } else if ( tagName == "alarm" ) // Alarms should be minutes before. Libkcal uses event time + alarm time setAlarm( - element.text().toInt() ); + else if ( tagName == "advanced-alarms" ) + loadAlarms( element ); else if ( tagName == "x-kde-internaluid" ) setInternalUID( element.text() ); - else if ( tagName == "revision" ) { - bool ok; - int revision = element.text().toInt( &ok ); - if ( ok ) - setRevision( revision ); - } else if ( tagName == "x-custom" ) + else if ( tagName == "x-custom" ) loadCustomAttributes( element ); else { bool ok = KolabBase::loadAttribute( element ); if ( !ok ) { // Unhandled tag - save for later storage - kdDebug() << "Saving unhandled tag " << element.tagName() << endl; + //kdDebug() << "Saving unhandled tag " << element.tagName() << endl; Custom c; c.key = TQCString( "X-KDE-KolabUnhandled-" ) + element.tagName().latin1(); c.value = element.text(); @@ -385,8 +562,8 @@ bool Incidence::saveAttributes( TQDomElement& element ) const int alarmTime = qRound( -alarm() ); writeString( element, "alarm", TQString::number( alarmTime ) ); } + saveAlarms( element ); writeString( element, "x-kde-internaluid", internalUID() ); - writeString( element, "revision", TQString::number( revision() ) ); saveCustomAttributes( element ); return true; } @@ -424,13 +601,15 @@ static KCal::Attendee::PartStat attendeeStringToStatus( const TQString& s ) return KCal::Attendee::NeedsAction; if ( s == "tentative" ) return KCal::Attendee::Tentative; + if ( s == "accepted" ) + return KCal::Attendee::Accepted; if ( s == "declined" ) return KCal::Attendee::Declined; if ( s == "delegated" ) return KCal::Attendee::Delegated; // Default: - return KCal::Attendee::Accepted; + return KCal::Attendee::None; } static TQString attendeeStatusToString( KCal::Attendee::PartStat status ) @@ -649,6 +828,14 @@ void Incidence::setFields( const KCal::Incidence* incidence ) mAttachments.push_back( a ); } + mAlarms.clear(); + + // Alarms + const KCal::Alarm::List alarms = incidence->alarms(); + for ( KCal::Alarm::List::ConstIterator it = alarms.begin(); it != alarms.end(); ++it ) { + mAlarms.push_back( *it ); + } + if ( incidence->doesRecur() ) { setRecurrence( incidence->recurrence() ); mRecurrence.exclusions = incidence->recurrence()->exDates(); @@ -711,10 +898,17 @@ void Incidence::saveTo( KCal::Incidence* incidence ) incidence->setSummary( summary() ); incidence->setLocation( location() ); - if ( mHasAlarm ) { + if ( mHasAlarm && mAlarms.isEmpty() ) { KCal::Alarm* alarm = incidence->newAlarm(); alarm->setStartOffset( qRound( mAlarm * 60.0 ) ); alarm->setEnabled( true ); + alarm->setType( KCal::Alarm::Display ); + } else if ( !mAlarms.isEmpty() ) { + for ( KCal::Alarm::List::ConstIterator it = mAlarms.constBegin(); it != mAlarms.constEnd(); ++it ) { + KCal::Alarm *alarm = *it; + alarm->setParent( incidence ); + incidence->addAlarm( alarm ); + } } if ( organizer().displayName.isEmpty() ) @@ -803,7 +997,7 @@ void Incidence::saveTo( KCal::Incidence* incidence ) if ( hasPilotSyncStatus() ) incidence->setSyncStatus( pilotSyncStatus() ); - for( TQValueList::ConstIterator it = mCustomList.begin(); it != mCustomList.end(); ++it ) { + for( TQValueList::ConstIterator it = mCustomList.constBegin(); it != mCustomList.constEnd(); ++it ) { incidence->setNonKDECustomProperty( (*it).key, (*it).value ); } @@ -836,7 +1030,7 @@ void Incidence::loadAttachments() TQString Incidence::productID() const { - return TQString( "KOrganizer " ) + korgVersion + ", Kolab resource"; + return TQString( "KOrganizer %1, Kolab resource" ).arg( korgVersion ); } // Unhandled KCal::Incidence fields: diff --git a/kresources/kolab/kcal/incidence.h b/kresources/kolab/kcal/incidence.h index 32b112aaf..582d34c38 100644 --- a/kresources/kolab/kcal/incidence.h +++ b/kresources/kolab/kcal/incidence.h @@ -41,6 +41,7 @@ class TQDomElement; namespace KCal { class Incidence; class Recurrence; + class Alarm; class Attachment; class ResourceKolab; } @@ -115,9 +116,6 @@ public: void setInternalUID( const TQString& iuid ); TQString internalUID() const; - virtual void setRevision( int ); - virtual int revision() const; - // Load the attributes of this class virtual bool loadAttribute( TQDomElement& ); @@ -136,6 +134,9 @@ protected: void saveAttendees( TQDomElement& element ) const; void saveAttachments( TQDomElement& element ) const; + void loadAlarms( const TQDomElement& element ); + void saveAlarms( TQDomElement& element ) const; + void loadRecurrence( const TQDomElement& element ); void saveRecurrence( TQDomElement& element ) const; void saveCustomAttributes( TQDomElement& element ) const; @@ -154,9 +155,9 @@ protected: bool mHasAlarm; Recurrence mRecurrence; TQValueList mAttendees; + TQValueList mAlarms; TQValueList mAttachments; TQString mInternalUID; - int mRevision; struct Custom { TQCString key; diff --git a/kresources/kolab/kcal/kolab.desktop b/kresources/kolab/kcal/kolab.desktop index 579e6406d..c0a7daa56 100644 --- a/kresources/kolab/kcal/kolab.desktop +++ b/kresources/kolab/kcal/kolab.desktop @@ -21,7 +21,6 @@ Name[hu]=IMAP-kiszolgálón tárolt naptár a KMailen keresztül Name[is]=Dagatal á IMAP þjóni gegnum KMail Name[it]=Calendario su server IMAP via KMail Name[ja]=KMail 経由 IMAP サーバのカレンダー -Name[ka]=კალენდარი IMAP სერვერზე KMail-ის საშუალებით Name[kk]=KMail арқылы IMAP серверіндегі күнтізбе Name[km]=ប្រតិទិន​លើ​ម៉ាស៊ីន​បម្រើ IMAP តាម​រយៈ KMail Name[lt]=Kalendorius IMAP serveryje per KMail diff --git a/kresources/kolab/kcal/resourcekolab.cpp b/kresources/kolab/kcal/resourcekolab.cpp index b61b12110..1f5f486ff 100644 --- a/kresources/kolab/kcal/resourcekolab.cpp +++ b/kresources/kolab/kcal/resourcekolab.cpp @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include @@ -72,8 +71,11 @@ static const char* incidenceInlineMimeType = "text/calendar"; ResourceKolab::ResourceKolab( const KConfig *config ) : ResourceCalendar( config ), ResourceKolabBase( "ResourceKolab-libkcal" ), mCalendar( TQString::fromLatin1("UTC") ), mOpen( false ),mResourceChangedTimer( 0, - "mResourceChangedTimer" ) + "mResourceChangedTimer" ), mBatchAddingInProgress( false ) { + if ( !config ) { + setResourceName( i18n( "Kolab Server" ) ); + } setType( "imap" ); connect( &mResourceChangedTimer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( slotEmitResourceChanged() ) ); @@ -132,7 +134,7 @@ bool ResourceKolab::doOpen() && openResource( config, kmailJournalContentsType, mJournalSubResources ); } -static void closeResource( KConfig& config, ResourceMap& map ) +static void writeResourceConfig( KConfig& config, ResourceMap& map ) { ResourceMap::ConstIterator it; for ( it = map.begin(); it != map.end(); ++it ) { @@ -148,10 +150,7 @@ void ResourceKolab::doClose() return; mOpen = false; - KConfig config( configFile() ); - closeResource( config, mEventSubResources ); - closeResource( config, mTodoSubResources ); - closeResource( config, mJournalSubResources ); + writeConfig(); } bool ResourceKolab::loadSubResource( const TQString& subResource, @@ -217,11 +216,20 @@ bool ResourceKolab::loadSubResource( const TQString& subResource, bool ResourceKolab::doLoad() { if (!mUidMap.isEmpty() ) { + emit resourceLoaded( this ); return true; } mUidMap.clear(); - return loadAllEvents() & loadAllTodos() & loadAllJournals(); + bool result = loadAllEvents() & loadAllTodos() & loadAllJournals(); + if ( result ) { + emit resourceLoaded( this ); + } else { + // FIXME: anyone know if the resource correctly calls loadError() + // if it has one? + } + + return result; } bool ResourceKolab::doLoadAll( ResourceMap& map, const char* mimetype ) @@ -297,19 +305,54 @@ bool ResourceKolab::doSave() && kmailTriggerSync( kmailJournalContentsType ); */ } -void ResourceKolab::incidenceUpdatedSilent( KCal::IncidenceBase* incidencebase) +void ResourceKolab::incidenceUpdatedSilent( KCal::IncidenceBase* incidencebase ) { - const TQString uid = incidencebase->uid(); + const TQString uid = incidencebase->uid(); //kdDebug() << k_funcinfo << uid << endl; if ( mUidsPendingUpdate.contains( uid ) || mUidsPendingAdding.contains( uid ) ) { /* We are currently processing this event ( removing and readding or * adding it ). If so, ignore this update. Keep the last of these around * and process once we hear back from KMail on this event. */ - mPendingUpdates.replace( uid, incidencebase ); + mPendingUpdates.remove( uid ); + mPendingUpdates.insert( uid, incidencebase ); return; } + { // start optimization + /** + KOrganizer and libkcal like calling two Incidence::updated() + for only one user change. That's because after a change, + IncidenceChanger calls incidence->setRevision( rev++ ); + which also calls Incidence::updated(). + + Lets ignore the first updated() and only send to kmail + the second. This makes things faster. + */ + + //IncidenceBase doesn't have revision(), downcast needed. + Incidence *i = dynamic_cast( incidencebase ); + + if ( i ) { + bool ignoreThisUpdate = false; + + if ( !mLastKnownRevisions.contains( uid ) ) { + mLastKnownRevisions[uid] = i->revision(); + } + + // update the last known revision + if ( mLastKnownRevisions[uid] < i->revision() ) { + mLastKnownRevisions[uid] = i->revision(); + } else { + ignoreThisUpdate = true; + } + + if ( ignoreThisUpdate ) { + return; + } + } + } // end optimization + TQString subResource; Q_UINT32 sernum = 0; if ( mUidMap.contains( uid ) ) { @@ -317,78 +360,85 @@ void ResourceKolab::incidenceUpdatedSilent( KCal::IncidenceBase* incidencebase) sernum = mUidMap[ uid ].serialNumber(); mUidsPendingUpdate.append( uid ); } - sendKMailUpdate( incidencebase, subResource, sernum ); + sendKMailUpdate( incidencebase, subResource, sernum ); } void ResourceKolab::incidenceUpdated( KCal::IncidenceBase* incidencebase ) { - if ( incidencebase->isReadOnly() ) return; + if ( incidencebase->isReadOnly() ) { + return; + } + incidencebase->setSyncStatusSilent( KCal::Event::SYNCMOD ); incidencebase->setLastModified( TQDateTime::currentDateTime() ); + // we should probably update the revision number here, // or internally in the Event itself when certain things change. // need to verify with ical documentation. incidenceUpdatedSilent( incidencebase ); - } void ResourceKolab::resolveConflict( KCal::Incidence* inc, const TQString& subresource, Q_UINT32 sernum ) { - if ( ! inc ) - return; - if ( ! mResolveConflict ) { - // we should do no conflict resolution - delete inc; - return; - } - const TQString origUid = inc->uid(); - Incidence* local = mCalendar.incidence( origUid ); - Incidence* localIncidence = 0; - Incidence* addedIncidence = 0; - Incidence* result = 0; - if ( local ) { - if (*local == *inc) { - // real duplicate, remove the second one - result = local; - } else { - KIncidenceChooser* ch = new KIncidenceChooser(); - ch->setIncidence( local ,inc ); - if ( KIncidenceChooser::chooseMode == KIncidenceChooser::ask ) { - connect ( this, TQT_SIGNAL( useGlobalMode() ), ch, TQT_SLOT ( useGlobalMode() ) ); - if ( ch->exec() ) - if ( KIncidenceChooser::chooseMode != KIncidenceChooser::ask ) - emit useGlobalMode() ; - } - result = ch->getIncidence(); - delete ch; - } - } else { - // nothing there locally, just take the new one. Can't Happen (TM) - result = inc; - } - if ( result == local ) { - delete inc; - localIncidence = local; - } else if ( result == inc ) { - addedIncidence = inc; - } else if ( result == 0 ) { // take both - addedIncidence = inc; - addedIncidence->setSummary( i18n("Copy of: %1").arg( addedIncidence->summary() ) ); - addedIncidence->setUid( CalFormat::createUniqueId() ); - localIncidence = local; - } - bool silent = mSilent; - mSilent = false; - if ( !localIncidence ) { - deleteIncidence( local ); // remove local from kmail - } - mUidsPendingDeletion.append( origUid ); - if ( addedIncidence ) { - sendKMailUpdate( addedIncidence, subresource, sernum ); - } else { - kmailDeleteIncidence( subresource, sernum );// remove new from kmail - } - mSilent = silent; + if ( !inc ) { + return; + } + + if ( !mResolveConflict ) { + // we should do no conflict resolution + delete inc; + return; + } + const TQString origUid = inc->uid(); + Incidence* local = mCalendar.incidence( origUid ); + Incidence* localIncidence = 0; + Incidence* addedIncidence = 0; + Incidence* result = 0; + if ( local ) { + if ( *local == *inc ) { + // real duplicate, remove the second one + result = local; + } else { + KIncidenceChooser* ch = new KIncidenceChooser(); + ch->setIncidence( local ,inc ); + if ( KIncidenceChooser::chooseMode == KIncidenceChooser::ask ) { + connect ( this, TQT_SIGNAL( useGlobalMode() ), ch, TQT_SLOT ( useGlobalMode() ) ); + if ( ch->exec() ) { + if ( KIncidenceChooser::chooseMode != KIncidenceChooser::ask ) { + emit useGlobalMode() ; + } + } + } + result = ch->getIncidence(); + delete ch; + } + } else { + // nothing there locally, just take the new one. Can't Happen (TM) + result = inc; + } + if ( result == local ) { + delete inc; + localIncidence = local; + } else if ( result == inc ) { + addedIncidence = inc; + } else if ( result == 0 ) { // take both + addedIncidence = inc; + addedIncidence->setSummary( i18n("Copy of: %1").arg( addedIncidence->summary() ) ); + addedIncidence->setUid( CalFormat::createUniqueId() ); + localIncidence = local; + } + const bool silent = mSilent; + mSilent = false; + if ( !localIncidence ) { + deleteIncidence( local ); // remove local from kmail + } + mUidsPendingDeletion.append( origUid ); + if ( addedIncidence ) { + sendKMailUpdate( addedIncidence, subresource, sernum ); + } else { + kmailDeleteIncidence( subresource, sernum );// remove new from kmail + } + mSilent = silent; } void ResourceKolab::addIncidence( const char* mimetype, const TQString& data, const TQString& subResource, Q_UINT32 sernum ) @@ -457,15 +507,24 @@ bool ResourceKolab::sendKMailUpdate( KCal::IncidenceBase* incidencebase, const T TQStringList attURLs, attMimeTypes, attNames; TQValueList tmpFiles; for ( KCal::Attachment::List::ConstIterator it = atts.constBegin(); it != atts.constEnd(); ++it ) { - KTempFile* tempFile = new KTempFile; - TQCString decoded = KCodecs::base64Decode( TQCString( (*it)->data() ) ); - tempFile->file()->writeBlock( decoded.data(), decoded.length() ); - tempFile->close(); - KURL url; - url.setPath( tempFile->name() ); - attURLs.append( url.url() ); - attMimeTypes.append( (*it)->mimeType() ); - attNames.append( (*it)->label() ); + if ( (*it)->isUri() ) { + continue; + } + KTempFile *tempFile = new KTempFile; + if ( tempFile->status() == 0 ) { // open ok + const TQByteArray decoded = (*it)->decodedData() ; + + tempFile->file()->writeBlock( decoded.data(), decoded.count() ); + KURL url; + url.setPath( tempFile->name() ); + attURLs.append( url.url() ); + attMimeTypes.append( (*it)->mimeType() ); + attNames.append( (*it)->label() ); + tempFile->close(); + tmpFiles.append( tempFile ); + } else { + kdWarning(5006) << "Cannot open temporary file for attachment"; + } } TQStringList deletedAtts; if ( kmailListAttachments( deletedAtts, subresource, sernum ) ) { @@ -474,8 +533,9 @@ bool ResourceKolab::sendKMailUpdate( KCal::IncidenceBase* incidencebase, const T } } CustomHeaderMap customHeaders; - if ( incidence->schedulingID() != incidence->uid() ) + if ( incidence->schedulingID() != incidence->uid() ) { customHeaders.insert( "X-Kolab-SchedulingID", incidence->schedulingID() ); + } TQString subject = incidencebase->uid(); if ( !isXMLStorageFormat ) subject.prepend( "iCal " ); // conform to the old style @@ -499,34 +559,49 @@ bool ResourceKolab::addIncidence( KCal::Incidence* incidence, const TQString& _s Q_UINT32 sernum ) { Q_ASSERT( incidence ); - if ( !incidence ) return false; + if ( !incidence ) { + return false; + } + + kdDebug() << "Resourcekolab, adding incidence " + << incidence->summary() + << "; subresource = " << _subresource + << "; sernum = " << sernum + << "; mBatchAddingInProgress = " << mBatchAddingInProgress + << endl; + TQString uid = incidence->uid(); TQString subResource = _subresource; Kolab::ResourceMap *map = &mEventSubResources; // don't use a ref here! const TQString& type = incidence->type(); - if ( type == "Event" ) + if ( type == "Event" ) { map = &mEventSubResources; - else if ( type == "Todo" ) + } else if ( type == "Todo" ) { map = &mTodoSubResources; - else if ( type == "Journal" ) + } else if ( type == "Journal" ) { map = &mJournalSubResources; - else + } else { kdWarning() << "unknown type " << type << endl; + } if ( !mSilent ) { /* We got this one from the user, tell KMail. */ // Find out if this event was previously stored in KMail bool newIncidence = _subresource.isEmpty(); if ( newIncidence ) { + ResourceType type = Incidences; // Add a description of the incidence TQString text = ""; - if ( incidence->type() == "Event" ) + if ( incidence->type() == "Event" ) { + type = Events; text += i18n( "Choose the folder where you want to store this event" ); - else if ( incidence->type() == "Todo" ) + } else if ( incidence->type() == "Todo" ) { + type = Tasks; text += i18n( "Choose the folder where you want to store this task" ); - else + } else { text += i18n( "Choose the folder where you want to store this incidence" ); + } text += "
"; if ( !incidence->summary().isEmpty() ) text += i18n( "Summary: %1" ).arg( incidence->summary() ) + "
"; @@ -541,24 +616,51 @@ bool ResourceKolab::addIncidence( KCal::Incidence* incidence, const TQString& _s text += "
"; if ( incidence->type() == "Event" ) { Event* event = static_cast( incidence ); - if ( event->hasEndDate() ) - if ( !event->doesFloat() ) + if ( event->hasEndDate() ) { + if ( !event->doesFloat() ) { text += i18n( "End: %1, %2" ) .arg( event->dtEndDateStr(), event->dtEndTimeStr() ); - else + } else { text += i18n( "End: %1" ).arg( event->dtEndDateStr() ); + } + } text += "
"; } - subResource = findWritableResource( *map, text ); + + // Lets not warn the user 100 times that there's no writable resource + // and not ask 100 times which resource to use + if ( !mBatchAddingInProgress || !mLastUsedResources.contains( type ) ) { + subResource = findWritableResource( type, *map, text ); + mLastUsedResources[type] = subResource; + } else { + subResource = mLastUsedResources[type]; + } + + if ( subResource.isEmpty() ) { + switch( mErrorCode ) { + case NoWritableFound: + setException( new ErrorFormat( ErrorFormat::NoWritableFound ) ); + break; + case UserCancel: + setException( new ErrorFormat( ErrorFormat::UserCancel ) ); + break; + case NoError: + break; + } + } } - if ( subResource.isEmpty() ) + if ( subResource.isEmpty() ) { + endAddingIncidences(); // cleanup + kdDebug(5650) << "ResourceKolab: subResource is empty" << endl; return false; + } mNewIncidencesMap.insert( uid, subResource ); if ( !sendKMailUpdate( incidence, subResource, sernum ) ) { kdError(5650) << "Communication problem in ResourceKolab::addIncidence()\n"; + endAddingIncidences(); // cleanup return false; } else { // KMail is doing it's best to add the event now, put a sticker on it, @@ -568,13 +670,14 @@ bool ResourceKolab::addIncidence( KCal::Incidence* incidence, const TQString& _s /* 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 ) { + if ( newIncidence || sernum == 0 ) { mCalendar.addIncidence( incidence ); - incidence->registerObserver( this ); + incidence->registerObserver( this ); } } } else { /* KMail told us */ - bool ourOwnUpdate = mUidsPendingUpdate.contains( uid ); + const bool ourOwnUpdate = mUidsPendingUpdate.contains( uid ); + kdDebug( 5650 ) << "addIncidence: ourOwnUpdate " << ourOwnUpdate << endl; /* Check if we updated this one, which means kmail deleted and added it. * We know the new state, so lets just not do much at all. The old incidence * in the calendar remains valid, but the serial number changed, so we need to @@ -592,6 +695,7 @@ bool ResourceKolab::addIncidence( KCal::Incidence* incidence, const TQString& _s if ( mUidMap.contains( uid ) ) { if ( mUidMap[ uid ].resource() == subResource ) { if ( (*map)[ subResource ].writable() ) { + kdDebug( 5650 ) << "lets resolve the conflict " << endl; resolveConflict( incidence, subResource, sernum ); } else { kdWarning( 5650 ) << "Duplicate event in a read-only folder detected! " @@ -601,8 +705,13 @@ bool ResourceKolab::addIncidence( KCal::Incidence* incidence, const TQString& _s } else { // duplicate uid in a different folder, do the internal-uid tango incidence->setSchedulingID( uid ); - incidence->setUid(CalFormat::createUniqueId( ) ); + + incidence->setUid( CalFormat::createUniqueId( ) ); uid = incidence->uid(); + + /* Will be needed when kmail triggers a delete, so we don't delete the inocent + * incidence that's sharing the uid with this one */ + mOriginalUID2fakeUID[qMakePair( incidence->schedulingID(), subResource )] = uid; } } /* Add to the cache if the add didn't come from KOrganizer, in which case @@ -636,13 +745,18 @@ bool ResourceKolab::addIncidence( KCal::Incidence* incidence, const TQString& _s return true; } +bool ResourceKolab::addEvent( KCal::Event *event ) +{ + return addEvent( event, TQString() ); +} -bool ResourceKolab::addEvent( KCal::Event* event ) +bool ResourceKolab::addEvent( KCal::Event *event, const TQString &subResource ) { - if ( mUidMap.contains( event->uid() ) ) + if ( mUidMap.contains( event->uid() ) ) { return true; //noop - else - return addIncidence( event, TQString::null, 0 ); + } else { + return addIncidence( event, subResource, 0 ); + } } void ResourceKolab::addEvent( const TQString& xml, const TQString& subresource, @@ -650,14 +764,16 @@ void ResourceKolab::addEvent( const TQString& xml, const TQString& subresource, { KCal::Event* event = Kolab::Event::xmlToEvent( xml, mCalendar.timeZoneId(), this, subresource, sernum ); Q_ASSERT( event ); - if( event ) { + if ( event ) { addIncidence( event, subresource, sernum ); } } bool ResourceKolab::deleteIncidence( KCal::Incidence* incidence ) { - if ( incidence->isReadOnly() ) return false; + if ( incidence->isReadOnly() ) { + return false; + } const TQString uid = incidence->uid(); if( !mUidMap.contains( uid ) ) return false; // Odd @@ -709,12 +825,18 @@ KCal::Event::List ResourceKolab::rawEvents( const TQDate& start, return mCalendar.rawEvents( start, end, inclusive ); } -bool ResourceKolab::addTodo( KCal::Todo* todo ) +bool ResourceKolab::addTodo( KCal::Todo *todo ) { - if ( mUidMap.contains( todo->uid() ) ) + return addTodo( todo, TQString() ); +} + +bool ResourceKolab::addTodo( KCal::Todo *todo, const TQString &subResource ) +{ + if ( mUidMap.contains( todo->uid() ) ) { return true; //noop - else - return addIncidence( todo, TQString::null, 0 ); + } else { + return addIncidence( todo, subResource, 0 ); + } } void ResourceKolab::addTodo( const TQString& xml, const TQString& subresource, @@ -722,8 +844,9 @@ void ResourceKolab::addTodo( const TQString& xml, const TQString& subresource, { KCal::Todo* todo = Kolab::Task::xmlToTask( xml, mCalendar.timeZoneId(), this, subresource, sernum ); Q_ASSERT( todo ); - if( todo ) - addIncidence( todo, subresource, sernum ); + if ( todo ) { + addIncidence( todo, subresource, sernum ); + } } bool ResourceKolab::deleteTodo( KCal::Todo* todo ) @@ -746,12 +869,17 @@ KCal::Todo::List ResourceKolab::rawTodosForDate( const TQDate& date ) return mCalendar.rawTodosForDate( date ); } -bool ResourceKolab::addJournal( KCal::Journal* journal ) +bool ResourceKolab::addJournal( KCal::Journal *journal ) +{ + return addJournal( journal, TQString() ); +} + +bool ResourceKolab::addJournal( KCal::Journal *journal, const TQString &subResource ) { if ( mUidMap.contains( journal->uid() ) ) return true; //noop else - return addIncidence( journal, TQString::null, 0 ); + return addIncidence( journal, subResource, 0 ); } void ResourceKolab::addJournal( const TQString& xml, const TQString& subresource, @@ -839,27 +967,33 @@ bool ResourceKolab::fromKMailAddIncidence( const TQString& type, bool rc = true; TemporarySilencer t( this ); // RAII if ( type != kmailCalendarContentsType && type != kmailTodoContentsType - && type != kmailJournalContentsType ) + && type != kmailJournalContentsType ) { // Not ours return false; - if ( !subresourceActive( subResource ) ) return true; + } + + if ( !subresourceActive( subResource ) ) { + return true; + } if ( format == KMailICalIface::StorageXML ) { // If this data file is one of ours, load it here - if ( type == kmailCalendarContentsType ) + if ( type == kmailCalendarContentsType ) { addEvent( data, subResource, sernum ); - else if ( type == kmailTodoContentsType ) + } else if ( type == kmailTodoContentsType ) { addTodo( data, subResource, sernum ); - else if ( type == kmailJournalContentsType ) + } else if ( type == kmailJournalContentsType ) { addJournal( data, subResource, sernum ); - else + } else { rc = false; + } } else { Incidence *inc = mFormat.fromString( data ); - if ( !inc ) - rc = false; - else + if ( inc ) { addIncidence( inc, subResource, sernum ); + } else { + rc = false; + } } return rc; } @@ -881,13 +1015,25 @@ void ResourceKolab::fromKMailDelIncidence( const TQString& type, // It's good to know if was deleted, but we are waiting on a new one to // replace it, so let's just sit tight. } else { + TQString uidToUse; + + QPair p( uid, subResource ); + if ( mOriginalUID2fakeUID.contains( p ) ) { + // Incidence with the same uid in a different folder... + // use the UID that addIncidence(...) generated + uidToUse = mOriginalUID2fakeUID[p]; + } else { + uidToUse = uid; + } + // We didn't trigger this, so KMail did, remove the reference to the uid - KCal::Incidence* incidence = mCalendar.incidence( uid ); + KCal::Incidence* incidence = mCalendar.incidence( uidToUse ); if( incidence ) { incidence->unRegisterObserver( this ); mCalendar.deleteIncidence( incidence ); } - mUidMap.remove( uid ); + mUidMap.remove( uidToUse ); + mOriginalUID2fakeUID.remove( p ); mResourceChangedTimer.changeInterval( 100 ); } } @@ -1039,6 +1185,23 @@ void ResourceKolab::setSubresourceActive( const TQString &subresource, bool v ) } mResourceChangedTimer.changeInterval( 100 ); } + TQTimer::singleShot( 0, this, TQT_SLOT(writeConfig()) ); +} + +bool ResourceKolab::subresourceWritable( const TQString& subresource ) const +{ + // Workaround: The ResourceView in KOrganizer wants to know this + // before it opens the resource :-( Make sure we are open + const_cast( this )->doOpen(); + + if ( mEventSubResources.contains( subresource ) ) + return mEventSubResources[ subresource ].writable(); + if ( mTodoSubResources.contains( subresource ) ) + return mTodoSubResources[ subresource ].writable(); + if ( mJournalSubResources.contains( subresource ) ) + return mJournalSubResources[ subresource ].writable(); + + return false; //better a safe default } void ResourceKolab::slotEmitResourceChanged() @@ -1053,7 +1216,6 @@ KABC::Lock* ResourceKolab::lock() return new KABC::LockNull( true ); } - Kolab::ResourceMap* ResourceKolab::subResourceMap( const TQString& contentsType ) { if ( contentsType == kmailCalendarContentsType ) { @@ -1122,6 +1284,7 @@ bool ResourceKolab::unloadSubResource( const TQString& subResource ) const bool silent = mSilent; mSilent = true; Kolab::UidMap::Iterator mapIt = mUidMap.begin(); + TQPtrList incidences; while ( mapIt != mUidMap.end() ) { Kolab::UidMap::Iterator it = mapIt++; @@ -1130,11 +1293,18 @@ bool ResourceKolab::unloadSubResource( const TQString& subResource ) // FIXME incidence() is expensive KCal::Incidence* incidence = mCalendar.incidence( it.key() ); if( incidence ) { - incidence->unRegisterObserver( this ); - mCalendar.deleteIncidence( incidence ); + // register all observers first before actually deleting them + // in case of inter-incidence relations the other part will get + // the change notification otherwise + incidence->unRegisterObserver( this ); + incidences.append( incidence ); } mUidMap.remove( it ); } + TQPtrListIterator it( incidences ); + for ( ; it.current(); ++it ) { + mCalendar.deleteIncidence( it.current() ); + } mSilent = silent; return true; } @@ -1150,4 +1320,23 @@ TQString ResourceKolab::subresourceType( const TQString &resource ) return TQString(); } +void ResourceKolab::writeConfig() +{ + KConfig config( configFile() ); + writeResourceConfig( config, mEventSubResources ); + writeResourceConfig( config, mTodoSubResources ); + writeResourceConfig( config, mJournalSubResources ); +} + +void ResourceKolab::beginAddingIncidences() +{ + mBatchAddingInProgress = true; +} + +void ResourceKolab::endAddingIncidences() +{ + mBatchAddingInProgress = false; + mLastUsedResources.clear(); +} + #include "resourcekolab.moc" diff --git a/kresources/kolab/kcal/resourcekolab.h b/kresources/kolab/kcal/resourcekolab.h index e68c2c6bf..dda5ba32a 100644 --- a/kresources/kolab/kcal/resourcekolab.h +++ b/kresources/kolab/kcal/resourcekolab.h @@ -70,8 +70,9 @@ public: void doClose(); // The libkcal functions. See the resource for descriptions - bool addEvent( KCal::Event* anEvent ); - bool deleteEvent( KCal::Event* ); + KDE_DEPRECATED bool addEvent( KCal::Event *event ); + bool addEvent( KCal::Event *event, const TQString &subResource ); + bool deleteEvent( KCal::Event * ); KCal::Event* event( const TQString &UniqueStr ); KCal::Event::List rawEvents( EventSortField sortField = EventSortUnsorted, SortDirection sortDirection = SortDirectionAscending ); KCal::Event::List rawEventsForDate( @@ -82,15 +83,17 @@ public: KCal::Event::List rawEvents( const TQDate& start, const TQDate& end, bool inclusive = false ); - bool addTodo( KCal::Todo* todo ); - bool deleteTodo( KCal::Todo* ); - KCal::Todo* todo( const TQString& uid ); + KDE_DEPRECATED bool addTodo( KCal::Todo * todo ); + bool addTodo( KCal::Todo *todo, const TQString &subResource ); + bool deleteTodo( KCal::Todo * ); + KCal::Todo* todo( const TQString &uid ); KCal::Todo::List rawTodos( TodoSortField sortField = TodoSortUnsorted, SortDirection sortDirection = SortDirectionAscending ); KCal::Todo::List rawTodosForDate( const TQDate& date ); - bool addJournal( KCal::Journal* ); - bool deleteJournal( KCal::Journal* ); - KCal::Journal* journal( const TQString& uid ); + KDE_DEPRECATED bool addJournal( KCal::Journal * ); + bool addJournal( KCal::Journal *, const TQString &subResource ); + bool deleteJournal( KCal::Journal * ); + KCal::Journal* journal( const TQString &uid ); KCal::Journal::List rawJournals( JournalSortField sortField = JournalSortUnsorted, SortDirection sortDirection = SortDirectionAscending ); KCal::Journal::List rawJournalsForDate( const TQDate &date ); @@ -128,6 +131,9 @@ public: /** (De)activate the subresource */ virtual void setSubresourceActive( const TQString &, bool ); + /** Is this subresource writable? */ + bool subresourceWritable( const TQString& ) const; + /** What is the label for this subresource? */ virtual const TQString labelForSubresource( const TQString& resource ) const; @@ -140,10 +146,16 @@ public: KABC::Lock* lock(); + void beginAddingIncidences(); + + void endAddingIncidences(); + signals: void useGlobalMode(); protected slots: void slotEmitResourceChanged(); + void writeConfig(); + protected: /** * Return list of alarms which are relevant for the current user. These @@ -157,7 +169,11 @@ private: void addIncidence( const char* mimetype, const TQString& xml, const TQString& subResource, Q_UINT32 sernum ); - bool addIncidence( KCal::Incidence* i, const TQString& subresource, + + /** + Caller guarantees i is not null. + */ + bool addIncidence( KCal::Incidence *i, const TQString& subresource, Q_UINT32 sernum ); void addEvent( const TQString& xml, const TQString& subresource, @@ -215,6 +231,36 @@ private: */ TQMap mNewIncidencesMap; int mProgressDialogIncidenceLimit; + + /** + * If a user has a subresource for viewing another user's folder then it can happen + * that addIncidence(...) adds an incidence with an already existing UID. + * + * When this happens, addIncidence(...) sets a new random UID and stores the + * original UID using incidence->setSchedulingID(uid) because KCal doesn't + * allow two incidences to have the same UID. + * + * This map keeps track of the generated UIDs (which are local) so we can delete the + * right incidence inside fromKMailDelIncidence(...) whenever we sync. + * + * The key is originalUID,subResource and the value is the fake UID. + */ + TQMap< QPair, TQString > mOriginalUID2fakeUID; + + bool mBatchAddingInProgress; + TQMap mLastUsedResources; + + /** + Indexed by uid, it holds the last known revision of an incidence. + If we receive an update where the incidence still has the same + revision as the last known, we ignore it and don't send it to kmail, + because shortly after, IncidenceChanger will increment the revision + and that will trigger another update. + + If we didn't discard the first update, kmail would have been updated twice. + */ + TQMap mLastKnownRevisions; + }; struct TemporarySilencer { diff --git a/kresources/kolab/kcal/task.cpp b/kresources/kolab/kcal/task.cpp index 7bbdba978..36876b7d5 100644 --- a/kresources/kolab/kcal/task.cpp +++ b/kresources/kolab/kcal/task.cpp @@ -38,6 +38,41 @@ using namespace Kolab; +// Kolab Storage Specification: +// "The priority can be a number between 1 and 5, with 1 being the highest priority." +// iCalendar (RFC 2445): +// "The priority is specified as an integer in the range +// zero to nine. A value of zero specifies an +// undefined priority. A value of one is the +// highest priority. A value of nine is the lowest +// priority." + +static int kcalPriorityToKolab( const int kcalPriority ) +{ + if ( kcalPriority >= 0 && kcalPriority <= 9 ) { + // We'll map undefined (0) to 3 (default) + // 0 1 2 3 4 5 6 7 8 9 + static const int priorityMap[10] = { 3, 1, 1, 2, 2, 3, 3, 4, 4, 5 }; + return priorityMap[kcalPriority]; + } + else { + kdWarning() << "kcalPriorityToKolab(): Got invalid priority " << kcalPriority << endl; + return 3; + } +} + +static int kolabPrioritytoKCal( const int kolabPriority ) +{ + if ( kolabPriority >= 1 && kolabPriority <= 5 ) { + // 1 2 3 4 5 + static const int priorityMap[5] = { 1, 3, 5, 7, 9 }; + return priorityMap[kolabPriority - 1]; + } + else { + kdWarning() << "kolabPrioritytoKCal(): Got invalid priority " << kolabPriority << endl; + return 5; + } +} KCal::Todo* Task::xmlToTask( const TQString& xml, const TQString& tz, KCal::ResourceKolab *res, const TQString& subResource, Q_UINT32 sernum ) @@ -115,6 +150,26 @@ void Task::setDueDate( const TQDateTime& date ) { mDueDate = date; mHasDueDate = true; + mFloatingStatus = HasTime; +} + +void Task::setDueDate( const TQDate &date ) +{ + mDueDate = date; + mHasDueDate = true; + mFloatingStatus = AllDay; +} + + +void Task::setDueDate( const TQString &date ) +{ + if ( date.length() > 10 ) { + // This is a date + time + setDueDate( stringToDateTime( date ) ); + } else { + // This is only a date + setDueDate( stringToDate( date ) ); + } } TQDateTime Task::dueDate() const @@ -159,10 +214,18 @@ bool Task::loadAttribute( TQDomElement& element ) if ( tagName == "priority" ) { bool ok; - int priority = element.text().toInt( &ok ); - if ( !ok || priority < 0 || priority > 9 ) - priority = 5; - setPriority( priority ); + mKolabPriorityFromDom = element.text().toInt( &ok ); + if ( !ok || mKolabPriorityFromDom < 1 || mKolabPriorityFromDom > 5 ) { + kdWarning() << "loadAttribute(): Invalid \"priority\" value: " << element.text() << endl; + mKolabPriorityFromDom = -1; + } + } else if ( tagName == "x-kcal-priority" ) { + bool ok; + mKCalPriorityFromDom = element.text().toInt( &ok ); + if ( !ok || mKCalPriorityFromDom < 0 || mKCalPriorityFromDom > 9 ) { + kdWarning() << "loadAttribute(): Invalid \"x-kcal-priority\" value: " << element.text() << endl; + mKCalPriorityFromDom = -1; + } } else if ( tagName == "completed" ) { bool ok; int percent = element.text().toInt( &ok ); @@ -182,13 +245,13 @@ bool Task::loadAttribute( TQDomElement& element ) else // Default setStatus( KCal::Incidence::StatusNone ); - } else if ( tagName == "due-date" ) - setDueDate( stringToDateTime( element.text() ) ); - else if ( tagName == "parent" ) + } else if ( tagName == "due-date" ) { + setDueDate( element.text() ); + } else if ( tagName == "parent" ) { setParent( element.text() ); - else if ( tagName == "x-completed-date" ) + } else if ( tagName == "x-completed-date" ) { setCompletedDate( stringToDateTime( element.text() ) ); - else if ( tagName == "start-date" ) { + } else if ( tagName == "start-date" ) { setHasStartDate( true ); setStartDate( element.text() ); } else @@ -203,7 +266,11 @@ bool Task::saveAttributes( TQDomElement& element ) const // Save the base class elements Incidence::saveAttributes( element ); - writeString( element, "priority", TQString::number( priority() ) ); + // We need to save x-kcal-priority as well, since the Kolab priority can only save values from + // 1 to 5, but we have values from 0 to 9, and do not want to loose them + writeString( element, "priority", TQString::number( kcalPriorityToKolab( priority() ) ) ); + writeString( element, "x-kcal-priority", TQString::number( priority() ) ); + writeString( element, "completed", TQString::number( percentCompleted() ) ); switch( status() ) { @@ -232,14 +299,21 @@ bool Task::saveAttributes( TQDomElement& element ) const break; } - if ( hasDueDate() ) - writeString( element, "due-date", dateTimeToString( dueDate() ) ); + if ( hasDueDate() ) { + if ( mFloatingStatus == HasTime ) { + writeString( element, "due-date", dateTimeToString( dueDate() ) ); + } else { + writeString( element, "due-date", dateToString( dueDate().date() ) ); + } + } - if ( !parent().isNull() ) + if ( !parent().isNull() ) { writeString( element, "parent", parent() ); + } - if ( hasCompletedDate() && percentCompleted() == 100) + if ( hasCompletedDate() && percentCompleted() == 100 ) { writeString( element, "x-completed-date", dateTimeToString( completedDate() ) ); + } return true; } @@ -247,6 +321,9 @@ bool Task::saveAttributes( TQDomElement& element ) const bool Task::loadXML( const TQDomDocument& document ) { + mKolabPriorityFromDom = -1; + mKCalPriorityFromDom = -1; + TQDomElement top = document.documentElement(); if ( top.tagName() != "task" ) { @@ -269,6 +346,7 @@ bool Task::loadXML( const TQDomDocument& document ) } loadAttachments(); + decideAndSetPriority(); return true; } @@ -278,7 +356,7 @@ TQString Task::saveXML() const TQDomElement element = document.createElement( "task" ); element.setAttribute( "version", "1.0" ); saveAttributes( element ); - if ( !hasStartDate() ) { + if ( !hasStartDate() && startDate().isValid() ) { // events and journals always have a start date, but tasks don't. // Remove the entry done by the inherited save above, because we // don't have one. @@ -299,21 +377,68 @@ void Task::setFields( const KCal::Todo* task ) setStatus( task->status() ); setHasStartDate( task->hasStartDate() ); - if ( task->hasDueDate() ) + if ( task->hasDueDate() ) { setDueDate( localToUTC( task->dtDue() ) ); - else + if ( task->doesFloat() ) { + // This is a floating task. Don't timezone move this one + mFloatingStatus = AllDay; + setDueDate( task->dtDue().date() ); + } else { + mFloatingStatus = HasTime; + setDueDate( localToUTC( task->dtDue() ) ); + } + } else { mHasDueDate = false; - if ( task->relatedTo() ) + } + + if ( task->relatedTo() ) { setParent( task->relatedTo()->uid() ); - else if ( !task->relatedToUid().isEmpty() ) - setParent( task->relatedToUid() ); - else + } else if ( !task->relatedToUid().isEmpty() ) { + setParent( task->relatedToUid( ) ); + } else { setParent( TQString::null ); + } - if ( task->hasCompletedDate() && task->percentComplete() == 100 ) + if ( task->hasCompletedDate() && task->percentComplete() == 100 ) { setCompletedDate( localToUTC( task->completed() ) ); - else + } else { mHasCompletedDate = false; + } +} + +void Task::decideAndSetPriority() +{ + // If we have both Kolab and KCal values in the XML, we prefer the KCal value, but only if the + // values are still in sync + if ( mKolabPriorityFromDom != -1 && mKCalPriorityFromDom != -1 ) { + const bool inSync = ( kcalPriorityToKolab( mKCalPriorityFromDom ) == mKolabPriorityFromDom ); + if ( inSync ) { + setPriority( mKCalPriorityFromDom ); + } + else { + // Out of sync, some other client changed the Kolab priority, so we have to ignore our + // KCal priority + setPriority( kolabPrioritytoKCal( mKolabPriorityFromDom ) ); + } + } + + // Only KCal priority set, use that. + else if ( mKolabPriorityFromDom == -1 && mKCalPriorityFromDom != -1 ) { + kdWarning() << "decideAndSetPriority(): No Kolab priority found, only the KCal priority!" << endl; + setPriority( mKCalPriorityFromDom ); + } + + // Only Kolab priority set, use that + else if ( mKolabPriorityFromDom != -1 && mKCalPriorityFromDom == -1 ) { + setPriority( kolabPrioritytoKCal( mKolabPriorityFromDom ) ); + } + + // No priority set, use the default + else { + // According the RFC 2445, we should use 0 here, for undefined priority, but AFAIK KOrganizer + // doesn't support that, so we'll use 5. + setPriority( 5 ); + } } void Task::saveTo( KCal::Todo* task ) diff --git a/kresources/kolab/kcal/task.h b/kresources/kolab/kcal/task.h index 5dfb55854..f7e7c6d51 100644 --- a/kresources/kolab/kcal/task.h +++ b/kresources/kolab/kcal/task.h @@ -86,7 +86,9 @@ public: virtual void setHasStartDate( bool ); virtual bool hasStartDate() const; - virtual void setDueDate( const TQDateTime& date ); + virtual void setDueDate( const TQDateTime &date ); + virtual void setDueDate( const TQString &date ); + virtual void setDueDate( const TQDate &date ); virtual TQDateTime dueDate() const; virtual bool hasDueDate() const; @@ -110,7 +112,19 @@ protected: // Read all known fields from this ical todo void setFields( const KCal::Todo* ); + // This sets the priority of this task by looking at mKolabPriorityFromDom and + // mKCalPriorityFromDom. + void decideAndSetPriority(); + + // This is the KCal priority, not the Kolab priority. + // See kcalPriorityToKolab() and kolabPrioritytoKCal(). int mPriority; + + // Those priority values are the raw values read by loadAttribute(). + // They will be converted later in decideAndSetPriority(). + int mKolabPriorityFromDom; + int mKCalPriorityFromDom; + int mPercentCompleted; KCal::Incidence::Status mStatus; TQString mParent; diff --git a/kresources/kolab/knotes/kolabresource.desktop b/kresources/kolab/knotes/kolabresource.desktop index d74e3f59b..317032d17 100644 --- a/kresources/kolab/knotes/kolabresource.desktop +++ b/kresources/kolab/knotes/kolabresource.desktop @@ -21,7 +21,6 @@ Name[hu]=IMAP-kiszolgáló a KMailen keresztül Name[is]=IMAP þjónn gegnum KMail Name[it]=Server IMAP via KMail Name[ja]=KMail 経由 IMAP サーバ -Name[ka]= IMAP-ს სერვერთან დაშვება KMail-ის საშუალებით Name[kk]=KMail арқылы IMAP сервері Name[km]=ម៉ាស៊ីន​បម្រើ IMAP តាម​រយៈ KMail Name[lt]=IMAP serveris per KMail diff --git a/kresources/kolab/knotes/note.cpp b/kresources/kolab/knotes/note.cpp index 66556aaf8..168dae562 100644 --- a/kresources/kolab/knotes/note.cpp +++ b/kresources/kolab/knotes/note.cpp @@ -108,7 +108,6 @@ bool Note::richText() const bool Note::loadAttribute( TQDomElement& element ) { TQString tagName = element.tagName(); - if ( tagName == "summary" ) setSummary( element.text() ); else if ( tagName == "foreground-color" ) @@ -136,8 +135,10 @@ bool Note::saveAttributes( TQDomElement& element ) const #endif writeString( element, "summary", summary() ); - writeString( element, "foreground-color", colorToString( foregroundColor() ) ); - writeString( element, "background-color", colorToString( backgroundColor() ) ); + if ( foregroundColor().isValid() ) + writeString( element, "foreground-color", colorToString( foregroundColor() ) ); + if ( backgroundColor().isValid() ) + writeString( element, "background-color", colorToString( backgroundColor() ) ); writeString( element, "knotes-richtext", mRichText ? "true" : "false" ); return true; @@ -183,11 +184,27 @@ void Note::setFields( const KCal::Journal* journal ) { KolabBase::setFields( journal ); - // TODO: background and foreground setSummary( journal->summary() ); - setBackgroundColor( journal->customProperty( "KNotes", "BgColor" ) ); - setForegroundColor( journal->customProperty( "KNotes", "FgColor" ) ); - setRichText( journal->customProperty( "KNotes", "RichText" ) == "true" ); + + TQString property = journal->customProperty( "KNotes", "BgColor" ); + if ( !property.isNull() ) { + setBackgroundColor( property ); + } else { + setBackgroundColor( "yellow" ); + } + property = journal->customProperty( "KNotes", "FgColor" ); + if ( !property.isNull() ) { + setForegroundColor( property ); + } else { + setForegroundColor( "black" ); + } + + property = journal->customProperty( "KNotes", "RichText" ); + if ( !property.isNull() ) { + setRichText( property == "true" ? true : false ); + } else { + setRichText( "false" ); + } } void Note::saveTo( KCal::Journal* journal ) @@ -196,10 +213,12 @@ void Note::saveTo( KCal::Journal* journal ) // TODO: background and foreground journal->setSummary( summary() ); - journal->setCustomProperty( "KNotes", "FgColor", - colorToString( foregroundColor() ) ); - journal->setCustomProperty( "KNotes", "BgColor", - colorToString( backgroundColor() ) ); + if ( foregroundColor().isValid() ) + journal->setCustomProperty( "KNotes", "FgColor", + colorToString( foregroundColor() ) ); + if ( backgroundColor().isValid() ) + journal->setCustomProperty( "KNotes", "BgColor", + colorToString( backgroundColor() ) ); journal->setCustomProperty( "KNotes", "RichText", richText() ? "true" : "false" ); } diff --git a/kresources/kolab/knotes/resourcekolab.cpp b/kresources/kolab/knotes/resourcekolab.cpp index 1d633b62a..d917d0ac2 100644 --- a/kresources/kolab/knotes/resourcekolab.cpp +++ b/kresources/kolab/knotes/resourcekolab.cpp @@ -41,6 +41,7 @@ #include #include +#include using namespace Kolab; @@ -53,6 +54,9 @@ ResourceKolab::ResourceKolab( const KConfig *config ) : ResourceNotes( config ), ResourceKolabBase( "ResourceKolab-KNotes" ), mCalendar( TQString::fromLatin1("UTC") ) { + if ( !config ) { + setResourceName( i18n( "Kolab Server" ) ); + } setType( "imap" ); } @@ -73,7 +77,7 @@ bool ResourceKolab::doOpen() // Make the resource map from the folder list TQValueList::ConstIterator it; mSubResources.clear(); - for ( it = subResources.begin(); it != subResources.end(); ++it ) { + for ( it = subResources.constBegin(); it != subResources.constEnd(); ++it ) { const TQString subResource = (*it).location; const bool active = config.readBoolEntry( subResource, true ); mSubResources[ subResource ] = Kolab::SubResource( active, (*it).writable, (*it).label ); @@ -87,7 +91,7 @@ void ResourceKolab::doClose() KConfig config( configFile() ); config.setGroup( configGroupName ); Kolab::ResourceMap::ConstIterator it; - for ( it = mSubResources.begin(); it != mSubResources.end(); ++it ) + for ( it = mSubResources.constBegin(); it != mSubResources.constEnd(); ++it ) config.writeEntry( it.key(), it.data().active() ); } @@ -113,8 +117,8 @@ bool ResourceKolab::loadSubResource( const TQString& subResource, // Populate with the new entries const bool silent = mSilent; mSilent = true; - TQMap::Iterator it; - for ( it = lst.begin(); it != lst.end(); ++it ) { + TQMap::ConstIterator it; + for ( it = lst.constBegin(); it != lst.constEnd(); ++it ) { KCal::Journal* journal = addNote( it.data(), subResource, it.key(), mimetype ); if ( !journal ) kdDebug(5500) << "loading note " << it.key() << " failed" << endl; @@ -134,7 +138,7 @@ bool ResourceKolab::load() bool rc = true; Kolab::ResourceMap::ConstIterator itR; - for ( itR = mSubResources.begin(); itR != mSubResources.end(); ++itR ) { + for ( itR = mSubResources.constBegin(); itR != mSubResources.constEnd(); ++itR ) { if ( !itR.data().active() ) // This subResource is disabled continue; @@ -162,25 +166,35 @@ bool ResourceKolab::addNote( KCal::Journal* journal ) KCal::Journal* ResourceKolab::addNote( const TQString& data, const TQString& subresource, Q_UINT32 sernum, const TQString &mimetype ) { - KCal::Journal* journal = 0; - // FIXME: This does not take into account the time zone! + KCal::Journal *journal = 0; + + // FIXME: This does not take into account the time zone! KCal::ICalFormat formatter; - if ( mimetype == attachmentMimeType ) + if ( mimetype == attachmentMimeType ) { journal = Note::xmlToJournal( data ); - else + } else { journal = static_cast( 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 addedOk = journal && + !mUidMap.contains( journal->uid() ) && + addNote( journal, subresource, sernum ); + + // for debugging + if ( journal && mUidMap.contains( journal->uid() ) ) { + kdDebug(5500) << "mUidMap already contains " << journal->uid() << endl; + } + + if ( !addedOk ) { + delete journal; + journal = 0; + } + + return journal; } -bool ResourceKolab::addNote( KCal::Journal* journal, - const TQString& subresource, Q_UINT32 sernum ) +bool ResourceKolab::addNote( KCal::Journal *journal, const TQString &subresource, Q_UINT32 sernum ) { kdDebug(5500) << "ResourceKolab::addNote( KCal::Journal*, '" << subresource << "', " << sernum << " )\n"; @@ -188,12 +202,15 @@ bool ResourceKolab::addNote( KCal::Journal* journal, // Find out if this note was previously stored in KMail bool newNote = subresource.isEmpty(); - mCalendar.addJournal( journal ); + if ( !mCalendar.addJournal( journal ) ) { + return false; + } - TQString resource = - newNote ? findWritableResource( mSubResources ) : subresource; - if ( resource.isEmpty() ) // canceled + TQString resource = newNote ? findWritableResource( Kolab::Notes, mSubResources ) : subresource; + if ( resource.isEmpty() ) { + // canceled return false; + } if ( !mSilent ) { TQString xml = Note::journalToXML( journal ); @@ -209,7 +226,6 @@ bool ResourceKolab::addNote( KCal::Journal* journal, mUidMap[ journal->uid() ] = StorageReference( resource, sernum ); return true; } - return false; } @@ -225,9 +241,7 @@ bool ResourceKolab::deleteNote( KCal::Journal* journal ) mUidMap[ uid ].serialNumber() ); } mUidMap.remove( uid ); - manager()->deleteNote( journal ); - mCalendar.deleteJournal( journal ); - return true; + return mCalendar.deleteJournal( journal ); } KCal::Alarm::List ResourceKolab::alarms( const TQDateTime& from, const TQDateTime& to ) @@ -239,7 +253,7 @@ KCal::Alarm::List ResourceKolab::alarms( const TQDateTime& from, const TQDateTim { TQDateTime preTime = from.addSecs( -1 ); KCal::Alarm::List::ConstIterator it; - for( it = (*note)->alarms().begin(); it != (*note)->alarms().end(); ++it ) + for( it = (*note)->alarms().constBegin(); it != (*note)->alarms().constEnd(); ++it ) { if ( (*it)->enabled() ) { @@ -261,7 +275,7 @@ void ResourceKolab::incidenceUpdated( KCal::IncidenceBase* i ) subResource = mUidMap[ i->uid() ].resource(); sernum = mUidMap[ i->uid() ].serialNumber(); } else { // can this happen? - subResource = findWritableResource( mSubResources ); + subResource = findWritableResource( Kolab::Notes, mSubResources ); if ( subResource.isEmpty() ) // canceled return; sernum = 0; @@ -313,8 +327,11 @@ void ResourceKolab::fromKMailDelIncidence( const TQString& type, const bool silent = mSilent; mSilent = true; KCal::Journal* j = mCalendar.journal( uid ); - if( j ) - deleteNote( j ); + if ( j ) { + if ( deleteNote( j ) ) { + manager()->deleteNote( j ); + } + } mSilent = silent; } @@ -370,7 +387,7 @@ void ResourceKolab::fromKMailDelSubresource( const TQString& type, // Make a list of all uids to remove Kolab::UidMap::ConstIterator mapIt; TQStringList uids; - for ( mapIt = mUidMap.begin(); mapIt != mUidMap.end(); ++mapIt ) + for ( mapIt = mUidMap.constBegin(); mapIt != mUidMap.constEnd(); ++mapIt ) if ( mapIt.data().resource() == subResource ) // We have a match uids << mapIt.key(); @@ -380,7 +397,7 @@ void ResourceKolab::fromKMailDelSubresource( const TQString& type, const bool silent = mSilent; mSilent = true; TQStringList::ConstIterator it; - for ( it = uids.begin(); it != uids.end(); ++it ) { + for ( it = uids.constBegin(); it != uids.constEnd(); ++it ) { KCal::Journal* j = mCalendar.journal( *it ); if( j ) deleteNote( j ); @@ -405,7 +422,7 @@ void ResourceKolab::fromKMailAsyncLoadResult( const TQMap& m mimetype = attachmentMimeType; else mimetype = inlineMimeType; - for( TQMap::ConstIterator it = map.begin(); it != map.end(); ++it ) { + for( TQMap::ConstIterator it = map.constBegin(); it != map.constEnd(); ++it ) { KCal::Journal* journal = addNote( it.data(), folder, it.key(), mimetype ); if ( !journal ) kdDebug(5500) << "loading note " << it.key() << " failed" << endl; @@ -433,5 +450,14 @@ bool ResourceKolab::subresourceActive( const TQString& res ) const return true; } +bool ResourceKolab::subresourceWritable( const TQString& res ) const +{ + if ( mSubResources.contains( res ) ) { + return mSubResources[ res ].writable(); + } + + // Safe default bet: + return false; +} #include "resourcekolab.moc" diff --git a/kresources/kolab/knotes/resourcekolab.h b/kresources/kolab/knotes/resourcekolab.h index a738a30a5..6ff994ccf 100644 --- a/kresources/kolab/knotes/resourcekolab.h +++ b/kresources/kolab/knotes/resourcekolab.h @@ -102,6 +102,9 @@ public: /** Is this subresource active? */ bool subresourceActive( const TQString& ) const; + /** Is this subresource writable? */ + bool subresourceWritable( const TQString& ) const; + signals: void signalSubresourceAdded( Resource*, const TQString&, const TQString& ); void signalSubresourceRemoved( Resource*, const TQString&, const TQString& ); diff --git a/kresources/kolab/shared/kmailconnection.cpp b/kresources/kolab/shared/kmailconnection.cpp index 9135e16db..66674abfa 100644 --- a/kresources/kolab/shared/kmailconnection.cpp +++ b/kresources/kolab/shared/kmailconnection.cpp @@ -73,16 +73,38 @@ static const TQCString dcopObjectId = "KMailICalIface"; bool KMailConnection::connectToKMail() { if ( !mKMailIcalIfaceStub ) { - TQString error; TQCString dcopService; - int result = KDCOPServiceStarter::self()-> - findServiceFor( "DCOP/ResourceBackend/IMAP", TQString::null, - TQString::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; + + // if we are kmail (and probably kontact as well) ourselves, don't try to start us again + // this prevents a DCOP deadlock when launching the kmail while kontact is the IMAP backend + // provider (and probably vice versa) + if ( kapp->instanceName() == "kmail" ) { + // someone, probably ourselves, already offers the interface, if not stop here + const QCStringList services = kapp->dcopClient()->registeredApplications(); + for ( uint i = 0; i < services.count(); ++i ) { + if ( services[i].find( "anonymous" ) == 0 ) // querying anonymous-XXXXX deadlocks as well, what are those anyway? + continue; + const QCStringList objs = kapp->dcopClient()->remoteObjects( services[i] ); + if ( objs.contains( dcopObjectId ) ) { + dcopService = services[i]; + break; + } + } + if ( dcopService.isEmpty() ) { + kdError(5650) << k_funcinfo << "Not connecting to KMail to prevent DCOP deadlock" << endl; + return false; + } + } else { + TQString error; + int result = KDCOPServiceStarter::self()-> + findServiceFor( "DCOP/ResourceBackend/IMAP", TQString::null, + TQString::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(), diff --git a/kresources/kolab/shared/kolabbase.cpp b/kresources/kolab/shared/kolabbase.cpp index 9a4a17f7c..b7f502576 100644 --- a/kresources/kolab/shared/kolabbase.cpp +++ b/kresources/kolab/shared/kolabbase.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -257,8 +258,16 @@ bool KolabBase::loadEmailAttribute( TQDomElement& element, Email& email ) TQDomElement e = n.toElement(); const TQString tagName = e.tagName(); - if ( tagName == "display-name" ) - email.displayName = e.text(); + if ( tagName == "display-name" ) { + // Quote the text in case it contains commas or other quotable chars. + TQString tusername = KPIM::quoteNameIfNecessary( e.text() ); + + TQString tname, temail; + // ignore the return value because it will always be false since + // tusername does not contain "@domain". + KPIM::getNameAndMail( tusername, tname, temail ); + email.displayName = tname; + } else if ( tagName == "smtp-address" ) email.smtpAddress = e.text(); else @@ -411,7 +420,11 @@ TQString KolabBase::dateToString( const TQDate& date ) TQDateTime KolabBase::stringToDateTime( const TQString& _date ) { TQString date( _date ); - if ( date.endsWith( "Z" ) ) + //Deal with data from some clients that always append a Z to dates. + if ( date.endsWith( "ZZ" ) ) + date.truncate( date.length() - 2 ); + //In TQt3, TQt::ISODate cannot handle a trailing Z for UTC, so remove if found. + else if ( date.endsWith( "Z" ) ) date.truncate( date.length() - 1 ); return TQDateTime::fromString( date, Qt::ISODate ); } diff --git a/kresources/kolab/shared/resourcekolabbase.cpp b/kresources/kolab/shared/resourcekolabbase.cpp index 291910fb9..2db2117db 100644 --- a/kresources/kolab/shared/resourcekolabbase.cpp +++ b/kresources/kolab/shared/resourcekolabbase.cpp @@ -210,9 +210,12 @@ bool ResourceKolabBase::kmailRemoveSubresource( const TQString& resource ) return mConnection->kmailRemoveSubresource( resource ); } -TQString ResourceKolabBase::findWritableResource( const ResourceMap& resources, +TQString ResourceKolabBase::findWritableResource( const ResourceType &type, + const ResourceMap& resources, const TQString& text ) { + mErrorCode = NoError; + // I have to use the label (shown in the dialog) as key here. But given how the // label is made up, it should be unique. If it's not, well the dialog would suck anyway... TQMap possible; @@ -227,7 +230,33 @@ TQString ResourceKolabBase::findWritableResource( const ResourceMap& resources, 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." ) ); + + TQString errorText; + switch( type ) { + case Events: + errorText = i18n( "You have no writable event folders so saving will not be possible.\n" + "Please create or activate at least one writable event folder and try again." ); + break; + case Tasks: + errorText = i18n( "You have no writable task folders so saving will not be possible.\n" + "Please create or activate at least one writable task folder and try again." ); + break; + case Incidences: + errorText = i18n( "You have no writable calendar folder so saving will not be possible.\n" + "Please create or activate at least one writable calendar folder and try again." ); + break; + case Notes: + errorText = i18n( "You have no writable notes folders so saving will not be possible.\n" + "Please create or activate at least one writable notes folder and try again." ); + break; + case Contacts: + errorText = i18n( "You have no writable addressbook folder so saving will not be possible.\n" + "Please create or activate at least one writable addressbook folder and try again." ); + break; + } + + KMessageBox::error( 0, errorText ); + mErrorCode = NoWritableFound; return TQString::null; } if ( possible.count() == 1 ) @@ -242,8 +271,11 @@ TQString ResourceKolabBase::findWritableResource( const ResourceMap& resources, // Several found, ask the user TQString chosenLabel = KPIM::FolderSelectDialog::getItem( i18n( "Select Resource Folder" ), t, possible.keys() ); - if ( chosenLabel.isEmpty() ) // cancelled + if ( chosenLabel.isEmpty() ) { + // cancelled + mErrorCode = UserCancel; return TQString::null; + } return possible[chosenLabel]; } diff --git a/kresources/kolab/shared/resourcekolabbase.h b/kresources/kolab/shared/resourcekolabbase.h index b2ce0501f..1bd8b9515 100644 --- a/kresources/kolab/shared/resourcekolabbase.h +++ b/kresources/kolab/shared/resourcekolabbase.h @@ -46,6 +46,8 @@ class KURL; namespace Kolab { +enum ResourceType { Tasks, Events, Incidences, Contacts, Notes }; + class KMailConnection; /** @@ -168,9 +170,17 @@ protected: TQString configFile( const TQString& type ) const; /// If only one of these is writable, return that. Otherwise return null. - TQString findWritableResource( const ResourceMap& resources, + TQString findWritableResource( const ResourceType &type, + const ResourceMap& resources, const TQString& text = TQString::null ); + enum ErrorCode { + NoError, + NoWritableFound, /**< No writable resource is available */ + UserCancel /**< User canceled the operation */ + }; + ErrorCode mErrorCode; + bool mSilent; /** diff --git a/kresources/lib/addressbookadaptor.cpp b/kresources/lib/addressbookadaptor.cpp index 900772e56..80da39421 100644 --- a/kresources/lib/addressbookadaptor.cpp +++ b/kresources/lib/addressbookadaptor.cpp @@ -32,9 +32,9 @@ using namespace KABC; -AddressBookUploadItem::AddressBookUploadItem( - KPIM::GroupwareDataAdaptor *adaptor, - KABC::Addressee addr, +AddressBookUploadItem::AddressBookUploadItem( + KPIM::GroupwareDataAdaptor *adaptor, + KABC::Addressee addr, GroupwareUploadItem::UploadType type ) : GroupwareUploadItem( type ) { @@ -42,7 +42,11 @@ AddressBookUploadItem::AddressBookUploadItem( setUrl( addr.custom( adaptor->identifier(), "storagelocation" ) ); setUid( addr.uid() ); KABC::VCardConverter vcard; +#if defined(KABC_VCARD_ENCODING_FIX) + setData( vcard.createVCardRaw( addr ) ); +#else setData( vcard.createVCard( addr ) ); +#endif } @@ -105,12 +109,12 @@ void AddressBookAdaptor::addressbookItemDownloaded( KABC::Addressee addr, deleteItem( newLocalId ); TQString localId = idMapper()->localId( remoteId.path() ); if ( !localId.isEmpty() ) deleteItem( localId ); - + // add the new item addr.insertCustom( identifier(), "storagelocation", storagelocation ); if ( !localId.isEmpty() ) addr.setUid( localId ); addItem( addr ); - + // update the fingerprint and the ids in the idMapper idMapper()->removeRemoteId( localId ); idMapper()->removeRemoteId( newLocalId ); @@ -123,7 +127,7 @@ void AddressBookAdaptor::clearChange( const TQString &uid ) mResource->clearChange( uid ); } -KPIM::GroupwareUploadItem *AddressBookAdaptor::newUploadItem( +KPIM::GroupwareUploadItem *AddressBookAdaptor::newUploadItem( KABC::Addressee addr, KPIM::GroupwareUploadItem::UploadType type ) { return new AddressBookUploadItem( this, addr, type ); diff --git a/kresources/lib/folderselectdialog.cpp b/kresources/lib/folderselectdialog.cpp index 0942f8223..c4d343598 100644 --- a/kresources/lib/folderselectdialog.cpp +++ b/kresources/lib/folderselectdialog.cpp @@ -39,7 +39,7 @@ using namespace KPIM; FolderSelectDialog::FolderSelectDialog( const TQString& caption, const TQString& label, const TQStringList& list ) - : KDialogBase(0, 0, true, caption, Ok, Ok, true) + : KDialogBase(0, 0, true, caption, Ok|Cancel, Ok, true) { TQFrame* frame = makeMainWidget(); TQVBoxLayout* layout = new TQVBoxLayout( frame, 0, spacingHint() ); @@ -81,3 +81,8 @@ void FolderSelectDialog::closeEvent(TQCloseEvent *event) { event->ignore(); } + +void FolderSelectDialog::reject() +{ +} + diff --git a/kresources/lib/folderselectdialog.h b/kresources/lib/folderselectdialog.h index a7879f9a0..e5901239a 100644 --- a/kresources/lib/folderselectdialog.h +++ b/kresources/lib/folderselectdialog.h @@ -49,6 +49,7 @@ public: protected: virtual void closeEvent(TQCloseEvent *event); + void reject(); private: KListBox* mListBox; }; diff --git a/kresources/lib/kcal_resourcegroupwarebase.cpp b/kresources/lib/kcal_resourcegroupwarebase.cpp index 7499b224d..823943c2b 100644 --- a/kresources/lib/kcal_resourcegroupwarebase.cpp +++ b/kresources/lib/kcal_resourcegroupwarebase.cpp @@ -39,13 +39,13 @@ using namespace KCal; ResourceGroupwareBase::ResourceGroupwareBase() - : ResourceCached( 0 ), mPrefs(0), mFolderLister(0), + : ResourceCached( 0 ), mPrefs(0), mFolderLister(0), mLock( true ), mAdaptor(0), mDownloadJob(0), mUploadJob(0) { } ResourceGroupwareBase::ResourceGroupwareBase( const KConfig *config ) - : ResourceCached( config ), mPrefs(0), mFolderLister(0), + : ResourceCached( config ), mPrefs(0), mFolderLister(0), mLock( true ), mAdaptor(0), mDownloadJob(0), mUploadJob(0) { if ( config ) readConfig( config ); @@ -69,7 +69,7 @@ bool ResourceGroupwareBase::addEvent( Event *event ) { if ( adaptor() && ( adaptor()->supports( KPIM::FolderLister::Event ) || adaptor()->supports( KPIM::FolderLister::All ) ) ) { - return ResourceCached::addEvent( event ); + return ResourceCached::addEvent( event, TQString() ); } else return false; } @@ -77,7 +77,7 @@ bool ResourceGroupwareBase::addTodo( Todo *todo ) { if ( adaptor() && ( adaptor()->supports( KPIM::FolderLister::Todo ) || adaptor()->supports( KPIM::FolderLister::All ) ) ) { - return ResourceCached::addTodo( todo ); + return ResourceCached::addTodo( todo, TQString() ); } else return false; } @@ -85,30 +85,30 @@ bool ResourceGroupwareBase::addJournal( Journal *journal ) { if ( adaptor() && ( adaptor()->supports( KPIM::FolderLister::Journal ) || adaptor()->supports( KPIM::FolderLister::All ) ) ) { - return ResourceCached::addJournal( journal ); + return ResourceCached::addJournal( journal, TQString() ); } else return false; } -KPIM::GroupwareDownloadJob *ResourceGroupwareBase::createDownloadJob( +KPIM::GroupwareDownloadJob *ResourceGroupwareBase::createDownloadJob( CalendarAdaptor *adaptor ) { return new KPIM::GroupwareDownloadJob( adaptor ); } -KPIM::GroupwareUploadJob *ResourceGroupwareBase::createUploadJob( +KPIM::GroupwareUploadJob *ResourceGroupwareBase::createUploadJob( CalendarAdaptor *adaptor ) { return new KPIM::GroupwareUploadJob( adaptor ); } -void ResourceGroupwareBase::setPrefs( KPIM::GroupwarePrefsBase *newprefs ) +void ResourceGroupwareBase::setPrefs( KPIM::GroupwarePrefsBase *newprefs ) { if ( !newprefs ) return; if ( mPrefs ) delete mPrefs; mPrefs = newprefs; mPrefs->addGroupPrefix( identifier() ); - + mPrefs->readConfig(); if ( mFolderLister ) mFolderLister->readConfig( mPrefs ); } @@ -236,7 +236,7 @@ void ResourceGroupwareBase::doClose() ResourceCached::doClose(); if ( mDownloadJob ) mDownloadJob->kill(); - if ( adaptor() && + if ( adaptor() && adaptor()->flags() & KPIM::GroupwareDataAdaptor::GWResNeedsLogoff ) { KIO::Job *logoffJob = adaptor()->createLogoffJob( prefs()->url(), prefs()->user(), prefs()->password() ); connect( logoffJob, TQT_SIGNAL( result( KIO::Job * ) ), @@ -267,7 +267,7 @@ bool ResourceGroupwareBase::doLoad() kdWarning() << "Download still in progress" << endl; return false; } - + mCalendar.close(); clearChanges(); disableChangeNotification(); @@ -292,7 +292,7 @@ void ResourceGroupwareBase::slotDownloadJobResult( KPIM::GroupwareJob *job ) mIsShowingError = false; } else { kdDebug(5800) << "Successfully downloaded data" << endl; - + clearChanges(); saveCache(); enableChangeNotification(); @@ -318,9 +318,9 @@ bool ResourceGroupwareBase::doSave() // to upload only certain changes and discard the rest. This is // particularly important for resources like the blogging resource, // where uploading would mean a republication of the blog, not only - // a modifications. + // a modifications. if ( !confirmSave() ) return false; - + mUploadJob = createUploadJob( adaptor() ); connect( mUploadJob, TQT_SIGNAL( result( KPIM::GroupwareJob * ) ), TQT_SLOT( slotUploadJobResult( KPIM::GroupwareJob * ) ) ); @@ -331,20 +331,20 @@ bool ResourceGroupwareBase::doSave() inc = addedIncidences(); for( it = inc.begin(); it != inc.end(); ++it ) { - addedItems.append( adaptor()->newUploadItem( *it, + addedItems.append( adaptor()->newUploadItem( *it, KPIM::GroupwareUploadItem::Added ) ); } // TODO: Check if the item has changed on the server... - // In particular, check if the version we based our change on is still current + // In particular, check if the version we based our change on is still current // on the server inc = changedIncidences(); for( it = inc.begin(); it != inc.end(); ++it ) { - changedItems.append( adaptor()->newUploadItem( *it, + changedItems.append( adaptor()->newUploadItem( *it, KPIM::GroupwareUploadItem::Changed ) ); } inc = deletedIncidences(); for( it = inc.begin(); it != inc.end(); ++it ) { - deletedItems.append( adaptor()->newUploadItem( *it, + deletedItems.append( adaptor()->newUploadItem( *it, KPIM::GroupwareUploadItem::Deleted ) ); } @@ -368,10 +368,10 @@ void ResourceGroupwareBase::slotUploadJobResult( KPIM::GroupwareJob *job ) mIsShowingError = false; } else { kdDebug(5800) << "Successfully uploaded data" << endl; - /* + /* * After the put the server might have expanded recurring events and will * also change the uids of the uploaded events. Remove them from the cache - * and get the fresh delta and download. + * and get the fresh delta and download. */ if ( !mDownloadJob ) { diff --git a/kresources/newexchange/exchangeconvertercontact.cpp b/kresources/newexchange/exchangeconvertercontact.cpp index 0764d3101..732c9db15 100644 --- a/kresources/newexchange/exchangeconvertercontact.cpp +++ b/kresources/newexchange/exchangeconvertercontact.cpp @@ -52,7 +52,7 @@ void ExchangeConverterContact::createRequest( TQDomDocument &doc, TQDomElement & TQDomAttr att_cal = doc.createAttribute( "xmlns:cal" ); att_cal.setValue( "urn:schemas:calendar:" ); doc.documentElement().setAttributeNode( att_cal ); - + propertyDAV( "contentclass" ); propertyDAV( "getcontenttype" ); propertyNS( "http://schemas.microsoft.com/exchange/", "outlookmessageclass" ); @@ -160,10 +160,10 @@ void ExchangeConverterContact::createRequest( TQDomDocument &doc, TQDomElement & #undef property -bool ExchangeConverterContact::extractAddress( const TQDomElement &node, +bool ExchangeConverterContact::extractAddress( const TQDomElement &node, Addressee &addressee, int type, - const TQString &street, const TQString &pobox, const TQString &location, - const TQString &postalcode, const TQString &state, const TQString &country, + const TQString &street, const TQString &pobox, const TQString &location, + const TQString &postalcode, const TQString &state, const TQString &country, const TQString &/*countycode*/ ) { bool haveAddr = false; @@ -206,13 +206,13 @@ bool ExchangeConverterContact::extractAddress( const TQDomElement &node, /** -For the complete list of Exchange <=> KABC field mappings see the file +For the complete list of Exchange <=> KABC field mappings see the file Person.mapping */ -bool ExchangeConverterContact::readAddressee( const TQDomElement &node, Addressee &addressee ) +bool ExchangeConverterContact::readAddressee( const TQDomElement &node, Addressee &addressee ) { TQString tmpstr; long tmplng; - + // The UID is absolutely required! if ( WebdavHandler::extractString( node, "uid", tmpstr ) ) { addressee.setUid( tmpstr ); @@ -224,7 +224,7 @@ bool ExchangeConverterContact::readAddressee( const TQDomElement &node, Addresse addressee.insertCustom( "KDEPIM-Exchange-Resource", "fingerprint", tmpstr ); if ( WebdavHandler::extractString( node, "href", tmpstr ) ) addressee.insertCustom( "KDEPIM-Exchange-Resource", "href", tmpstr ); - + /* KDE4: addressee does not have any creation or modification date :-(( */ /* KDE4: read-only not supported by libkabc */ @@ -232,16 +232,16 @@ bool ExchangeConverterContact::readAddressee( const TQDomElement &node, Addresse if ( WebdavHandler::extractString( node, "fileas", tmpstr ) || WebdavHandler::extractString( node, "cn", tmpstr ) ) addressee.setFormattedName( tmpstr ); - if ( WebdavHandler::extractString( node, "givenName", tmpstr ) ) + if ( WebdavHandler::extractString( node, "givenName", tmpstr ) ) addressee.setGivenName( tmpstr ); - if ( WebdavHandler::extractString( node, "middlename", tmpstr ) ) + if ( WebdavHandler::extractString( node, "middlename", tmpstr ) ) addressee.setAdditionalName( tmpstr ); - if ( WebdavHandler::extractString( node, "sn", tmpstr ) ) + if ( WebdavHandler::extractString( node, "sn", tmpstr ) ) addressee.setFamilyName( tmpstr ); //urn:schemas:contacts:initials not used - - if ( WebdavHandler::extractString( node, "namesuffix", tmpstr ) ) + if ( WebdavHandler::extractString( node, "namesuffix", tmpstr ) ) addressee.setSuffix( tmpstr ); - if ( WebdavHandler::extractString( node, "personaltitle", tmpstr ) ) + if ( WebdavHandler::extractString( node, "personaltitle", tmpstr ) ) addressee.setPrefix( tmpstr ); // Role @@ -249,31 +249,37 @@ bool ExchangeConverterContact::readAddressee( const TQDomElement &node, Addresse addressee.setRole( tmpstr ); // Company-Related settings - if ( WebdavHandler::extractString( node, "o", tmpstr ) ) + if ( WebdavHandler::extractString( node, "o", tmpstr ) ) addressee.setOrganization( tmpstr ); - if ( WebdavHandler::extractString( node, "department", tmpstr ) ) + if ( WebdavHandler::extractString( node, "department", tmpstr ) ) + { +#if KDE_IS_VERSION(3,5,8) + addressee.setDepartment( tmpstr ); +#else addressee.insertCustom( "KADDRESSBOOK", "X-Department", tmpstr ); - if ( WebdavHandler::extractString( node, "roomnumber", tmpstr ) ) +#endif + } + if ( WebdavHandler::extractString( node, "roomnumber", tmpstr ) ) addressee.insertCustom( "KADDRESSBOOK", "X-Office", tmpstr ); - if ( WebdavHandler::extractString( node, "profession", tmpstr ) ) + if ( WebdavHandler::extractString( node, "profession", tmpstr ) ) addressee.insertCustom( "KADDRESSBOOK", "X-Profession", tmpstr ); - if ( WebdavHandler::extractString( node, "manager", tmpstr ) ) + if ( WebdavHandler::extractString( node, "manager", tmpstr ) ) addressee.insertCustom( "KADDRESSBOOK", "X-ManagersName", tmpstr ); - if ( WebdavHandler::extractString( node, "secretarycn", tmpstr ) ) + if ( WebdavHandler::extractString( node, "secretarycn", tmpstr ) ) addressee.insertCustom( "KADDRESSBOOK", "X-AssistantsName", tmpstr ); // Web-Related settings if ( WebdavHandler::extractString( node, "email1", tmpstr ) ) addressee.insertEmail( tmpstr, true ); - if ( WebdavHandler::extractString( node, "email2", tmpstr ) ) + if ( WebdavHandler::extractString( node, "email2", tmpstr ) ) addressee.insertEmail( tmpstr ); - if ( WebdavHandler::extractString( node, "email3", tmpstr ) ) + if ( WebdavHandler::extractString( node, "email3", tmpstr ) ) addressee.insertEmail( tmpstr ); - + // No kabc field for personalHomePage - if ( WebdavHandler::extractString( node, "businesshomepage", tmpstr ) ) + if ( WebdavHandler::extractString( node, "businesshomepage", tmpstr ) ) addressee.setUrl( tmpstr ); if ( WebdavHandler::extractString( node, "fburl", tmpstr ) ) { @@ -284,14 +290,14 @@ bool ExchangeConverterContact::readAddressee( const TQDomElement &node, Addresse // General stuff: TQStringList tmplst; - if ( WebdavHandler::extractStringList( node, "Keywords", tmplst ) ) + if ( WebdavHandler::extractStringList( node, "Keywords", tmplst ) ) addressee.setCategories( tmplst ); // Exchange sentitivity values: // 0 None, 1 Personal, 2 Private, 3 Company Confidential if ( WebdavHandler::extractLong( node, "sensitivity", tmplng ) ) { switch( tmplng ) { case 0: addressee.setSecrecy( KABC::Secrecy::Public ); break; - case 1: + case 1: case 2: addressee.setSecrecy( KABC::Secrecy::Private ); break; case 3: addressee.setSecrecy( KABC::Secrecy::Confidential ); break; default: kdWarning() << "Unknown sensitivity: " << tmplng << endl; @@ -322,39 +328,39 @@ bool ExchangeConverterContact::readAddressee( const TQDomElement &node, Addresse insertPhone( "callbackphone", PhoneNumber::Msg ); insertPhone( "telexnumber", PhoneNumber::Bbs ); insertPhone( "ttytddphone", PhoneNumber::Pcs ); -#undef insertPhone +#undef insertPhone // Addresses: Work, Home, Mailing and Other: extractAddress( node, addressee, Address::Work | Address::Pref, "street", "postofficebox", "l", "postalcode", "st", "co", "c" ); extractAddress( node, addressee, Address::Home, - "homeStreet", "homepostofficebox", "homeCity", "homePostalCode", + "homeStreet", "homepostofficebox", "homeCity", "homePostalCode", "homeState", "homeCountry", "homeCountrycode" ); // Exchange doesn't support writing/changing the mailing address fields, // so don't download it. It's equal to either the home or work address anyway /* extractAddress( node, addressee, Address::Postal, - "mailingstreet", "mailingpostofficebox", "mailingcity", "mailingpostalcode", + "mailingstreet", "mailingpostofficebox", "mailingcity", "mailingpostalcode", "mailingstate", "mailingcountry", "mailingcountrycode" );*/ extractAddress( node, addressee, 0, - "otherstreet", "otherpostofficebox", "othercity", "otherpostalcode", + "otherstreet", "otherpostofficebox", "othercity", "otherpostalcode", "otherstate", "othercountry", "othercountrycode" ); - if ( WebdavHandler::extractString( node, "nickname", tmpstr ) ) + if ( WebdavHandler::extractString( node, "nickname", tmpstr ) ) addressee.setNickName( tmpstr ); - if ( WebdavHandler::extractString( node, "spousecn", tmpstr ) ) + if ( WebdavHandler::extractString( node, "spousecn", tmpstr ) ) addressee.insertCustom( "KADDRESSBOOK", "X-SpousesName", tmpstr ); TQDateTime tmpdt; - if ( WebdavHandler::extractDateTime( node, "bday", tmpdt ) ) + if ( WebdavHandler::extractDateTime( node, "bday", tmpdt ) ) addressee.setBirthday( tmpdt.date() ); - if ( WebdavHandler::extractString( node, "weddinganniversary", tmpstr ) ) + if ( WebdavHandler::extractString( node, "weddinganniversary", tmpstr ) ) addressee.insertCustom( "KADDRESSBOOK", "X-Anniversary", tmpstr ); // TODO? timeZone() float lt,lng; - if ( WebdavHandler::extractFloat( node, "geolatitude", lt ) && + if ( WebdavHandler::extractFloat( node, "geolatitude", lt ) && WebdavHandler::extractFloat( node, "geolongitude", lng ) ) addressee.setGeo( Geo( lt, lng ) ); // TODO: mapurl @@ -363,7 +369,7 @@ bool ExchangeConverterContact::readAddressee( const TQDomElement &node, Addresse if ( WebdavHandler::extractString( node, "textdescription", tmpstr ) ) addressee.setNote( tmpstr ); -// if ( WebdavHandler::extractString( node, "usercertificate", tmpstr ) ) +// if ( WebdavHandler::extractString( node, "usercertificate", tmpstr ) ) // addressee.setKeys() return true; @@ -380,24 +386,24 @@ Addressee::List ExchangeConverterContact::parseWebDAV( const TQDomDocument& davd kdDebug()<<"ExchangeConverterContact::parseWebDAV, no response->propstat->prop element!"< 0 ) { @@ -463,10 +473,10 @@ TQDomDocument ExchangeConverterContact::createWebDAV( Addressee addr ) if ( emails.count() > 2 ) { domContactProperty( "email3", emails[2] ); } - + // No value for "personalHomePage" domContactProperty( "businesshomepage", addr.url().url() ); - + TQString fburl = KCal::FreeBusyUrlStore::self()->readUrl( addr.preferredEmail() ); if ( !fburl.isEmpty() ) { domContactProperty( "fburl", fburl ); @@ -475,16 +485,16 @@ TQDomDocument ExchangeConverterContact::createWebDAV( Addressee addr ) /* FIXME: This doesn't work! TQStringList cats = addr.categories(); if ( cats.isEmpty() ) { - TQDomElement catsnode = WebdavHandler::addElementNS( doc, prop, + TQDomElement catsnode = WebdavHandler::addElementNS( doc, prop, "urn:schemas-microsoft-com:office:office", "Keywords" ); for ( TQStringList::Iterator it = cats.begin(); it != cats.end(); ++it ) { WebdavHandler::addElementNS( doc, catsnode, "xml:", "v", *it ); } } else { -// TQDomElement catsnode = addProperty( doc, prop, +// TQDomElement catsnode = addProperty( doc, prop, // "urn:schemas-microsoft-com:office:office", "Keywords", "" ); }*/ - + // Exchange sentitivity values: // 0 None, 1 Personal, 2 Private, 3 Company Confidential TQString value; @@ -517,7 +527,7 @@ TQDomDocument ExchangeConverterContact::createWebDAV( Addressee addr ) domPhoneProperty( "telexnumber", PhoneNumber::Bbs ); domPhoneProperty( "ttytddphone", PhoneNumber::Pcs ); - + // work address: Address workaddr = addr.address( Address::Work | Address::Pref ); if ( !workaddr.isEmpty() ) { @@ -541,7 +551,7 @@ TQDomDocument ExchangeConverterContact::createWebDAV( Addressee addr ) domContactProperty( "homeCountry", homeaddr.country() ); // domContactProperty( "homeCountrycode", homeaddr.countryCode() ); } - + // mailing address: // Exchange doesn't support writing/changing the mailing address fields /* Address mailingaddr = addr.address( Address::Postal ); @@ -566,8 +576,8 @@ TQDomDocument ExchangeConverterContact::createWebDAV( Addressee addr ) domContactProperty( "othercountry", otheraddr.country() ); // domContactProperty( "othercountrycode", otheraddr.countryCode() ); } - - + + domContactProperty( "nickname", addr.nickName() ); domContactProperty( "spousecn", addr.custom( "KADDRESSBOOK", "X-SpousesName" ) ); @@ -606,7 +616,7 @@ TQDomDocument ExchangeConverterContact::createWebDAV( Addressee addr ) // TODO:usercertificate // TODO: custom fields kdDebug()<<"DOM document: "< + using namespace KABC; ResourceExchange::ResourceExchange( const KConfig *config ) : ResourceGroupwareBase( config ) { init(); - if ( config ) readConfig( config ); + if ( config ) { + readConfig( config ); + } else { + setResourceName( i18n( "Exchange Server" ) ); + } } void ResourceExchange::init() diff --git a/kresources/newexchange/kcal_newexchange.desktop b/kresources/newexchange/kcal_newexchange.desktop index b94e28ce9..a0dd29c1e 100644 --- a/kresources/newexchange/kcal_newexchange.desktop +++ b/kresources/newexchange/kcal_newexchange.desktop @@ -20,7 +20,6 @@ Name[hu]=Exchange 2000-kiszolgáló naptára (kísérleti) Name[is]=Dagatal á Exchange þjóni (á tilraunarstigi) Name[it]=Calendario su un server Exchange (sperimentale) Name[ja]=Exchange サーバのカレンダー (実験版) -Name[ka]=კალენდარი Exchange სერვერზე (ექსპერიმენტული) Name[kk]=Exchange серверіндегі күнтізбе (сынақтағы) Name[km]=ប្រតិទិន​លើ​ម៉ាស៊ីន​បម្រើ Exchange (សម្រាប់​អ្នក​មាន​បទពិសោធន៍) Name[lt]=Kalendorius Exchange serveryje (eksperimentine tvarka) diff --git a/kresources/newexchange/kcal_newexchange_final.desktop b/kresources/newexchange/kcal_newexchange_final.desktop index fd159051d..01904c54a 100644 --- a/kresources/newexchange/kcal_newexchange_final.desktop +++ b/kresources/newexchange/kcal_newexchange_final.desktop @@ -22,7 +22,6 @@ Name[hu]=Exchange 2000-kiszolgáló naptára Name[is]=Dagatal á Exchange þjóni Name[it]=Calendario su un server Exchange Name[ja]=Exchange サーバのカレンダー -Name[ka]=კალენდარი Exchange სერვერზე Name[kk]=Exchange серверіндегі күнтізбе Name[km]=ប្រតិទិន​លើ​ម៉ាស៊ីន​បម្រើ Exchange Name[lt]=Kalendorius Exchange serveryje diff --git a/kresources/newexchange/kcal_resourceexchange.cpp b/kresources/newexchange/kcal_resourceexchange.cpp index 4c9f7726d..37d99d376 100644 --- a/kresources/newexchange/kcal_resourceexchange.cpp +++ b/kresources/newexchange/kcal_resourceexchange.cpp @@ -25,6 +25,7 @@ #include #include #include +#include using namespace KCal; @@ -38,7 +39,11 @@ ResourceExchange::ResourceExchange( const KConfig *config ) : ResourceGroupwareBase( config ) { init(); - if ( config ) readConfig( config ); + if ( config ) { + readConfig( config ); + } else { + setResourceName( i18n( "Exchange Server" ) ); + } } void ResourceExchange::init() diff --git a/kresources/remote/remote.desktop b/kresources/remote/remote.desktop index 66a1542af..2ddebc7e4 100644 --- a/kresources/remote/remote.desktop +++ b/kresources/remote/remote.desktop @@ -24,7 +24,6 @@ Name[hu]=Távoli fájlban tárolt naptár Name[is]=Dagatal í fjarlægri skrá Name[it]=Calendario in file remoto Name[ja]=リモートファイルのカレンダー -Name[ka]=კალენდარი გარე ფაილზე Name[kk]=Қашықтағы файлдағы күнтізбе Name[km]=ប្រតិទិន​នៅ​ក្នុង​ឯកសារ​នៅ​ឆ្ងាយ Name[lt]=Kalendorius nutolusioje byloje diff --git a/kresources/remote/resourceremote.cpp b/kresources/remote/resourceremote.cpp index 2aceaad0c..229dd86bf 100644 --- a/kresources/remote/resourceremote.cpp +++ b/kresources/remote/resourceremote.cpp @@ -56,6 +56,8 @@ ResourceRemote::ResourceRemote( const KConfig *config ) { if ( config ) { readConfig( config ); + } else { + setResourceName( i18n( "Remote Calendar" ) ); } init(); diff --git a/kresources/scalix/kcal/resourcescalix.cpp b/kresources/scalix/kcal/resourcescalix.cpp index d2849e862..63e964eb9 100644 --- a/kresources/scalix/kcal/resourcescalix.cpp +++ b/kresources/scalix/kcal/resourcescalix.cpp @@ -510,6 +510,12 @@ bool ResourceScalix::addEvent( KCal::Event* event ) return addIncidence( event, TQString::null, 0 ); } +bool ResourceScalix::addEvent( KCal::Event *event, const TQString &subresource ) +{ + Q_UNUSED( subresource ); // ResourceScalix does not support subresources + return this->addEvent( event ); +} + bool ResourceScalix::deleteIncidence( KCal::Incidence* incidence ) { if ( incidence->isReadOnly() ) return false; @@ -572,6 +578,12 @@ bool ResourceScalix::addTodo( KCal::Todo* todo ) return addIncidence( todo, TQString::null, 0 ); } +bool ResourceScalix::addTodo( KCal::Todo *todo, const TQString &subresource ) +{ + Q_UNUSED( subresource ); // ResourceScalix does not support subresources + return this->addTodo( todo ); +} + bool ResourceScalix::deleteTodo( KCal::Todo* todo ) { return deleteIncidence( todo ); @@ -600,6 +612,12 @@ bool ResourceScalix::addJournal( KCal::Journal* journal ) return addIncidence( journal, TQString::null, 0 ); } +bool ResourceScalix::addJournal( KCal::Journal *journal, const TQString &subresource ) +{ + Q_UNUSED( subresource ); // ResourceScalix does not support subresources + return this->addJournal( journal ); +} + bool ResourceScalix::deleteJournal( KCal::Journal* journal ) { return deleteIncidence( journal ); diff --git a/kresources/scalix/kcal/resourcescalix.h b/kresources/scalix/kcal/resourcescalix.h index 223161b4b..11baa5ec0 100644 --- a/kresources/scalix/kcal/resourcescalix.h +++ b/kresources/scalix/kcal/resourcescalix.h @@ -70,6 +70,7 @@ public: // The libkcal functions. See the resource for descriptions bool addEvent( KCal::Event* anEvent ); + bool addEvent( KCal::Event* anEvent, const TQString &subresource ); bool deleteEvent( KCal::Event* ); KCal::Event* event( const TQString &UniqueStr ); KCal::Event::List rawEvents( EventSortField sortField = EventSortUnsorted, SortDirection sortDirection = SortDirectionAscending ); @@ -82,12 +83,14 @@ public: bool inclusive = false ); bool addTodo( KCal::Todo* todo ); + bool addTodo( KCal::Todo* todo, const TQString &subresource ); bool deleteTodo( KCal::Todo* ); KCal::Todo* todo( const TQString& uid ); KCal::Todo::List rawTodos( TodoSortField sortField = TodoSortUnsorted, SortDirection sortDirection = SortDirectionAscending ); KCal::Todo::List rawTodosForDate( const TQDate& date ); bool addJournal( KCal::Journal* ); + bool addJournal( KCal::Journal* journal, const TQString &subresource ); bool deleteJournal( KCal::Journal* ); KCal::Journal* journal( const TQString& uid ); KCal::Journal::List rawJournals( JournalSortField sortField = JournalSortUnsorted, SortDirection sortDirection = SortDirectionAscending ); diff --git a/kresources/slox/kabc_ox.desktop b/kresources/slox/kabc_ox.desktop index 4f4fb8c22..8388f0800 100644 --- a/kresources/slox/kabc_ox.desktop +++ b/kresources/slox/kabc_ox.desktop @@ -18,7 +18,6 @@ Name[gl]=Servidor OpenXchange Name[hu]=OpenXchange-kiszolgáló Name[is]=OpenXchange þjónn Name[ja]=OpenXchange サーバ -Name[ka]=Openexchange სერვერი Name[kk]=OpenXchange сервері Name[km]=ម៉ាស៊ីន​បម្រើ OpenXchange Name[lt]=OpenXchange serveris diff --git a/kresources/slox/kabc_slox.desktop b/kresources/slox/kabc_slox.desktop index bdfce204e..5a0192caa 100644 --- a/kresources/slox/kabc_slox.desktop +++ b/kresources/slox/kabc_slox.desktop @@ -21,7 +21,6 @@ Name[hu]=SUSE LINUX Openexchange-kiszolgáló Name[is]=SUSE LINUX Openexchange þjónn Name[it]=Server SUSE LINUX Openexchange Name[ja]=SUSE LINUX Openexchange サーバ -Name[ka]= SUSE LINUX Openexchange სერვერი Name[kk]=SUSE LINUX Openexchange сервері Name[km]=ម៉ាស៊ីន​បម្រើ Openexchange របស់​ស៊ូស៊ីលីនីក Name[lt]=SUSE LINUX Openexchange serveris diff --git a/kresources/slox/kabcresourceslox.cpp b/kresources/slox/kabcresourceslox.cpp index 757bfae08..16d5aced5 100644 --- a/kresources/slox/kabcresourceslox.cpp +++ b/kresources/slox/kabcresourceslox.cpp @@ -49,6 +49,8 @@ ResourceSlox::ResourceSlox( const KConfig *config ) if ( config ) { readConfig( config ); + } else { + setResourceName( i18n( "OpenXchange Server" ) ); } } @@ -353,7 +355,11 @@ void ResourceSlox::parseContactAttribute( const TQDomElement &e, Addressee &a ) } else if ( tag == fieldName( Organization ) ) { a.setOrganization( text ); } else if ( tag == fieldName( Department ) ) { +#if KDE_IS_VERSION(3,5,8) + a.setDepartment( text ); +#else a.insertCustom( "KADDRESSBOOK", "X-Department", text ); +#endif } else if ( tag == fieldName( FamilyName ) ) { a.setFamilyName( text ); } else if ( tag == fieldName( GivenName) ) { @@ -542,8 +548,13 @@ void ResourceSlox::createAddresseeFields( TQDomDocument &doc, TQDomElement &prop else WebdavHandler::addSloxElement( this, doc, prop, fieldName( Birthday ) ); WebdavHandler::addSloxElement( this, doc, prop, fieldName( Role ), a.role() ); +#if KDE_IS_VERSION(3,5,8) + WebdavHandler::addSloxElement( this, doc, prop, fieldName( Department ), + a.department( ) ); +#else WebdavHandler::addSloxElement( this, doc, prop, fieldName( Department ), a.custom( "KADDRESSBOOK", "X-Department" ) ); +#endif if ( type() == "ox" ) { // OX only fields WebdavHandler::addSloxElement( this, doc, prop, fieldName( DisplayName ), a.formattedName() ); WebdavHandler::addSloxElement( this, doc, prop, fieldName( SecondName ), a.additionalName() ); diff --git a/kresources/slox/kcal_ox.desktop b/kresources/slox/kcal_ox.desktop index e0eaa9224..5bc7600ae 100644 --- a/kresources/slox/kcal_ox.desktop +++ b/kresources/slox/kcal_ox.desktop @@ -18,7 +18,6 @@ Name[gl]=Servidor OpenXchange Name[hu]=OpenXchange-kiszolgáló Name[is]=OpenXchange þjónn Name[ja]=OpenXchange サーバ -Name[ka]=Openexchange სერვერი Name[kk]=OpenXchange сервері Name[km]=ម៉ាស៊ីន​បម្រើ OpenXchange Name[lt]=OpenXchange serveris diff --git a/kresources/slox/kcal_slox.desktop b/kresources/slox/kcal_slox.desktop index 0daca0b2c..b4fe8e7a8 100644 --- a/kresources/slox/kcal_slox.desktop +++ b/kresources/slox/kcal_slox.desktop @@ -21,7 +21,6 @@ Name[hu]=SUSE LINUX Openexchange-kiszolgáló Name[is]=SUSE LINUX Openexchange þjónn Name[it]=Server SUSE LINUX Openexchange Name[ja]=SUSE LINUX Openexchange サーバ -Name[ka]= SUSE LINUX Openexchange სერვერი Name[kk]=SUSE LINUX Openexchange сервері Name[km]=ម៉ាស៊ីន​បម្រើ Openexchange របស់​ស៊ូស៊ីលីនីក Name[lt]=SUSE LINUX Openexchange serveris diff --git a/kresources/slox/kcalresourceslox.cpp b/kresources/slox/kcalresourceslox.cpp index 2fcb0baa3..edd13e6f9 100644 --- a/kresources/slox/kcalresourceslox.cpp +++ b/kresources/slox/kcalresourceslox.cpp @@ -70,6 +70,8 @@ KCalResourceSlox::KCalResourceSlox( const KConfig *config ) if ( config ) { readConfig( config ); + } else { + setResourceName( i18n( "OpenXchange Server" ) ); } } -- cgit v1.2.1