diff options
Diffstat (limited to 'kresources/carddav/resource.cpp')
-rw-r--r-- | kresources/carddav/resource.cpp | 683 |
1 files changed, 0 insertions, 683 deletions
diff --git a/kresources/carddav/resource.cpp b/kresources/carddav/resource.cpp deleted file mode 100644 index dae91c322..000000000 --- a/kresources/carddav/resource.cpp +++ /dev/null @@ -1,683 +0,0 @@ -/*========================================================================= -| KCardDAV -|-------------------------------------------------------------------------- -| (c) 2010 Timothy Pearson -| -| 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 <kabc/addressee.h> -#include <kabc/vcardconverter.h> - -#include <klocale.h> -#include <kpassdlg.h> - -#include <tqdatetime.h> -#include <tqmutex.h> -#include <tqthread.h> -#include <tqtimer.h> - -#ifdef KCARDDAV_DEBUG - #include <tqfile.h> -#endif - -#include "resource.h" -#include "reader.h" -#include "writer.h" - -/*========================================================================= -| NAMESPACE - ========================================================================*/ - -using namespace KABC; - -/*========================================================================= -| CONSTANTS - ========================================================================*/ - -const unsigned long ResourceCardDav::TERMINATION_WAITING_TIME = 3 * 1000; // 3 seconds -const int ResourceCardDav::CACHE_DAYS = 90; - -const int ResourceCardDav::DEFAULT_RELOAD_INTERVAL = 10; -const int ResourceCardDav::DEFAULT_SAVE_INTERVAL = 10; -const int ResourceCardDav::DEFAULT_RELOAD_POLICY = ResourceCached::ReloadInterval; -const int ResourceCardDav::DEFAULT_SAVE_POLICY = ResourceCached::SaveDelayed; - -/*========================================================================= -| UTILITY - ========================================================================*/ - -#define log(s) kdDebug() << identifier() << ": " << (s) << '\n'; - -/*========================================================================= -| CONSTRUCTOR / DESTRUCTOR - ========================================================================*/ - -ResourceCardDav::ResourceCardDav( 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("ResourceCardDav(config)"); - init(); - - if ( config ) { - readConfig( config ); - } -} - -ResourceCardDav::~ResourceCardDav() { - 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 (mWriter) { - mWriter->wait(TERMINATION_WAITING_TIME); - } - - log("deleting jobs"); - - delete mLoader; - delete mWriter; - - log("deleting preferences"); - - delete mPrefs; -} - -bool ResourceCardDav::isSaving() { - doSave(); - return (((mWriteRetryTimer != NULL) ? 1 : 0) || (mWriter->running() == true) || (mWritingQueue.isEmpty() == false) || !mWritingQueueReady || readLockout); -} - -/*========================================================================= -| GENERAL METHODS - ========================================================================*/ - -bool ResourceCardDav::load() { - 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)); - - // FIXME KABC - //clearCache(); - - log("loading from cache"); - //disableChangeNotification(); - loadCache(); - //enableChangeNotification(); - clearChanges(); - addressBook()->emitAddressBookChanged(); - emit loadingFinished( this ); - - log("starting download job"); - startLoading(mPrefs->getFullUrl()); - - return true; -} - -bool ResourceCardDav::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()) == 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 -} - - -bool ResourceCardDav::save( Ticket* ticket ) { - // To suppress warning about doSave() method hides ResourceCached::doSave(Ticket) - //return ResourceCached::doSave(); - return doSave(); -} - -KABC::Lock* ResourceCardDav::lock() { - log("lock()"); - return &mLock; -} - -void ResourceCardDav::readConfig( const TDEConfig *config ) { - log("readConfig"); - mPrefs->readConfig(); - // FIXME KABC - //ResourceCached::readConfig(config); -} - -void ResourceCardDav::writeConfig( TDEConfig *config ) { - log("writeConfig()"); - Resource::writeConfig(config); - mPrefs->writeConfig(); - ResourceCached::writeConfig(config); -} - -CardDavPrefs* ResourceCardDav::createPrefs() const { - log("createPrefs()"); - CardDavPrefs* p = new CardDavPrefs(identifier()); - return p; -} - -void ResourceCardDav::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 CardDavReader; - mWriter = new CardDavWriter; - - // 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("ResourceCardDav"); -} - -void ResourceCardDav::ensureReadOnlyFlagHonored() { - //disableChangeNotification(); - - // FIXME KABC - //Incidence::List inc( rawIncidences() ); - //setIncidencesReadOnly(inc, readOnly()); - - //enableChangeNotification(); - - if (addressBook() != NULL) { - addressBook()->emitAddressBookChanged(); - } -} - -void ResourceCardDav::setReadOnly(bool v) { - KRES::Resource::setReadOnly(v); - log("ensuring read only flag honored"); - ensureReadOnlyFlagHonored(); -} - -void ResourceCardDav::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 Contacts") ); - if (direction == 1) mProgress = KPIM::ProgressManager::createProgressItem(KPIM::ProgressManager::getUniqueID(), i18n("Uploading Contacts") ); - } - mProgress->setProgress( ((((float)original_queued_events-(float)current_queued_events)*100)/(float)original_queued_events) ); - } -} - -/*========================================================================= -| READING METHODS - ========================================================================*/ - -void ResourceCardDav::loadingQueuePush(const LoadingTask *task) { - if ((mLoadingQueue.isEmpty() == true) && (mLoader->running() == false)) { - mLoadingQueue.enqueue(task); - updateProgressBar(0); - loadingQueuePop(); - } -} - -void ResourceCardDav::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->setParent(this); - mLoader->setType(0); - mLoader->setUseURI(mPrefs->getUseURI()); - - 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 ResourceCardDav::startLoading(const TQString& url) { - LoadingTask *t = new LoadingTask; - t->url = url; - loadingQueuePush(t); -} - -void ResourceCardDav::loadFinished() { - CardDavReader* 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() ); - addressBook()->error(TQString("[%1] ").arg(abs(loader->errorNumber())) + loader->errorString()); - } - else { - // Set new password and try again - mPrefs->setPassword(TQString(newpass)); - startLoading(mPrefs->getFullUrl()); - } - } - else { - log("load error: " + loader->errorString() ); - addressBook()->error(TQString("[%1] ").arg(abs(loader->errorNumber())) + loader->errorString()); - } - } - else { - log("load error: " + loader->errorString() ); - addressBook()->error(TQString("[%1] ").arg(abs(loader->errorNumber())) + loader->errorString()); - } - } else { - log("successful load"); - TQString data = loader->data(); - - if (!data.isNull() && !data.isEmpty()) { - 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)) { - log("... parsing is ok"); - log("clearing changes"); - //enableChangeNotification(); - clearChanges(); - addressBook()->emitAddressBookChanged(); - emit loadingFinished( 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 ResourceCardDav::checkData(const TQString& data) { - log("checking the data"); - - KABC::VCardConverter converter; - bool ret = true; - KABC::VCardConverter conv; - Addressee::List addressees = conv.parseVCards( data ); - if (addressees.isEmpty() == true) { - ret = false; - } - - return ret; -} - -bool ResourceCardDav::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)) { - addressBook()->error(i18n("Parsing calendar data failed.")); - return false; - } - - // FIXME KABC - //log("clearing cache"); - //clearCache(); - - //disableChangeNotification(); - - log("actually parsing the data"); - - KABC::VCardConverter conv; - Addressee::List addressees = conv.parseVCards( data ); - Addressee::List::ConstIterator it; - for( it = addressees.begin(); it != addressees.end(); ++it ) { - KABC::Addressee addr = *it; - if ( !addr.isEmpty() ) { - addr.setResource( this ); - - insertAddressee( addr ); - clearChange( addr ); - } - } - - // debug code here ------------------------------------------------------- -#ifdef KCARDDAV_DEBUG - const TQString fout_path = "/tmp/kcarddav_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 { - addressBook()->error(i18n("can't open file")); - } -#endif // KCARDDAV_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("cleaning up cache"); - cleanUpCache( addressees ); - log("saving to cache"); - saveCache(); - } - - return ret; -} - -/*========================================================================= -| WRITING METHODS - ========================================================================*/ - -Ticket *ResourceCardDav::requestSaveTicket() -{ - if ( !addressBook() ) { - kdDebug(5700) << "no addressbook" << endl; - return 0; - } - - return createTicket( this ); -} - -void ResourceCardDav::releaseSaveTicket( Ticket *ticket ) -{ - delete ticket; -} - -void ResourceCardDav::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 ResourceCardDav::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->setParent(this); - mWriter->setType(1); - mWriter->setUseURI(mPrefs->getUseURI()); - -#ifdef KCARDDAV_DEBUG - const TQString fout_path = "/tmp/kcarddav_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 { - addressBook()->error(i18n("can't open file")); - } -#endif // debug - - mWriter->setAddedObjects(t->added); - mWriter->setChangedObjects(t->changed); - mWriter->setDeletedObjects(t->deleted); - - 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 ResourceCardDav::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; -} - -bool ResourceCardDav::startWriting(const TQString& url) { - log("startWriting: url = " + url); - - WritingTask *t = new WritingTask; - KABC::VCardConverter converter; - - // 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; - } - - KABC::Addressee::List added = addedAddressees(); - KABC::Addressee::List changed = changedAddressees(); - KABC::Addressee::List deleted = deletedAddressees(); - - t->url = url; - // FIXME KABC - t->added = converter.createVCards(added); // This crashes when an event is added from the remote server and save() is subsequently called - t->changed = converter.createVCards(changed); - t->deleted = converter.createVCards(deleted); - - writingQueuePush(t); - - return true; -} - -void ResourceCardDav::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()); - addressBook()->error(TQString("[%1] ").arg(abs(mWriter->errorNumber())) + mWriter->errorString()); - } - else { - // Set new password and try again - mPrefs->setPassword(TQString(newpass)); - startWriting(mPrefs->getFullUrl()); - } - } - else { - log("write error: " + mWriter->errorString()); - addressBook()->error(TQString("[%1] ").arg(abs(mWriter->errorNumber())) + mWriter->errorString()); - } - } - else { - log("write error: " + mWriter->errorString()); - addressBook()->error(TQString("[%1] ").arg(abs(mWriter->errorNumber())) + mWriter->errorString()); - } - } else { - log("success"); - // is there something to do here? - } - - // 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(); - - // If a URI is required we will need to retrieve it from the server after the new record is committed... - if (mPrefs->getUseURI() == true) { - startLoading(mPrefs->getFullUrl()); - } -} - -#include "resource.moc" - -// EOF ======================================================================== |