From cb7eddb91455a69cf66fcd717e91a51ca5e2cfef Mon Sep 17 00:00:00 2001 From: tpearson Date: Wed, 16 Feb 2011 20:17:18 +0000 Subject: Moved kpilot from kdepim to applications, as the core Trinity libraries should not contain hardware-dependent software git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/kpilot@1221127 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- conduits/docconduit/doc-conduit.cc | 1018 ++++++++++++++++++++++++++++++++++++ 1 file changed, 1018 insertions(+) create mode 100644 conduits/docconduit/doc-conduit.cc (limited to 'conduits/docconduit/doc-conduit.cc') diff --git a/conduits/docconduit/doc-conduit.cc b/conduits/docconduit/doc-conduit.cc new file mode 100644 index 0000000..54f1ab4 --- /dev/null +++ b/conduits/docconduit/doc-conduit.cc @@ -0,0 +1,1018 @@ +/* KPilot +** +** Copyright (C) 2002 by Reinhold Kainhofer +** +** The doc conduit synchronizes text files on the PC with DOC databases on the Palm +*/ + +/* +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 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 General Public License for more details. +** +** You should have received a copy of the GNU 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. +*/ + + +// naming of the bookmark file: +// PDB->TXT: convert bookmarks to a .bm file +// TXT->PDB: If a .bmk file exists, use it, otherwise use the .bm file (from the PDB->TXT conversion) +// This way, the bookmark file is not overwritten, a manual bookmark file overrides, but the bookmarks from the handheld are still available + + +#include "options.h" +#include "doc-conduit.moc" + +#include +#include + +#include +#include + +#include +#include + +#include "doc-factory.h" +#include "doc-conflictdialog.h" +#include "DOC-converter.h" +#include "pilotDOCHead.h" +#include "docconduitSettings.h" + + +// Something to allow us to check what revision +// the modules are that make up a binary distribution. +extern "C" +{ +unsigned long version_conduit_doc = Pilot::PLUGIN_API; +} + +TQString dirToString(eSyncDirectionEnum dir) { + switch(dir) { +// case eSyncAll: return "eSyncAll"; + case eSyncPDAToPC: return CSL1("eSyncPDAToPC"); + case eSyncPCToPDA: return CSL1("eSyncPCToPDA"); + case eSyncNone: return CSL1("eSyncNone"); + case eSyncConflict: return CSL1("eSyncConflict"); + case eSyncDelete: return CSL1("eSyncDelete"); + default: return CSL1("ERROR"); + } +} + + +/********************************************************************* + C O N S T R U C T O R + *********************************************************************/ + + +DOCConduit::DOCConduit(KPilotLink * o, + const char *n, const TQStringList & a):ConduitAction(o, n, a) +{ + FUNCTIONSETUP; + fConduitName=i18n("DOC"); +} + + + +DOCConduit::~DOCConduit() +{ + FUNCTIONSETUP; +} + + +bool DOCConduit::isCorrectDBTypeCreator(DBInfo dbinfo) { + return dbinfo.type == dbtype() && dbinfo.creator == dbcreator(); +} +const unsigned long DOCConduit::dbtype() { + return get_long(DOCConduitFactory::dbDOCtype); +} +const unsigned long DOCConduit::dbcreator() { + return get_long(DOCConduitFactory::dbDOCcreator); +} + + + +/********************************************************************* + L O A D I N G T H E D A T A + *********************************************************************/ + + + +void DOCConduit::readConfig() +{ + FUNCTIONSETUP; + DOCConduitSettings::self()->readConfig(); + + eConflictResolution = (enum eSyncDirectionEnum) (DOCConduitSettings::conflictResolution() ); + fTXTBookmarks = DOCConverter::eBmkNone; + if ( DOCConduitSettings::convertBookmarks() ) + { + if ( DOCConduitSettings::bmkFileBookmarks() ) + fTXTBookmarks |= DOCConverter::eBmkFile; + if ( DOCConduitSettings::inlineBookmarks() ) + fTXTBookmarks |= DOCConverter::eBmkInline; + if ( DOCConduitSettings::endtagBookmarks() ) + fTXTBookmarks |= DOCConverter::eBmkEndtags; + } + + eSyncDirection = (enum eSyncDirectionEnum)(DOCConduitSettings::syncDirection() ); + +#ifdef DEBUG + DEBUGKPILOT << fname + << ": Settings " + << " tXTDirectory=" << DOCConduitSettings::tXTDirectory() + << " pDBDirectory=" << DOCConduitSettings::pDBDirectory() + << " keepPDBLocally=" << DOCConduitSettings::keepPDBsLocally() + << " eConflictResolution=" << eConflictResolution + << " tXTBookmarks=" << fTXTBookmarks + << " pDBBookmarks=" << DOCConduitSettings::bookmarksToPC() + << " compress=" << DOCConduitSettings::compress() + << " eSyncDirection=" << eSyncDirection << endl; +#endif +} + + + +bool DOCConduit::pcTextChanged(TQString txtfn) +{ + FUNCTIONSETUP; + // How do I find out if a text file has changed shince we last synced it?? + // Use KMD5 for now. If I realize it is too slow, then I have to go back to comparing modification times + // if there is no config setting yet, assume the file has been changed. the md5 sum will be written to the config file after the sync. + TQString oldDigest=DOCConduitSettings::self()->config()->readEntry(txtfn); + if (oldDigest.length()<=0) + { + return true; + } +#ifdef DEBUG + DEBUGKPILOT<<"Old digest is "<readRecordByIndex(0); + PilotDOCHead docHeader(firstRec); + KPILOT_DELETE(firstRec); + + int storyRecs = docHeader.numRecords; + + // determine the index of the next modified record (does it lie + // beyond the actual text records?) + int modRecInd=-1; + PilotRecord*modRec=docdb->readNextModifiedRec(&modRecInd); +#ifdef DEBUG + DEBUGKPILOT<<"Index of first changed record: "<readNextModifiedRec(&modRecInd); +#ifdef DEBUG + DEBUGKPILOT<<"Reread Index of first changed records: "<= 0) { +#ifdef DEBUG + DEBUGKPILOT<<"Handheld side has changed, condition="<< + ((!DOCConduitSettings::ignoreBmkChanges()) || (modRecInd <= storyRecs))<deleteDatabase() !=0 ) { + WARNINGKPILOT << "Unable to delete database " << sinfo.dbinfo.name << " on the PC" << endl; + } + KPILOT_DELETE(database); + } + } + if (!DOCConduitSettings::localSync()) { + PilotDatabase *database=deviceLink()->database( sinfo.dbinfo.name ); + if ( database->deleteDatabase() !=0 ) { + WARNINGKPILOT << "Unable to delete database " << sinfo.dbinfo.name << " from the handheld" << endl; + } + KPILOT_DELETE(database); + } + return true; + } + // preSyncAction should initialize the custom databases/files for the + // specific action chosen for this db and return a pointer to a docDBInfo + // instance which points either to a local database or a database on the handheld. + PilotDatabase *database = preSyncAction(sinfo); + + if (database && ( !database->isOpen() ) ) { +#ifdef DEBUG + DEBUGKPILOT<<"Database "<createDatabase(dbcreator(), dbtype()) ) { +#ifdef DEBUG + DEBUGKPILOT<<"Failed"<isOpen()) { + DOCConverter docconverter; + connect(&docconverter, TQT_SIGNAL(logError(const TQString &)), TQT_SIGNAL(logError(const TQString &))); + connect(&docconverter, TQT_SIGNAL(logMessage(const TQString &)), TQT_SIGNAL(logMessage(const TQString &))); + + docconverter.setTXTpath( DOCConduitSettings::tXTDirectory(), sinfo.txtfilename ); + docconverter.setPDB(database); + docconverter.setCompress(DOCConduitSettings::compress()); + + switch (sinfo.direction) { + case eSyncPDAToPC: + docconverter.setBookmarkTypes(DOCConduitSettings::bookmarksToPC()); + res = docconverter.convertPDBtoTXT(); + break; + case eSyncPCToPDA: + docconverter.setBookmarkTypes(fTXTBookmarks); + res = docconverter.convertTXTtoPDB(); + break; + default: + break; + } + + // Now calculate the md5 checksum of the PC text and write it to the config file + if (res) + { + KMD5 docmd5; + TQFile txtfile(docconverter.txtFilename()); + if (txtfile.open(IO_ReadOnly)) { + docmd5.update(txtfile); + TQString thisDigest(docmd5.hexDigest() /* .data() */); + DOCConduitSettings::self()->config()->writeEntry(docconverter.txtFilename(), thisDigest); + DOCConduitSettings::self()->config()->sync(); +#ifdef DEBUG + DEBUGKPILOT<<"MD5 Checksum of the text "<findDatabase(NULL, &dbinfo, dbnr, dbtype(), dbcreator() /*, cardno */ ) < 0) + { + // no more databases available, so check for PC->Palm sync + TQTimer::singleShot(0, this, TQT_SLOT(syncNextTXT())); + return; + } + dbnr=dbinfo.index+1; +#ifdef DEBUG + DEBUGKPILOT<<"Next Palm database to sync: "<Palm sync + TQTimer::singleShot(0, this, TQT_SLOT(checkDeletedDocs())); + return; + } + + // Walk through all files in the pdb directory and check if it has already been synced. + // if docnames isn't initialized, get a list of all *.pdb files in DOCConduitSettings::pDBDirectory() + if (docnames.isEmpty()/* || dociterator==docnames.end() */) { + docnames=TQDir(DOCConduitSettings::pDBDirectory(), CSL1("*.pdb")).entryList() ; + dociterator=docnames.begin(); + } + if (dociterator==docnames.end()) { + // no more databases available, so start the conflict resolution and then the actual sync proces + docnames.clear(); + TQTimer::singleShot(0, this, TQT_SLOT(checkDeletedDocs())); + return; + } + + TQString fn=(*dociterator); + + TQDir dr(DOCConduitSettings::pDBDirectory()); + TQFileInfo fl(dr, fn ); + TQString pdbfilename=fl.absFilePath(); + ++dociterator; + + // Get the doc title and check if it has already been synced (in the synced docs list of in fDBNames to be synced) + // If the doc title doesn't appear in either list, install it to the Handheld, and add it to the list of dbs to be synced. + TQString dbname=fl.baseName(TRUE).left(30); + if (!fDBNames.tqcontains(dbname) && !fDBListSynced.tqcontains(dbname)) { + if (fHandle->installFiles(pdbfilename, false)) { + DBInfo dbinfo; + // Include all "extensions" except the last. This allows full stops inside the database name (e.g. abbreviations) + // first fill everything with 0, so we won't have a buffer overflow. + memset(&dbinfo.name[0], 0, 33); + strncpy(&dbinfo.name[0], dbname.latin1(), 30); + + docSyncInfo syncInfo(dbname, constructTXTFileName(dbname), pdbfilename, eSyncNone); + syncInfo.dbinfo=dbinfo; + needsSync(syncInfo); + fSyncInfoList.append(syncInfo); + fDBNames.append(dbname); + } else { +#ifdef DEBUG + DEBUGKPILOT<<"Could not install database "<hasConflicts); + if (show) { + if (!dlg || !dlg->exec() ) { + KPILOT_DELETE(dlg) + emit logMessage(i18n("Sync aborted by user.")); + TQTimer::singleShot(0, this, TQT_SLOT(cleanup())); + return; + } + } + KPILOT_DELETE(dlg) + + + // fDBNames will be filled with the names of the databases that are actually synced (not deleted), so I can write the list to the config file + fDBNames.clear(); + fSyncInfoListIterator=fSyncInfoList.begin(); + TQTimer::singleShot(0,this, TQT_SLOT(syncDatabases())); + return; +} + + + +void DOCConduit::syncDatabases() { + FUNCTIONSETUP; + if (fSyncInfoListIterator==fSyncInfoList.end()) { + // We're done, so clean up + TQTimer::singleShot(0, this, TQT_SLOT(cleanup())); + return; + } + + docSyncInfo sinfo=(*fSyncInfoListIterator); + ++fSyncInfoListIterator; + + switch (sinfo.direction) { + case eSyncConflict: +#ifdef DEBUG + DEBUGKPILOT<<"Entry "<database( dbname ); + } +} + + +bool DOCConduit::needsSync(docSyncInfo &sinfo) +{ + FUNCTIONSETUP; + sinfo.direction = eSyncNone; + + PilotDatabase*docdb=openDOCDatabase(TQString::tqfromLatin1(sinfo.dbinfo.name)); + if (!fDBListSynced.tqcontains(sinfo.handheldDB)) { + // the database wasn't included on last sync, so it has to be new. +#ifdef DEBUG + DEBUGKPILOT<<"Database "<HH HH->PC + ----------------------------------------- + N - | P P D + - N | H D H + N N | C P H + */ + + if (TQFile::exists(sinfo.txtfilename)) sinfo.fPCStatus=eStatNew; + else sinfo.fPCStatus=eStatDoesntExist; + if (docdb && docdb->isOpen()) sinfo.fPalmStatus=eStatNew; + else sinfo.fPalmStatus=eStatDoesntExist; + KPILOT_DELETE(docdb); + + switch (eSyncDirection) { + case eSyncPDAToPC: + if (sinfo.fPalmStatus==eStatDoesntExist) + sinfo.direction=eSyncDelete; + else sinfo.direction=eSyncPDAToPC; + break; + case eSyncPCToPDA: + if (sinfo.fPCStatus==eStatDoesntExist) + sinfo.direction=eSyncDelete; + else sinfo.direction=eSyncPCToPDA; + break; + case eSyncNone: // means actually both directions! + if (sinfo.fPCStatus==eStatNew) { + if (sinfo.fPalmStatus==eStatNew) sinfo.direction=eSyncConflict; + else sinfo.direction=eSyncPCToPDA; + } else { + if (sinfo.fPalmStatus==eStatNew) sinfo.direction=eSyncPDAToPC; + else { + sinfo.direction=eSyncNone; +#ifdef DEBUG + DEBUGKPILOT<<"I'm supposed to find a sync direction, but the "<< + " text "<isOpen()) sinfo.fPalmStatus=eStatDeleted; + else if (hhTextChanged(docdb)) { +#ifdef DEBUG + DEBUGKPILOT<<"Handheld side has changed!"<HH HH->PC + ----------------------------------------- + - - | - - - + C - | P P H + - C | H P H + C C | C P H + D - | D D H + - D | D P D + D D | D D D + ----------------------------------------- + C D | C P D + D C | C D H + */ + + + if (sinfo.fPCStatus == eStatNone && sinfo.fPalmStatus==eStatNone) { +#ifdef DEBUG + DEBUGKPILOT<<"Nothing has changed, not need for a sync."<HH or HH->PC) + // should be done, check if the DB was deleted or if we are supposed + // to sync that direction + + if (eSyncDirection==eSyncPCToPDA) { + if (sinfo.fPCStatus==eStatDeleted) sinfo.direction=eSyncDelete; + else sinfo.direction=eSyncPCToPDA; + return true; + } + if (eSyncDirection==eSyncPDAToPC) { + if (sinfo.fPalmStatus==eStatDeleted) sinfo.direction=eSyncDelete; + else sinfo.direction=eSyncPDAToPC; + return true; + } + + + // --------------------------------------------------------------- + // Finally, do the normal case, where both directions are possible + // --------------------------------------------------------------- + + + // if either is deleted, and the other is not changed, delete + if ( ((sinfo.fPCStatus==eStatDeleted) && (sinfo.fPalmStatus!=eStatChanged)) || + ((sinfo.fPalmStatus==eStatDeleted) && (sinfo.fPCStatus!=eStatChanged)) ) + { +#ifdef DEBUG + DEBUGKPILOT<<"DB was deleted on one side and not changed on " + "the other -> Delete it."<retrieveDatabase(sinfo.pdbfilename, &dbinfo) ) + { + WARNINGKPILOT << "Unable to retrieve database " << dbinfo.name << + " from the handheld into " << sinfo.pdbfilename << "." << endl; + return 0L; + } + } + break; + case eSyncPCToPDA: + if (DOCConduitSettings::keepPDBsLocally()) + { + // make sure the dir for the local db really exists! + TQDir dir(DOCConduitSettings::pDBDirectory()); + if (!dir.exists()) + { + dir.mkdir(dir.absPath()); + } + } + break; + default: + break; + } + if (DOCConduitSettings::keepPDBsLocally()) + { + return new PilotLocalDatabase(DOCConduitSettings::pDBDirectory(), + TQString::tqfromLatin1(dbinfo.name), false); + } + else + { + return deviceLink()->database(TQString::tqfromLatin1(dbinfo.name)); + } +} + + +// res gives us information whether the sync worked and the db might need to be +// transferred to the handheld or not (and we just need to clean up the mess) +bool DOCConduit::postSyncAction(PilotDatabase * database, + docSyncInfo &sinfo, bool res) +{ + FUNCTIONSETUP; + bool rs = true; + + switch (sinfo.direction) + { + case eSyncPDAToPC: + // also reset the sync flags on the handheld +#ifdef DEBUG + DEBUGKPILOT<<"Resetting sync flags for database " + <database( + TQString::tqfromLatin1(sinfo.dbinfo.name)); +#ifdef DEBUG + DEBUGKPILOT<<"Middle 1 Resetting sync flags for database " + <resetSyncFlags(); + KPILOT_DELETE(db); + } + } +#ifdef DEBUG + DEBUGKPILOT<<"End Resetting sync flags for database " + <(database); + if (localdb) + { +#ifdef DEBUG + DEBUGKPILOT<<"Installing file "<dbPathName()<<" (" + <dbPathName(); + // This deletes localdb as well, which is just a cast from database + KPILOT_DELETE(database); + if (!fHandle->installFiles(dbpathname, false)) + { + rs = false; +#ifdef DEBUG + DEBUGKPILOT<<"Could not install the database "<writeConfig(); + + emit syncDone(this); +} + -- cgit v1.2.1