/* memofile-conduit.cc KPilot ** ** Copyright (C) 2004-2007 by Jason 'vanRijn' Kasper ** ** This file does the actual conduit work. */ /* ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU Lesser General Public License as published by ** the Free Software Foundation; either version 2.1 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser General Public License ** along with this program in a file called COPYING; if not, write to ** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ** MA 02110-1301, USA. */ /* ** Bug reports and questions can be sent to kde-pim@kde.org */ #include "options.h" // Only include what we really need: // First UNIX system stuff, then std C++, // then TQt, then KDE, then local includes. // // #include // required by pilot-link includes #include #include "pilotMemo.h" #include #include #include #include #include #include "pilotRecord.h" #include "pilotSerialDatabase.h" #include "memofile-factory.h" #include "memofile-conduit.h" #include "memofileSettings.h" /** * Our workhorse. This is the main driver for the conduit. */ MemofileConduit::MemofileConduit(KPilotLink *d, const char *n, const TQStringList &l) : ConduitAction(d,n,l), _DEFAULT_MEMODIR(TQDir::homeDirPath() + CSL1("/MyMemos")), fMemoAppInfo(0L), _memofiles(0L) { FUNCTIONSETUP; fConduitName=i18n("Memofile"); fMemoList.setAutoDelete(true); } MemofileConduit::~MemofileConduit() { FUNCTIONSETUP; KPILOT_DELETE(_memofiles); } /* virtual */ bool MemofileConduit::exec() { FUNCTIONSETUP; setFirstSync( false ); // try new format first... // DEBUGKPILOT << fname << ": trying new format database first." << endl; bool _open = false; /* _open = openDatabases(CSL1("MemosDB-PMem")); if(!_open) { DEBUGKPILOT << fname << ": unable to open new format database. trying old one." << endl; */ _open = openDatabases(CSL1("MemoDB")); /* } else { DEBUGKPILOT << fname << ": able to open new format database." << endl; } */ if(!_open) { emit logError(i18n("Unable to open the memo databases on the handheld.")); DEBUGKPILOT << fname << ": unable to open new or old format database." << endl; return false; } readConfig(); if (! initializeFromPilot()) { emit logError(i18n("Cannot initialize from pilot.")); return false; } _memofiles = new Memofiles(fCategories, *fMemoAppInfo, _memo_directory, *fCtrHH); if (! _memofiles || ! _memofiles->isReady()) { emit logError(i18n("Cannot initialize the memo files from disk.")); return false; } fCtrPC->setStartCount(_memofiles->count()); setFirstSync( _memofiles->isFirstSync() ); addSyncLogEntry(i18n(" Syncing with %1.").tqarg(_memo_directory)); if ( (syncMode() == SyncAction::SyncMode::eCopyHHToPC) || _memofiles->isFirstSync() ) { addSyncLogEntry(i18n(" Copying Pilot to PC...")); DEBUGKPILOT << fname << ": copying Pilot to PC." << endl; copyHHToPC(); } else if ( syncMode() == SyncAction::SyncMode::eCopyPCToHH ) { DEBUGKPILOT << fname << ": copying PC to Pilot." << endl; addSyncLogEntry(i18n(" Copying PC to Pilot...")); copyPCToHH(); } else { DEBUGKPILOT << fname << ": doing regular sync." << endl; addSyncLogEntry(i18n(" Doing regular sync...")); sync(); } cleanup(); return delayDone(); } bool MemofileConduit::readConfig() { FUNCTIONSETUP; TQString dir(MemofileConduitSettings::directory()); if (dir.isEmpty()) { dir = _DEFAULT_MEMODIR; DEBUGKPILOT << fname << ": no directory given to us. defaulting to: [" << _DEFAULT_MEMODIR << "]" << endl; } _memo_directory = dir; _sync_private = MemofileConduitSettings::syncPrivate(); DEBUGKPILOT << fname << ": Settings... " << " directory: [" << _memo_directory << "], first sync: [" << isFirstSync() << "], sync private: [" << _sync_private << "]" << endl; return true; } bool MemofileConduit::setAppInfo() { FUNCTIONSETUP; // reset our category mapping from the filesystem MemoCategoryMap map = _memofiles->readCategoryMetadata(); if (map.count() <=0) { DEBUGKPILOT << fname << ": category metadata map is empty, nothing to do." << endl; return true; } fCategories = map; for (unsigned int i = 0; i < Pilot::CATEGORY_COUNT; i++) { if (fCategories.contains(i)) { fMemoAppInfo->setCategoryName(i,fCategories[i]); } } if (fDatabase) { fMemoAppInfo->writeTo(fDatabase); } if (fLocalDatabase) { fMemoAppInfo->writeTo(fLocalDatabase); } return true; } bool MemofileConduit::getAppInfo() { FUNCTIONSETUP; KPILOT_DELETE(fMemoAppInfo); fMemoAppInfo = new PilotMemoInfo(fDatabase); fMemoAppInfo->dump(); return true; } /** * Methods related to getting set up from the Pilot. */ bool MemofileConduit::initializeFromPilot() { if (!getAppInfo()) return false; if (!loadPilotCategories()) return false; return true; } bool MemofileConduit::loadPilotCategories() { FUNCTIONSETUP; fCategories.clear(); TQString _category_name; int _category_id=0; int _category_num=0; for (unsigned int i = 0; i < Pilot::CATEGORY_COUNT; i++) { _category_name = fMemoAppInfo->categoryName(i); if (!_category_name.isEmpty()) { _category_name = Memofiles::sanitizeName( _category_name ); _category_id = fMemoAppInfo->categoryInfo()->ID[i]; _category_num = i; fCategories[_category_num] = _category_name; DEBUGKPILOT << fname << ": Category #" << _category_num << " has ID " << _category_id << " and name " <<_category_name << endl; } } return true; } /** * Read all memos in from Pilot. */ void MemofileConduit::getAllFromPilot() { FUNCTIONSETUP; DEBUGKPILOT << fname << ": Database has " << fDatabase->recordCount() << " records." << endl; fMemoList.clear(); int currentRecord = 0; PilotRecord *pilotRec; PilotMemo *memo = 0; while ((pilotRec = fDatabase->readRecordByIndex(currentRecord)) != NULL) { if ((!pilotRec->isSecret()) || _sync_private) { memo = new PilotMemo(pilotRec); fMemoList.append(memo); DEBUGKPILOT << fname << ": Added memo: [" << currentRecord << "], id: [" << memo->id() << "], category: [" << fCategories[memo->category()] << "], title: [" << memo->getTitle() << "]" << endl; } else { DEBUGKPILOT << fname << ": Skipped secret record: [" << currentRecord << "], title: [" << memo->getTitle() << "]" << endl; } KPILOT_DELETE(pilotRec); currentRecord++; } DEBUGKPILOT << fname << ": read: [" << fMemoList.count() << "] records from palm." << endl; } /** * Read all modified memos in from Pilot. */ void MemofileConduit::getModifiedFromPilot() { FUNCTIONSETUP; fMemoList.clear(); int currentRecord = 0; PilotRecord *pilotRec; PilotMemo *memo = 0; while ((pilotRec = fDatabase->readNextModifiedRec()) != NULL) { memo = new PilotMemo(pilotRec); // we are syncing to both our filesystem and to the local // database, so take care of the local database here if (memo->isDeleted()) { fLocalDatabase->deleteRecord(memo->id()); } else { fLocalDatabase->writeRecord(pilotRec); } if ((!pilotRec->isSecret()) || _sync_private) { fMemoList.append(memo); DEBUGKPILOT << fname << ": modified memo id: [" << memo->id() << "], title: [" << memo->getTitle() << "]" << endl; } else { DEBUGKPILOT << fname << ": skipped secret modified record id: [" << memo->id() << "], title: [" << memo->getTitle() << "]" << endl; } KPILOT_DELETE(pilotRec); currentRecord++; } DEBUGKPILOT << fname << ": read: [" << fMemoList.count() << "] modified records from palm." << endl; } /* slot */ void MemofileConduit::process() { FUNCTIONSETUP; DEBUGKPILOT << fname << ": Now in state " << fActiontqStatus << endl; } void MemofileConduit::listPilotMemos() { FUNCTIONSETUP; PilotMemo *memo; for ( memo = fMemoList.first(); memo; memo = fMemoList.next() ) { TQString _category_name = fCategories[memo->category()]; DEBUGKPILOT << fConduitName << ": listing record id: [" << memo->id() << "] category id: [" << memo->category() << "] category name: [" << _category_name << "] title: [" << memo->getTitle() << "]" << endl; } } bool MemofileConduit::copyHHToPC() { FUNCTIONSETUP; getAllFromPilot(); _memofiles->eraseLocalMemos(); _memofiles->setPilotMemos(fMemoList); _memofiles->save(); return true; } bool MemofileConduit::copyPCToHH() { FUNCTIONSETUP; // set category info from the filesystem, if we can. // Note: This will reset both fCategories and fMemoAppInfo, so // after this, we need to reinitialize our memofiles object... setAppInfo(); // re-create our memofiles helper... KPILOT_DELETE(_memofiles); _memofiles = new Memofiles(fCategories, *fMemoAppInfo, _memo_directory, *fCtrHH); _memofiles->load(true); TQPtrList memofiles = _memofiles->getAll(); Memofile * memofile; for ( memofile = memofiles.first(); memofile; memofile = memofiles.next() ) { writeToPilot(memofile); } _memofiles->save(); // now that we've copied from the PC to our handheld, remove anything extra from the // handheld... deleteUnsyncedHHRecords(); return true; } void MemofileConduit::deleteUnsyncedHHRecords() { FUNCTIONSETUP; if ( syncMode()==SyncMode::eCopyPCToHH ) { Pilot::RecordIDList ids=fDatabase->idList(); Pilot::RecordIDList::iterator it; for ( it = ids.begin(); it != ids.end(); ++it ) { if (!_memofiles->find(*it)) { DEBUGKPILOT << fname << "Deleting record with ID "<< *it <<" from handheld " << "(is not on PC, and syncing with PC->HH direction)" << endl; fDatabase->deleteRecord(*it); fLocalDatabase->deleteRecord(*it); } } } } int MemofileConduit::writeToPilot(Memofile * memofile) { FUNCTIONSETUP; int oldid = memofile->id(); PilotRecord *r = memofile->pack(); if (!r) { DEBUGKPILOT << fname << ": ERROR: [" << memofile->toString() << "] could not be written to the pilot." << endl; return -1; } int newid = fDatabase->writeRecord(r); fLocalDatabase->writeRecord(r); KPILOT_DELETE(r); memofile->setID(newid); TQString status; if (oldid <=0) { fCtrHH->created(); status = "new to pilot"; } else { fCtrHH->updated(); status = "updated"; } DEBUGKPILOT << fname << ": memofile: [" << memofile->toString() << "] written to the pilot, [" << status << "]." << endl; return newid; } void MemofileConduit::deleteFromPilot(PilotMemo * memo) { FUNCTIONSETUP; PilotRecord *r = memo->pack(); if (r) { r->setDeleted(true); fDatabase->writeRecord(r); fLocalDatabase->writeRecord(r); } KPILOT_DELETE(r); fCtrHH->deleted(); DEBUGKPILOT << fname << ": memo: [" << memo->getTitle() << "] deleted from the pilot." << endl; } bool MemofileConduit::sync() { FUNCTIONSETUP; _memofiles->load(false); getModifiedFromPilot(); PilotMemo *memo; for ( memo = fMemoList.first(); memo; memo = fMemoList.next() ) { _memofiles->addModifiedMemo(memo); } TQPtrList memofiles = _memofiles->getModified(); Memofile *memofile; for ( memofile = memofiles.first(); memofile; memofile = memofiles.next() ) { if (memofile->isDeleted()) { deleteFromPilot(memofile); } else { writeToPilot(memofile); } } _memofiles->save(); return true; } void MemofileConduit::cleanup() { FUNCTIONSETUP; fDatabase->resetSyncFlags(); fDatabase->cleanup(); fLocalDatabase->resetSyncFlags(); fLocalDatabase->cleanup(); fCtrPC->setEndCount(_memofiles->count()); } #include "memofile-conduit.moc"