From 75502cb30b6b56c4ab65ef7f3e315c3298408937 Mon Sep 17 00:00:00 2001 From: tpearson Date: Sat, 28 Aug 2010 01:04:18 +0000 Subject: Added tasks support to CalDAV resource This nearly completes Zimbra integration git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdepim@1168963 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- kresources/caldav/config.cpp | 32 ++++++++-- kresources/caldav/config.h | 4 ++ kresources/caldav/job.h | 15 +++++ kresources/caldav/preferences.cpp | 27 ++++++++ kresources/caldav/preferences.h | 5 ++ kresources/caldav/prefsskel.kcfg | 8 +++ kresources/caldav/reader.cpp | 33 +++++++++- kresources/caldav/reader.h | 8 +++ kresources/caldav/resource.cpp | 126 +++++++++++++++++++++++++++++++++++--- kresources/caldav/resource.h | 20 +++++- kresources/caldav/writer.cpp | 27 ++++++++ kresources/caldav/writer.h | 64 ++++++++++++++++--- 12 files changed, 341 insertions(+), 28 deletions(-) (limited to 'kresources') diff --git a/kresources/caldav/config.cpp b/kresources/caldav/config.cpp index da9bd8473..550e00c97 100644 --- a/kresources/caldav/config.cpp +++ b/kresources/caldav/config.cpp @@ -88,6 +88,8 @@ void ResourceCalDavConfig::loadSettings( KRES::Resource *resource ) { mUsername->setText(p->username()); mRememberPassword->setChecked(p->rememberPassword()); mPassword->setText(p->password()); + mTasksUrl->setText(p->tasksUrl()); + mUseSTasks->setChecked(p->useSTasks()); mReloadConfig->loadSettings(res); mSaveConfig->loadSettings(res); @@ -106,6 +108,8 @@ void ResourceCalDavConfig::saveSettings( KRES::Resource *resource ) { p->setUsername(mUsername->text()); p->setRememberPassword(mRememberPassword->isChecked()); p->setPassword(mPassword->text()); + p->setTasksUrl(mTasksUrl->text()); + p->setUseSTasks(mUseSTasks->isChecked()); } } } @@ -121,22 +125,36 @@ void ResourceCalDavConfig::setupUI() { mainLayout->addWidget( label, 1, 0 ); mainLayout->addWidget( mUrl, 1, 1 ); + // Tasks URL + TQLabel *tlabel = new TQLabel( i18n( "Tasks URL:" ), this ); + mTasksUrl = new TQLineEdit( this ); + mainLayout->addWidget( tlabel, 2, 0 ); + mainLayout->addWidget( mTasksUrl, 2, 1 ); + + // Use Task URL checkbox + mUseSTasks = new TQCheckBox( i18n("Use separate Tasks URL"), this ); + mainLayout->addWidget(mUseSTasks, 3, 0 ); + // Username label = new TQLabel( i18n( "Username:" ), this ); mUsername = new TQLineEdit( this ); - mainLayout->addWidget( label, 2, 0 ); - mainLayout->addWidget( mUsername, 2, 1 ); + mainLayout->addWidget( label, 4, 0 ); + mainLayout->addWidget( mUsername, 4, 1 ); // Password label = new TQLabel( i18n( "Password:" ), this ); mPassword = new TQLineEdit( this ); mPassword->setEchoMode( TQLineEdit::Password ); - mainLayout->addWidget( label, 3, 0 ); - mainLayout->addWidget( mPassword, 3, 1 ); + mainLayout->addWidget( label, 5, 0 ); + mainLayout->addWidget( mPassword, 5, 1 ); // Remember password checkbox mRememberPassword = new TQCheckBox( i18n("Remember password"), this ); - mainLayout->addWidget(mRememberPassword, 4, 1); + mainLayout->addWidget(mRememberPassword, 6, 1); + + mTasksUrl->setEnabled(mUseSTasks->isChecked()); + connect( mUseSTasks, TQT_SIGNAL( toggled( bool ) ), + TQT_SLOT( slotSTasksToggled( bool ) ) ); // configs TQHBoxLayout* horizontal = new TQHBoxLayout(this); @@ -159,4 +177,8 @@ void ResourceCalDavConfig::setupUI() { vertical->addLayout(horizontal); } +void ResourceCalDavConfig::slotSTasksToggled( bool enabled ) { + mTasksUrl->setEnabled(enabled); +} + // EOF ======================================================================== diff --git a/kresources/caldav/config.h b/kresources/caldav/config.h index 5e9d2e760..746c87aca 100644 --- a/kresources/caldav/config.h +++ b/kresources/caldav/config.h @@ -50,6 +50,8 @@ public slots: virtual void loadSettings(KRES::Resource *resource); virtual void saveSettings(KRES::Resource *resource); + void slotSTasksToggled( bool ); + protected: virtual void setupUI(); @@ -57,8 +59,10 @@ protected: private: TQLineEdit *mUrl; + TQLineEdit *mTasksUrl; TQLineEdit *mUsername; TQLineEdit *mPassword; + TQCheckBox *mUseSTasks; TQCheckBox *mRememberPassword; CalDavReloadConfig* mReloadConfig; CalDavSaveConfig* mSaveConfig; diff --git a/kresources/caldav/job.h b/kresources/caldav/job.h index 254a0a104..53d4e0e18 100644 --- a/kresources/caldav/job.h +++ b/kresources/caldav/job.h @@ -53,6 +53,13 @@ public: mUrl = s; } + /** + * Sets a new Tasks URL to load. + */ + virtual void setTasksUrl(const TQString& s) { + mTasksUrl = s; + } + /** * Sets the parent qobject. */ @@ -74,6 +81,13 @@ public: return mUrl; } + /** + * @return Tasks URL to load. + */ + virtual TQString tasksUrl() const { + return mTasksUrl; + } + /** * @return parent object */ @@ -147,6 +161,7 @@ protected: private: TQString mUrl; + TQString mTasksUrl; bool mError; TQString mErrorString; long mErrorNumber; diff --git a/kresources/caldav/preferences.cpp b/kresources/caldav/preferences.cpp index 8e27b9df0..d70a35193 100644 --- a/kresources/caldav/preferences.cpp +++ b/kresources/caldav/preferences.cpp @@ -232,5 +232,32 @@ TQString CalDavPrefs::getFullUrl() { return safeURL; } +TQString CalDavPrefs::getFullTasksUrl() { + if (useSTasks() == 0) + return TQString(); + + TQUrl t(tasksUrl()); + 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 3a9400ae8..666b8ccf1 100644 --- a/kresources/caldav/preferences.h +++ b/kresources/caldav/preferences.h @@ -87,6 +87,11 @@ public: */ TQString getFullUrl(); + /** + * @return A full URL to connect to CalDAV Tasks server (including username and password). + */ + TQString getFullTasksUrl(); + protected: /** diff --git a/kresources/caldav/prefsskel.kcfg b/kresources/caldav/prefsskel.kcfg index 39b79b85f..bb05a75f6 100644 --- a/kresources/caldav/prefsskel.kcfg +++ b/kresources/caldav/prefsskel.kcfg @@ -10,6 +10,14 @@ + + + + + + + + diff --git a/kresources/caldav/reader.cpp b/kresources/caldav/reader.cpp index 7d912a7f8..4a65b2ab9 100644 --- a/kresources/caldav/reader.cpp +++ b/kresources/caldav/reader.cpp @@ -31,6 +31,7 @@ using namespace KCal; void CalDavReader::cleanJob() { CalDavJob::cleanJob(); mData = ""; + mTasksData = ""; } int CalDavReader::runJob(runtime_info* RT) { @@ -41,10 +42,10 @@ int CalDavReader::runJob(runtime_info* RT) { if (mGetAll) { kdDebug() << "getting all objects"; - res = caldav_getall_object(result, std::string(url().ascii()).c_str(), RT); + res = caldav_tasks_getall_object(result, std::string(url().ascii()).c_str(), RT); } else { kdDebug() << "getting object from the specified time range"; - res = caldav_get_object(result, mTimeStart.toTime_t(), mTimeEnd.toTime_t(), std::string(url().ascii()).c_str(), RT); + res = caldav_tasks_get_object(result, mTimeStart.toTime_t(), mTimeEnd.toTime_t(), std::string(url().ascii()).c_str(), RT); } if (OK == res) { @@ -60,6 +61,34 @@ int CalDavReader::runJob(runtime_info* RT) { caldav_free_response(&result); + if ((OK == res) && (tasksUrl() != "")) { + kdDebug() << "reader::run, url: " << tasksUrl(); + + response* result = caldav_get_response(); + CALDAV_RESPONSE res = OK; + + if (mGetAll) { + kdDebug() << "getting all objects"; + res = caldav_tasks_getall_object(result, std::string(tasksUrl().ascii()).c_str(), RT); + } else { + kdDebug() << "getting object from the specified time range"; + res = caldav_tasks_get_object(result, mTimeStart.toTime_t(), mTimeEnd.toTime_t(), std::string(tasksUrl().ascii()).c_str(), RT); + } + + if (OK == res) { + kdDebug() << "success"; + if (result->msg) { + mTasksData = result->msg; + } else { + kdDebug() << "empty collection"; + // empty collection + mTasksData = ""; + } + } + + caldav_free_response(&result); + } + return res; } diff --git a/kresources/caldav/reader.h b/kresources/caldav/reader.h index 191d28bad..c34f2083b 100644 --- a/kresources/caldav/reader.h +++ b/kresources/caldav/reader.h @@ -71,6 +71,13 @@ public: return mData; } + /** + * @return downloaded task data in iCal format. + */ + TQString tasksData() const { + return mTasksData; + } + protected: virtual int runJob(runtime_info* caldavRuntime); @@ -80,6 +87,7 @@ protected: private: TQString mData; + TQString mTasksData; bool mGetAll; TQDateTime mTimeStart; TQDateTime mTimeEnd; diff --git a/kresources/caldav/resource.cpp b/kresources/caldav/resource.cpp index 462cd6290..f3835b180 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()); + startLoading(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl()); return true; } @@ -189,7 +189,7 @@ bool ResourceCalDav::doSave() { } log("start writing job"); - if (startWriting(mPrefs->getFullUrl()) == true) { + if (startWriting(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl()) == 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... @@ -333,6 +333,7 @@ void ResourceCalDav::loadingQueuePop() { LoadingTask *t = mLoadingQueue.head(); mLoader->setUrl(t->url); + mLoader->setTasksUrl(t->tasksUrl); mLoader->setParent(this); mLoader->setType(0); @@ -352,9 +353,10 @@ void ResourceCalDav::loadingQueuePop() { delete t; } -void ResourceCalDav::startLoading(const TQString& url) { +void ResourceCalDav::startLoading(const TQString& url, const TQString& tasksUrl) { LoadingTask *t = new LoadingTask; t->url = url; + t->tasksUrl = tasksUrl; loadingQueuePush(t); } @@ -379,7 +381,7 @@ void ResourceCalDav::loadFinished() { else { // Set new password and try again mPrefs->setPassword(TQString(newpass)); - startLoading(mPrefs->getFullUrl()); + startLoading(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl()); } } else { @@ -394,6 +396,7 @@ void ResourceCalDav::loadFinished() { } else { log("successful load"); TQString data = loader->data(); + TQString tasksData = loader->tasksData(); if (!data.isNull() && !data.isEmpty()) { // TODO: I don't know why, but some schedules on http://caldav-test.ioda.net/ (I used it for testing) @@ -414,6 +417,26 @@ void ResourceCalDav::loadFinished() { emit resourceLoaded(this); } } + + if (!tasksData.isNull() && !tasksData.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. + tasksData.replace("\r\n", "\n"); // to avoid \r\n becomes \n\n after the next line + tasksData.replace('\r', '\n'); + + log("trying to parse..."); + if (parseTasksData(tasksData)) { + // 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. @@ -495,6 +518,60 @@ bool ResourceCalDav::parseData(const TQString& data) { return ret; } +bool ResourceCalDav::parseTasksData(const TQString& data) { + log("parseTasksData()"); + + 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; + } + + 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 ========================================================================*/ @@ -554,6 +631,7 @@ void ResourceCalDav::writingQueuePop() { log("writingQueuePop: url = " + t->url); mWriter->setUrl(t->url); + mWriter->setTasksUrl(t->tasksUrl); mWriter->setParent(this); mWriter->setType(1); @@ -577,6 +655,10 @@ void ResourceCalDav::writingQueuePop() { mWriter->setChangedObjects(t->changed); mWriter->setDeletedObjects(t->deleted); + mWriter->setAddedTasksObjects(t->tasksAdded); + mWriter->setChangedTasksObjects(t->tasksChanged); + mWriter->setDeletedTasksObjects(t->tasksDeleted); + mWritingQueueReady = false; log("starting actual write job"); @@ -607,7 +689,7 @@ void ResourceCalDav::releaseReadLockout() { readLockout = false; } -bool ResourceCalDav::startWriting(const TQString& url) { +bool ResourceCalDav::startWriting(const TQString& url, const TQString& tasksUrl) { log("startWriting: url = " + url); // WARNING: This will segfault if a separate read or write thread @@ -644,9 +726,17 @@ bool ResourceCalDav::startWriting(const TQString& url) { currentIncidence.append(*it); t->url = url; - t->added = getICalString(currentIncidence); + t->tasksUrl = tasksUrl; + t->added = ""; t->changed = ""; t->deleted = ""; + t->tasksAdded = ""; + t->tasksChanged = ""; + t->tasksDeleted = ""; + if (getICalString(currentIncidence).contains("BEGIN:VEVENT") > 0) + t->added = getICalString(currentIncidence); + else if (getICalString(currentIncidence).contains("BEGIN:VTODO") > 0) + t->tasksAdded = getICalString(currentIncidence); writingQueuePush(t); } @@ -658,9 +748,18 @@ bool ResourceCalDav::startWriting(const TQString& url) { currentIncidence.append(*it); t->url = url; + t->tasksUrl = tasksUrl; t->added = ""; - t->changed = getICalString(currentIncidence); + t->changed = ""; t->deleted = ""; + t->tasksAdded = ""; + t->tasksChanged = ""; + t->tasksDeleted = ""; + + if (getICalString(currentIncidence).contains("BEGIN:VEVENT") > 0) + t->changed = getICalString(currentIncidence); + else if (getICalString(currentIncidence).contains("BEGIN:VTODO") > 0) + t->tasksChanged = getICalString(currentIncidence); writingQueuePush(t); } @@ -672,9 +771,18 @@ bool ResourceCalDav::startWriting(const TQString& url) { currentIncidence.append(*it); t->url = url; + t->tasksUrl = tasksUrl; t->added = ""; t->changed = ""; - t->deleted = getICalString(currentIncidence); + t->deleted = ""; + t->tasksAdded = ""; + t->tasksChanged = ""; + t->tasksDeleted = ""; + + if (getICalString(currentIncidence).contains("BEGIN:VEVENT") > 0) + t->deleted = getICalString(currentIncidence); + else if (getICalString(currentIncidence).contains("BEGIN:VTODO") > 0) + t->tasksDeleted = getICalString(currentIncidence); writingQueuePush(t); } @@ -701,7 +809,7 @@ void ResourceCalDav::writingFinished() { else { // Set new password and try again mPrefs->setPassword(TQString(newpass)); - startWriting(mPrefs->getFullUrl()); + startWriting(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl()); } } else { diff --git a/kresources/caldav/resource.h b/kresources/caldav/resource.h index ba1f3e9af..bb69807be 100644 --- a/kresources/caldav/resource.h +++ b/kresources/caldav/resource.h @@ -85,13 +85,20 @@ protected: struct LoadingTask { TQString url; + TQString tasksUrl; }; struct WritingTask { TQString url; + TQString tasksUrl; + TQString added; TQString changed; TQString deleted; + + TQString tasksAdded; + TQString tasksChanged; + TQString tasksDeleted; }; @@ -121,8 +128,9 @@ protected: /** * Initiates calendar loading process. * @param url URL to load calendar data from. + * @param tasksUrl URL to load task data from. */ - void startLoading(const TQString& url); + void startLoading(const TQString& url, const TQString& tasksUrl); /** * Checks if the data is correct and can be parsed. @@ -138,12 +146,20 @@ protected: */ bool parseData(const TQString& data); + /** + * 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); + /** * Initiates calendar writing process. * @param url URL to save calendar data to. * @return true if write was queued successfully, false if not */ - bool startWriting(const TQString& url); + bool startWriting(const TQString& url, const TQString& tasksUrl); /** * Returns a list of incidences as a valid iCalendar string. diff --git a/kresources/caldav/writer.cpp b/kresources/caldav/writer.cpp index 98008bcd8..4580df514 100644 --- a/kresources/caldav/writer.cpp +++ b/kresources/caldav/writer.cpp @@ -28,6 +28,7 @@ // It's done, because, for some reason, SOGo server returns an error // on caldav_modify_object. DAViCAL works fine both ways. #define USE_CALDAV_MODIFY +#define USE_CALDAV_TASKS_MODIFY /*========================================================================= | NAMESPACE @@ -72,6 +73,32 @@ int CalDavWriter::runJob(runtime_info* RT) { #endif // if USE_CALDAV_MODIFY } + res = OK; + + kdDebug() << "pushing added tasks objects"; + res = pushTasksObjects(mTasksAdded, caldav_add_object, OK, RT); + if ((OK == res) && (tasksUrl() != "")) { +#ifdef USE_CALDAV_TASKS_MODIFY + kdDebug() << "pushing changed objects"; + res = pushTasksObjects(mTasksChanged, caldav_tasks_modify_object, OK, RT); + if (OK == res) { + kdDebug() << "pushing deleted objects"; + res = pushTasksObjects(mTasksDeleted, caldav_tasks_delete_object, OK, RT); + } +#else // if USE_CALDAV_TASKS_MODIFY + kdDebug() << "pushing changed objects (delete)"; + res = pushTasksObjects(mTasksChanged, caldav_tasks_delete_object, OK, RT); + if (OK == res) { + kdDebug() << "pushing changed objects (add)"; + res = pushTasksObjects(mTasksChanged, caldav_add_object, OK, RT); + if (OK == res) { + kdDebug() << "pushing deleted objects"; + res = pushTasksObjects(mTasksDeleted, caldav_tasks_delete_object, OK, RT); + } + } +#endif // if USE_CALDAV_TASKS_MODIFY + } + if (OK != res) { clearObjects(); } diff --git a/kresources/caldav/writer.h b/kresources/caldav/writer.h index 2d1d2d7bb..e9bfcd3b5 100644 --- a/kresources/caldav/writer.h +++ b/kresources/caldav/writer.h @@ -46,32 +46,59 @@ public: } /** - * Sets the information about added incidences writer should send to server. - * @param s icalendar-formatted string consists of all added incidences plus necessary calendar info. - * May be an empty string, which means there is no added incidences to send. + * Sets the information about added events writer should send to server. + * @param s icalendar-formatted string consists of all added events plus necessary calendar info. + * May be an empty string, which means there are no added events to send. */ void setAddedObjects(const TQString& s) { mAdded = s; } /** - * Sets the information about changed incidences writer should send to server. - * @param s icalendar-formatted string consists of all changed incidences plus necessary calendar info. - * May be an empty string, which means there is no changed incidences to send. + * Sets the information about changed events writer should send to server. + * @param s icalendar-formatted string consists of all changed events plus necessary calendar info. + * May be an empty string, which means there are no changed events to send. */ void setChangedObjects(const TQString& s) { mChanged = s; } /** - * Sets the information about deleted incidences writer should send to server. - * @param s icalendar-formatted string consists of all deleted incidences plus necessary calendar info. - * May be an empty string, which means there is no deleted incidences to send. + * Sets the information about deleted events writer should send to server. + * @param s icalendar-formatted string consists of all deleted events plus necessary calendar info. + * May be an empty string, which means there are no deleted events to send. */ void setDeletedObjects(const TQString& s) { mDeleted = s; } + /** + * Sets the information about added tasks writer should send to server. + * @param s icalendar-formatted string consists of all added tasks plus necessary calendar info. + * May be an empty string, which means there are no added tasks to send. + */ + void setAddedTasksObjects(const TQString& s) { + mTasksAdded = 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. + * May be an empty string, which means there are no changed tasks to send. + */ + void setChangedTasksObjects(const TQString& s) { + mTasksChanged = 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. + * May be an empty string, which means there are no deleted tasks to send. + */ + void setDeletedTasksObjects(const TQString& s) { + mTasksDeleted = s; + } + /** * Clear all the information previously set. */ @@ -79,6 +106,9 @@ public: setAddedObjects(""); setChangedObjects(""); setDeletedObjects(""); + setAddedTasksObjects(""); + setChangedTasksObjects(""); + setDeletedTasksObjects(""); } protected: @@ -87,7 +117,7 @@ protected: virtual void cleanJob(); - /// Just a wrapper above libcaldav functions. + /// Just a wrapper above libcaldav event writing functions. template int pushObjects(const TQString& data, Operation op, int okCode, runtime_info* RT) { int r = okCode; @@ -97,11 +127,25 @@ protected: return r; } + /// Just a wrapper above libcaldav task writing functions. + template + int pushTasksObjects(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(tasksUrl().ascii()).c_str(), RT); + } + return r; + } + private: TQString mAdded; TQString mChanged; TQString mDeleted; + + TQString mTasksAdded; + TQString mTasksChanged; + TQString mTasksDeleted; }; } // namespace KCal -- cgit v1.2.1