diff options
Diffstat (limited to 'kresources/caldav/resource.cpp')
-rw-r--r-- | kresources/caldav/resource.cpp | 1011 |
1 files changed, 0 insertions, 1011 deletions
diff --git a/kresources/caldav/resource.cpp b/kresources/caldav/resource.cpp deleted file mode 100644 index b9285e611..000000000 --- a/kresources/caldav/resource.cpp +++ /dev/null @@ -1,1011 +0,0 @@ -/*========================================================================= -| KCalDAV -|-------------------------------------------------------------------------- -| (c) 2010 Timothy Pearson -| (c) 2009 Kumaran Santhanam (initial KDE4 version) -| -| This project is released under the GNU General Public License. -| Please see the file COPYING for more details. -|-------------------------------------------------------------------------- -| Main interface to the KResource system. - ========================================================================*/ - -/*========================================================================= -| INCLUDES - ========================================================================*/ - -#include <string.h> -#include <unistd.h> - -#include <tqurl.h> -#include <tqmessagebox.h> -#include <tqapplication.h> -#include <tqeventloop.h> - -#include <libkcal/calendarlocal.h> -#include <libkcal/icalformat.h> - -#include <klocale.h> -#include <kpassdlg.h> - -#include <tqdatetime.h> -#include <tqmutex.h> -#include <tqthread.h> - -#ifdef KCALDAV_DEBUG - #include <tqfile.h> -#endif - -#include "resource.h" -#include "reader.h" -#include "writer.h" - -/*========================================================================= -| NAMESPACE - ========================================================================*/ - -using namespace KCal; - -/*========================================================================= -| CONSTANTS - ========================================================================*/ - -const unsigned long ResourceCalDav::TERMINATION_WAITING_TIME = 3 * 1000; // 3 seconds -const int ResourceCalDav::CACHE_DAYS = 90; - -const int ResourceCalDav::DEFAULT_RELOAD_INTERVAL = 10; -const int ResourceCalDav::DEFAULT_SAVE_INTERVAL = 10; -const int ResourceCalDav::DEFAULT_RELOAD_POLICY = ResourceCached::ReloadInterval; -const int ResourceCalDav::DEFAULT_SAVE_POLICY = ResourceCached::SaveDelayed; - -/*========================================================================= -| UTILITY - ========================================================================*/ - -#define log(s) kdDebug() << identifier() << ": " << (s) << '\n'; - -/*========================================================================= -| CONSTRUCTOR / DESTRUCTOR - ========================================================================*/ - -ResourceCalDav::ResourceCalDav( const TDEConfig *config ) : - ResourceCached(config) - , readLockout(false) - , mAllWritesComplete(false) - , mLock(true) - , mPrefs(NULL) - , mLoader(NULL) - , mWriter(NULL) - , mProgress(NULL) - , mLoadingQueueReady(true) - , mWritingQueueReady(true) - , mWriteRetryTimer(NULL) -{ - log("ResourceCalDav(config)"); - init(); - - if ( config ) { - readConfig( config ); - } -} - -ResourceCalDav::~ResourceCalDav() { - log("jobs termination"); - - if (mWriteRetryTimer != NULL) { - mWriteRetryTimer->stop(); // Unfortunately we cannot do anything at this point; if this timer is still running something is seriously wrong - } - - if (mLoader) { - readLockout = true; - mLoader->terminate(); - mLoader->wait(TERMINATION_WAITING_TIME); - mLoadingQueueReady = true; - } - - while ((mWriter->running() == true) || (mWritingQueue.isEmpty() == false) || !mWritingQueueReady) { - readLockout = true; - sleep(1); - tqApp->processEvents(TQEventLoop::ExcludeUserInput); - } - - if (mWriter) { - mWriter->terminate(); - } - - log("waiting for jobs terminated"); - - if (mLoader) { - mLoader->wait(TERMINATION_WAITING_TIME); - } - if (mWriter) { - mWriter->wait(TERMINATION_WAITING_TIME); - } - - log("deleting jobs"); - - delete mLoader; - delete mWriter; - - log("deleting preferences"); - - delete mPrefs; -} - -bool ResourceCalDav::isSaving() { - doSave(); - return (((mWriteRetryTimer != NULL) ? 1 : 0) || (mWriter->running() == true) || (mWritingQueue.isEmpty() == false) || !mWritingQueueReady || readLockout); -} - -/*========================================================================= -| GENERAL METHODS - ========================================================================*/ - -bool ResourceCalDav::doLoad() { - bool syncCache = true; - - if ((mLoadingQueueReady == false) || (mLoadingQueue.isEmpty() == false) || (mLoader->running() == true) || (isSaving() == true)) { - return true; // Silently fail; the user has obviously not responded to a dialog and we don't need to pop up more of them! - } - - log(TQString("doLoad(%1)").arg(syncCache)); - - clearCache(); - - log("loading from cache"); - disableChangeNotification(); - loadCache(); - enableChangeNotification(); - clearChanges(); // TODO: Determine if this really needs to be here, as it might clear out the calendar prematurely causing user confusion while the download process is running - emit resourceChanged(this); - emit resourceLoaded(this); - - log("starting download job"); - startLoading(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl(), mPrefs->getFullJournalsUrl()); - - return true; -} - -bool ResourceCalDav::doSave() { - bool syncCache = true; - - log(TQString("doSave(%1)").arg(syncCache)); - - if (!hasChanges()) { - log("no changes"); - return true; - } - - log("saving cache"); - saveCache(); - - // Delete any queued read jobs - mLoadingQueue.clear(); - - // See if there is a running read thread and terminate it - if (mLoader->running() == true) { - mLoader->terminate(); - mLoader->wait(TERMINATION_WAITING_TIME); - mLoadingQueueReady = true; - } - - log("start writing job"); - 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... - clearChanges(); - if (mWriteRetryTimer != NULL) { - if (mWriteRetryTimer->isActive() == false) { - disconnect( mWriteRetryTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(doSave()) ); - delete mWriteRetryTimer; - mWriteRetryTimer = NULL; - } - } - return true; - } - else return true; // We do not need to alert the user to this transient failure; a timer has been started to retry the save -} - - -KABC::Lock* ResourceCalDav::lock() { - log("lock()"); - return &mLock; -} - -void ResourceCalDav::readConfig( const TDEConfig *config ) { - log("readConfig"); - mPrefs->readConfig(); - ResourceCached::readConfig(config); -} - -void ResourceCalDav::writeConfig( TDEConfig *config ) { - log("writeConfig()"); - ResourceCalendar::writeConfig(config); - mPrefs->writeConfig(); - ResourceCached::writeConfig(config); -} - -CalDavPrefs* ResourceCalDav::createPrefs() const { - log("createPrefs()"); - CalDavPrefs* p = new CalDavPrefs(identifier()); - return p; -} - -void ResourceCalDav::init() { - // default settings - setReloadInterval(DEFAULT_RELOAD_INTERVAL); - setReloadPolicy(DEFAULT_RELOAD_POLICY); - setSaveInterval(DEFAULT_SAVE_INTERVAL); - setSavePolicy(DEFAULT_SAVE_POLICY); - - // creating preferences - mPrefs = createPrefs(); - - // creating reader/writer instances - mLoader = new CalDavReader; - mWriter = new CalDavWriter; - - // creating jobs - // TQt4 handles this quite differently, as shown below, - // whereas TQt3 needs events (see ::event()) -// connect(mLoader, TQT_SIGNAL(finished()), this, TQT_SLOT(loadFinished())); -// connect(mWriter, TQT_SIGNAL(finished()), this, TQT_SLOT(writingFinished())); - - setType("ResourceCalDav"); -} - -void ResourceCalDav::setIncidencesReadOnly(Incidence::List& inc, bool readOnly) { - Incidence::List::Iterator it; - for ( it = inc.begin(); it != inc.end(); ++it ) { - (*it)->setReadOnly( readOnly ); - } -} - -void ResourceCalDav::ensureReadOnlyFlagHonored() { - //disableChangeNotification(); - - Incidence::List inc( rawIncidences() ); - setIncidencesReadOnly(inc, readOnly()); - - //enableChangeNotification(); - - emit resourceChanged(this); -} - -void ResourceCalDav::setReadOnly(bool v) { - KRES::Resource::setReadOnly(v); - log("ensuring read only flag honored"); - ensureReadOnlyFlagHonored(); -} - -void ResourceCalDav::updateProgressBar(int direction) { - int current_queued_events; - static int original_queued_events; - - // See if anything is in the queues - current_queued_events = mWritingQueue.count() + mLoadingQueue.count(); - if ((direction == 0) && (mLoader->running() == true)) current_queued_events++; - if ((direction == 1) && (mWriter->running() == true)) current_queued_events++; - if (current_queued_events > original_queued_events) { - original_queued_events = current_queued_events; - } - - if (current_queued_events == 0) { - if ( mProgress != NULL) { - mProgress->setComplete(); - mProgress = NULL; - original_queued_events = 0; - } - } - else { - if (mProgress == NULL) { - if (direction == 0) mProgress = KPIM::ProgressManager::createProgressItem(KPIM::ProgressManager::getUniqueID(), i18n("Downloading Calendar") ); - if (direction == 1) mProgress = KPIM::ProgressManager::createProgressItem(KPIM::ProgressManager::getUniqueID(), i18n("Uploading Calendar") ); - } - mProgress->setProgress( ((((float)original_queued_events-(float)current_queued_events)*100)/(float)original_queued_events) ); - } -} - -/*========================================================================= -| READING METHODS - ========================================================================*/ - -void ResourceCalDav::loadingQueuePush(const LoadingTask *task) { - if ((mLoadingQueue.isEmpty() == true) && (mLoader->running() == false)) { - mLoadingQueue.enqueue(task); - updateProgressBar(0); - loadingQueuePop(); - } -} - -void ResourceCalDav::loadingQueuePop() { - if (!mLoadingQueueReady || mLoadingQueue.isEmpty() || (isSaving() == true)) { - return; - } - - if (!mLoader) { - log("loader == NULL"); - return; - } - - // 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. - LoadingTask *t = mLoadingQueue.head(); - - mLoader->setUrl(t->url); - mLoader->setTasksUrl(t->tasksUrl); - mLoader->setJournalsUrl(t->journalsUrl); - mLoader->setParent(this); - mLoader->setType(0); - - TQDateTime dt(TQDate::currentDate()); - mLoader->setRange(dt.addDays(-CACHE_DAYS), dt.addDays(CACHE_DAYS)); - //mLoader->setGetAll(); - - mLoadingQueueReady = false; - - log("starting actual download job"); - mLoader->start(TQThread::LowestPriority); - - // if all ok, removing the task from the queue - mLoadingQueue.dequeue(); - updateProgressBar(0); - - delete t; -} - -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); -} - -void ResourceCalDav::loadFinished() { - CalDavReader* loader = mLoader; - - log("load finished"); - - if (!loader) { - log("loader is NULL"); - return; - } - - if (loader->error()) { - if (loader->errorNumber() == -401) { - if (NULL != mPrefs) { - TQCString newpass; - if (KPasswordDialog::getPassword (newpass, TQString("<b>") + i18n("Remote authorization required") + TQString("</b><p>") + i18n("Please input the password for") + TQString(" ") + mPrefs->getusername(), NULL) != 1) { - log("load error: " + loader->errorString() ); - loadError(TQString("[%1] ").arg(abs(loader->errorNumber())) + loader->errorString()); - } - else { - // Set new password and try again - mPrefs->setPassword(TQString(newpass)); - startLoading(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl(), mPrefs->getFullJournalsUrl()); - } - } - else { - log("load error: " + loader->errorString() ); - loadError(TQString("[%1] ").arg(abs(loader->errorNumber())) + loader->errorString()); - } - } - else { - log("load error: " + loader->errorString() ); - loadError(TQString("[%1] ").arg(abs(loader->errorNumber())) + loader->errorString()); - } - } else { - log("successful event load"); - TQString data = loader->data(); - - 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) - // have some lines separated by single \r rather than \n or \r\n. - // ICalFormat fails to parse that. - data.replace("\r\n", "\n"); // to avoid \r\n becomes \n\n after the next line - data.replace('\r', '\n'); - - log("trying to parse..."); - if (parseData(data)) { - // 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); - } - } - } - - if (loader->tasksError()) { - if (loader->tasksErrorNumber() == -401) { - if (NULL != mPrefs) { -// TQCString newpass; -// if (KPasswordDialog::getPassword (newpass, TQString("<b>") + i18n("Remote authorization required") + TQString("</b><p>") + i18n("Please input the password for") + TQString(" ") + mPrefs->getusername(), NULL) != 1) { -// log("load error: " + loader->tasksErrorString() ); -// loadError(TQString("[%1] ").arg(abs(loader->tasksErrorNumber())) + loader->tasksErrorString()); -// } -// else { -// // Set new password and try again -// mPrefs->setPassword(TQString(newpass)); -// startLoading(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl(), mPrefs->getFullJournalsUrl()); -// } - } - else { - log("load error: " + loader->tasksErrorString() ); - loadError(TQString("[%1] ").arg(abs(loader->tasksErrorNumber())) + loader->tasksErrorString()); - } - } - else { - log("load error: " + loader->tasksErrorString() ); - loadError(TQString("[%1] ").arg(abs(loader->tasksErrorNumber())) + loader->tasksErrorString()); - } - } else { - log("successful tasks load"); - TQString tasksData = loader->tasksData(); - - 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); - } - } - } - - if (loader->journalsError()) { - if (loader->journalsErrorNumber() == -401) { - if (NULL != mPrefs) { -// TQCString newpass; -// if (KPasswordDialog::getPassword (newpass, TQString("<b>") + i18n("Remote authorization required") + TQString("</b><p>") + 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(); - mLoader->wait(TERMINATION_WAITING_TIME); - mLoadingQueueReady = true; - updateProgressBar(0); - loadingQueuePop(); -} - -bool ResourceCalDav::checkData(const TQString& data) { - log("checking the data"); - - ICalFormat ical; - bool ret = true; - if (!ical.fromString(&mCalendar, data)) { - log("invalid ical string"); - ret = false; - } - - return ret; -} - -bool ResourceCalDav::parseData(const TQString& data) { - log("parseData()"); - - 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"); - clearEventsCache(); - - 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; -} - -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; - } - - log("clearing cache"); - clearTodosCache(); - - 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; -} - -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 - ========================================================================*/ - -TQString ResourceCalDav::getICalString(const Incidence::List& inc) { - if (inc.isEmpty()) { - return ""; - } - - CalendarLocal loc(timeZoneId()); - TQString data = ""; - TQString header = ""; - TQString footer = ""; - ICalFormat ical; - - // Get the iCal header and footer - header = ical.toString(&loc); - int location = header.find("END:VCALENDAR", 0, true); - footer = header.mid(location, 0xffffffff); - header.remove("END:VCALENDAR"); - - data = data + header; - // NOTE: This is very susceptible to invalid entries in added/changed/deletedIncidences - // Be very careful with clearChange/clearChanges, and be sure to clear after load and save... - for(Incidence::List::ConstIterator it = inc.constBegin(); it != inc.constEnd(); ++it) { - Incidence *i = (*it)->clone(); - data = data + ical.toString(i, &mCalendar); - } - data = data + footer; - - // Remove any line feeds/carriage returns/white spaces from the UID field as they WILL break libcaldav - int uidPos = data.find("UID:", 0) + 4; - int nextPos = data.findRev("\n", data.find(":", uidPos)); - TQString uidField = data.mid(uidPos, nextPos-uidPos); - data.remove(uidPos, nextPos-uidPos); - uidField.replace("\n", ""); - uidField.replace("\r", ""); - uidField.replace(" ", ""); - data.insert(uidPos, uidField); - return data; -} - -void ResourceCalDav::writingQueuePush(const WritingTask *task) { -// printf("task->added: %s\n\r", task->added.ascii()); -// printf("task->deleted: %s\n\r", task->deleted.ascii()); -// printf("task->changed: %s\n\r", task->changed.ascii()); - mWritingQueue.enqueue(task); - updateProgressBar(1); - writingQueuePop(); -} - -void ResourceCalDav::writingQueuePop() { - if (!mWritingQueueReady || mWritingQueue.isEmpty()) { - return; - } - - if (!mWriter) { - log("writer == NULL"); - return; - } - - // Writing queue and mWritingQueueReady flag are not shared resources, i.e. only one thread has an access to them. - // That's why no mutexes are required. - WritingTask *t = mWritingQueue.head(); - - log("writingQueuePop: url = " + t->url); - - mWriter->setUrl(t->url); - mWriter->setTasksUrl(t->tasksUrl); - mWriter->setJournalsUrl(t->journalsUrl); - mWriter->setParent(this); - mWriter->setType(1); - -#ifdef KCALDAV_DEBUG - const TQString fout_path = "/tmp/kcaldav_upload_" + identifier() + ".tmp"; - - TQFile fout(fout_path); - if (fout.open(IO_WriteOnly | IO_Append)) { - TQTextStream sout(&fout); - sout << "---------- " << resourceName() << ": --------------------------------\n"; - sout << "================== Added:\n" << t->added << "\n"; - sout << "================== Changed:\n" << t->changed << "\n"; - sout << "================== Deleted:\n" << t->deleted << "\n"; - fout.close(); - } else { - loadError(i18n("can't open file")); - } -#endif // debug - - mWriter->setAddedObjects(t->added); - mWriter->setChangedObjects(t->changed); - mWriter->setDeletedObjects(t->deleted); - - mWriter->setAddedTasksObjects(t->tasksAdded); - 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"); - mWriter->start(TQThread::LowestPriority); - - // if all ok, remove the task from the queue - mWritingQueue.dequeue(); - updateProgressBar(1); - - delete t; -} - -bool ResourceCalDav::event ( TQEvent * e ) { - if (e->type() == 1000) { - // Read done - loadFinished(); - return TRUE; - } - else if (e->type() == 1001) { - // Write done - writingFinished(); - return TRUE; - } - else return FALSE; -} - -void ResourceCalDav::releaseReadLockout() { - readLockout = false; -} - -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 - // modifies the calendar with clearChanges() or similar - // Before these calls are made any existing read (and maybe write) threads should be finished - if ((mLoader->running() == true) || (mLoadingQueue.isEmpty() == false) || (mWriter->running() == true) || (mWritingQueue.isEmpty() == false)) { - if (mWriteRetryTimer == NULL) { - mWriteRetryTimer = new TQTimer(this); - connect( mWriteRetryTimer, TQT_SIGNAL(timeout()), TQT_SLOT(doSave()) ); - } - mWriteRetryTimer->start(1000, TRUE); - return false; - } - - // If we don't lock the read out for a few seconds, it would be possible for the old calendar to be - // downloaded before our changes are committed, presenting a very bad image to the user as his/her appointments - // revert to the state they were in before the write (albiet temporarily) - readLockout = true; - - // This needs to send each event separately; i.e. if two events were added they need - // to be extracted and pushed on the stack independently (using two calls to writingQueuePush()) - - Incidence::List added = addedIncidences(); - Incidence::List changed = changedIncidences(); - Incidence::List deleted = deletedIncidences(); - - Incidence::List::ConstIterator it; - Incidence::List currentIncidence; - - for( it = added.begin(); it != added.end(); ++it ) { - WritingTask *t = new WritingTask; - - currentIncidence.clear(); - currentIncidence.append(*it); - - 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); - } - - for( it = changed.begin(); it != changed.end(); ++it ) { - WritingTask *t = new WritingTask; - - currentIncidence.clear(); - currentIncidence.append(*it); - - t->url = url; - t->tasksUrl = tasksUrl; - 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->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); - } - - for( it = deleted.begin(); it != deleted.end(); ++it ) { - WritingTask *t = new WritingTask; - - currentIncidence.clear(); - currentIncidence.append(*it); - - t->url = url; - t->tasksUrl = tasksUrl; - 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->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); - } - - return true; -} - -void ResourceCalDav::writingFinished() { - log("writing finished"); - - if (!mWriter) { - log("mWriter is NULL"); - return; - } - - if (mWriter->error() && (abs(mWriter->errorNumber()) != 207)) { - if (mWriter->errorNumber() == -401) { - if (NULL != mPrefs) { - TQCString newpass; - if (KPasswordDialog::getPassword (newpass, TQString("<b>") + i18n("Remote authorization required") + TQString("</b><p>") + i18n("Please input the password for") + TQString(" ") + mPrefs->getusername(), NULL) != 1) { - log("write error: " + mWriter->errorString()); - saveError(TQString("[%1] ").arg(abs(mWriter->errorNumber())) + mWriter->errorString()); - } - else { - // Set new password and try again - mPrefs->setPassword(TQString(newpass)); - startWriting(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl(), mPrefs->getFullJournalsUrl()); - } - } - else { - log("write error: " + mWriter->errorString()); - saveError(TQString("[%1] ").arg(abs(mWriter->errorNumber())) + mWriter->errorString()); - } - } - else { - log("write error: " + mWriter->errorString()); - saveError(TQString("[%1] ").arg(abs(mWriter->errorNumber())) + mWriter->errorString()); - } - } else { - log("success"); - // is there something to do here? - } - - // Give the remote system a few seconds to process the data before we allow any read operations - TQTimer::singleShot( 3000, this, TQT_SLOT(releaseReadLockout()) ); - - // Writing queue and mWritingQueueReady flag are not shared resources, i.e. only one thread has an access to them. - // That's why no mutexes are required. - mWriter->terminate(); - mWriter->wait(TERMINATION_WAITING_TIME); - mWritingQueueReady = true; - updateProgressBar(1); - writingQueuePop(); -} - -#include "resource.moc" - -// EOF ======================================================================== |