You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kpilot/conduits/memofileconduit/memofile-conduit.cc

568 lines
12 KiB

/* 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 <time.h> // required by pilot-link includes
#include <pi-memo.h>
#include "pilotMemo.h"
#include <tqfile.h>
#include <tqdir.h>
#include <tqtextcodec.h>
#include <tdeconfig.h>
#include <kdebug.h>
#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.").arg(_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 " << fActionStatus << 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<Memofile> 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<Memofile> 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"