kpilot

memofile-conduit.cc

Go to the documentation of this file.
00001 /* memofile-conduit.cc          KPilot
00002 **
00003 ** Copyright (C) 2004-2007 by Jason 'vanRijn' Kasper
00004 **
00005 ** This file does the actual conduit work.
00006 */
00007 
00008 /*
00009 ** This program is free software; you can redistribute it and/or modify
00010 ** it under the terms of the GNU Lesser General Public License as published by
00011 ** the Free Software Foundation; either version 2.1 of the License, or
00012 ** (at your option) any later version.
00013 **
00014 ** This program is distributed in the hope that it will be useful,
00015 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00017 ** GNU Lesser General Public License for more details.
00018 **
00019 ** You should have received a copy of the GNU Lesser General Public License
00020 ** along with this program in a file called COPYING; if not, write to
00021 ** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
00022 ** MA 02110-1301, USA.
00023 */
00024 
00025 /*
00026 ** Bug reports and questions can be sent to kde-pim@kde.org
00027 */
00028 
00029 
00030 #include "options.h"
00031 
00032 // Only include what we really need:
00033 // First UNIX system stuff, then std C++,
00034 // then Qt, then KDE, then local includes.
00035 //
00036 //
00037 
00038 #include <time.h>  // required by pilot-link includes
00039 
00040 #include <pi-memo.h>
00041 
00042 #include "pilotMemo.h"
00043 
00044 #include <qfile.h>
00045 #include <qdir.h>
00046 #include <qtextcodec.h>
00047 
00048 #include <kconfig.h>
00049 #include <kdebug.h>
00050 
00051 #include "pilotRecord.h"
00052 #include "pilotSerialDatabase.h"
00053 #include "memofile-factory.h"
00054 #include "memofile-conduit.h"
00055 #include "memofileSettings.h"
00056 
00057 
00061 MemofileConduit::MemofileConduit(KPilotLink *d,
00062                                  const char *n,
00063                                  const QStringList &l) :
00064         ConduitAction(d,n,l),
00065         _DEFAULT_MEMODIR(QDir::homeDirPath() + CSL1("/MyMemos")),
00066         fMemoAppInfo(0L),
00067         _memofiles(0L)
00068 {
00069     FUNCTIONSETUP;
00070     fConduitName=i18n("Memofile");
00071     fMemoList.setAutoDelete(true);
00072 }
00073 
00074 MemofileConduit::~MemofileConduit()
00075 {
00076     FUNCTIONSETUP;
00077     KPILOT_DELETE(_memofiles);
00078 }
00079 
00080 /* virtual */ bool MemofileConduit::exec()
00081 {
00082     FUNCTIONSETUP;
00083 
00084     setFirstSync( false );
00085     // try new format first...
00086     // DEBUGKPILOT << fname << ": trying new format database first." << endl;
00087     bool _open = false;
00088     /*
00089     _open = openDatabases(CSL1("MemosDB-PMem"));
00090     if(!_open) {
00091         DEBUGKPILOT << fname << ": unable to open new format database. trying old one." << endl;
00092     */
00093         _open = openDatabases(CSL1("MemoDB"));
00094     /*
00095     } else {
00096         DEBUGKPILOT << fname << ": able to open new format database." << endl;
00097     }
00098     */
00099 
00100     if(!_open) {
00101         emit logError(i18n("Unable to open the memo databases on the handheld."));
00102         DEBUGKPILOT << fname << ": unable to open new or old format database." << endl;
00103         return false;
00104     }
00105 
00106     readConfig();
00107 
00108     if (! initializeFromPilot()) {
00109         emit logError(i18n("Cannot initialize from pilot."));
00110         return false;
00111     }
00112 
00113     _memofiles = new Memofiles(fCategories, *fMemoAppInfo,
00114         _memo_directory, *fCtrHH);
00115     if (! _memofiles || ! _memofiles->isReady()) {
00116         emit logError(i18n("Cannot initialize the memo files from disk."));
00117         return false;
00118     }
00119 
00120     fCtrPC->setStartCount(_memofiles->count());
00121 
00122     setFirstSync( _memofiles->isFirstSync() );
00123     addSyncLogEntry(i18n(" Syncing with %1.").arg(_memo_directory));
00124 
00125     if ( (syncMode() == SyncAction::SyncMode::eCopyHHToPC) || _memofiles->isFirstSync() ) {
00126         addSyncLogEntry(i18n(" Copying Pilot to PC..."));
00127         DEBUGKPILOT << fname << ": copying Pilot to PC." << endl;
00128         copyHHToPC();
00129     } else if ( syncMode() == SyncAction::SyncMode::eCopyPCToHH ) {
00130         DEBUGKPILOT << fname << ": copying PC to Pilot." << endl;
00131         addSyncLogEntry(i18n(" Copying PC to Pilot..."));
00132         copyPCToHH();
00133     } else {
00134         DEBUGKPILOT << fname << ": doing regular sync." << endl;
00135         addSyncLogEntry(i18n(" Doing regular sync..."));
00136         sync();
00137     }
00138 
00139     cleanup();
00140 
00141     return delayDone();
00142 }
00143 
00144 bool MemofileConduit::readConfig()
00145 {
00146     FUNCTIONSETUP;
00147 
00148     QString dir(MemofileConduitSettings::directory());
00149     if (dir.isEmpty()) {
00150         dir = _DEFAULT_MEMODIR;
00151 
00152         DEBUGKPILOT << fname
00153             << ": no directory given to us.  defaulting to: ["
00154             << _DEFAULT_MEMODIR
00155             << "]" << endl;
00156     }
00157 
00158     _memo_directory = dir;
00159     _sync_private = MemofileConduitSettings::syncPrivate();
00160 
00161 
00162     DEBUGKPILOT << fname
00163         << ": Settings... "
00164         << "  directory: [" << _memo_directory
00165         << "], first sync: [" << isFirstSync()
00166         << "], sync private: [" << _sync_private
00167         << "]" << endl;
00168 
00169     return true;
00170 
00171 }
00172 
00173 bool MemofileConduit::setAppInfo()
00174 {
00175     FUNCTIONSETUP;
00176 
00177     // reset our category mapping from the filesystem
00178     MemoCategoryMap map = _memofiles->readCategoryMetadata();
00179 
00180     if (map.count() <=0) {
00181         DEBUGKPILOT << fname
00182             << ": category metadata map is empty, nothing to do." << endl;
00183         return true;
00184     }
00185 
00186     fCategories = map;
00187 
00188     for (unsigned int i = 0; i < Pilot::CATEGORY_COUNT; i++)
00189     {
00190         if (fCategories.contains(i)) {
00191             fMemoAppInfo->setCategoryName(i,fCategories[i]);
00192         }
00193     }
00194 
00195     if (fDatabase)
00196     {
00197         fMemoAppInfo->writeTo(fDatabase);
00198     }
00199     if (fLocalDatabase)
00200     {
00201         fMemoAppInfo->writeTo(fLocalDatabase);
00202     }
00203 
00204     return true;
00205 }
00206 
00207 bool MemofileConduit::getAppInfo()
00208 {
00209     FUNCTIONSETUP;
00210 
00211     KPILOT_DELETE(fMemoAppInfo);
00212     fMemoAppInfo = new PilotMemoInfo(fDatabase);
00213     fMemoAppInfo->dump();
00214     return true;
00215 }
00216 
00217 
00222 bool MemofileConduit::initializeFromPilot()
00223 {
00224 
00225     if (!getAppInfo()) return false;
00226 
00227     if (!loadPilotCategories()) return false;
00228 
00229     return true;
00230 }
00231 
00232 bool MemofileConduit::loadPilotCategories()
00233 {
00234     FUNCTIONSETUP;
00235 
00236     fCategories.clear();
00237 
00238     QString _category_name;
00239     int _category_id=0;
00240     int _category_num=0;
00241 
00242     for (unsigned int i = 0; i < Pilot::CATEGORY_COUNT; i++)
00243     {
00244         _category_name = fMemoAppInfo->categoryName(i);
00245         if (!_category_name.isEmpty())
00246         {
00247             _category_name = Memofiles::sanitizeName( _category_name );
00248             _category_id   = fMemoAppInfo->categoryInfo()->ID[i];
00249             _category_num  = i;
00250             fCategories[_category_num] = _category_name;
00251 
00252             DEBUGKPILOT << fname
00253                 << ": Category #"
00254                 << _category_num
00255                 << " has ID "
00256                 << _category_id
00257                 << " and name "
00258                 <<_category_name << endl;
00259         }
00260     }
00261     return true;
00262 }
00263 
00267 void MemofileConduit::getAllFromPilot()
00268 {
00269     FUNCTIONSETUP;
00270 
00271     DEBUGKPILOT << fname
00272         << ": Database has " << fDatabase->recordCount()
00273         << " records." << endl;
00274 
00275     fMemoList.clear();
00276 
00277     int currentRecord = 0;
00278     PilotRecord *pilotRec;
00279     PilotMemo *memo = 0;
00280 
00281     while ((pilotRec = fDatabase->readRecordByIndex(currentRecord)) != NULL) {
00282         if ((!pilotRec->isSecret()) || _sync_private) {
00283             memo = new PilotMemo(pilotRec);
00284             fMemoList.append(memo);
00285 
00286             DEBUGKPILOT << fname
00287                 << ": Added memo: ["
00288                 << currentRecord
00289                 << "], id: ["
00290                 << memo->id()
00291                 << "], category: ["
00292                 << fCategories[memo->category()]
00293                 << "], title: ["
00294                 << memo->getTitle()
00295                 << "]" << endl;
00296         } else {
00297             DEBUGKPILOT << fname
00298                 << ": Skipped secret record: ["
00299                 << currentRecord
00300                 << "], title: ["
00301                 << memo->getTitle()
00302                 << "]" << endl;
00303         }
00304 
00305         KPILOT_DELETE(pilotRec);
00306 
00307         currentRecord++;
00308     }
00309 
00310     DEBUGKPILOT << fname
00311         << ": read: [" << fMemoList.count()
00312         << "] records from palm." << endl;
00313 }
00314 
00318 void MemofileConduit::getModifiedFromPilot()
00319 {
00320     FUNCTIONSETUP;
00321 
00322     fMemoList.clear();
00323 
00324     int currentRecord = 0;
00325     PilotRecord *pilotRec;
00326     PilotMemo *memo = 0;
00327 
00328     while ((pilotRec = fDatabase->readNextModifiedRec()) != NULL) {
00329         memo = new PilotMemo(pilotRec);
00330         // we are syncing to both our filesystem and to the local
00331         // database, so take care of the local database here
00332         if (memo->isDeleted()) {
00333             fLocalDatabase->deleteRecord(memo->id());
00334         } else {
00335             fLocalDatabase->writeRecord(pilotRec);
00336         }
00337 
00338         if ((!pilotRec->isSecret()) || _sync_private) {
00339             fMemoList.append(memo);
00340 
00341             DEBUGKPILOT << fname
00342                 << ": modified memo id: ["
00343                 << memo->id()
00344                 << "], title: ["
00345                 << memo->getTitle()
00346                 << "]" << endl;
00347         } else {
00348             DEBUGKPILOT << fname
00349                 << ": skipped secret modified record id: ["
00350                 << memo->id()
00351                 << "], title: ["
00352                 << memo->getTitle()
00353                 << "]" << endl;
00354         }
00355 
00356         KPILOT_DELETE(pilotRec);
00357 
00358         currentRecord++;
00359     }
00360 
00361     DEBUGKPILOT << fname
00362         << ": read: [" << fMemoList.count()
00363         << "] modified records from palm." << endl;
00364 }
00365 
00366 
00367 /* slot */ void MemofileConduit::process()
00368 {
00369     FUNCTIONSETUP;
00370 
00371     DEBUGKPILOT << fname << ": Now in state " << fActionStatus << endl;
00372 }
00373 
00374 
00375 void MemofileConduit::listPilotMemos()
00376 {
00377     FUNCTIONSETUP;
00378 
00379     PilotMemo *memo;
00380     for ( memo = fMemoList.first(); memo; memo = fMemoList.next() ) {
00381         QString _category_name = fCategories[memo->category()];
00382 
00383         DEBUGKPILOT << fConduitName
00384             << ": listing record id: [" << memo->id()
00385             << "] category id: [" << memo->category()
00386             << "] category name: [" << _category_name
00387             << "] title: [" << memo->getTitle()
00388             << "]" << endl;
00389     }
00390 }
00391 
00392 bool MemofileConduit::copyHHToPC()
00393 {
00394     FUNCTIONSETUP;
00395 
00396     getAllFromPilot();
00397 
00398     _memofiles->eraseLocalMemos();
00399 
00400     _memofiles->setPilotMemos(fMemoList);
00401 
00402     _memofiles->save();
00403 
00404     return true;
00405 
00406 }
00407 
00408 bool MemofileConduit::copyPCToHH()
00409 {
00410     FUNCTIONSETUP;
00411 
00412     // set category info from the filesystem, if we can.
00413     // Note: This will reset both fCategories and fMemoAppInfo, so
00414     //       after this, we need to reinitialize our memofiles object...
00415     setAppInfo();
00416 
00417     // re-create our memofiles helper...
00418     KPILOT_DELETE(_memofiles);
00419     _memofiles = new Memofiles(fCategories, *fMemoAppInfo,
00420         _memo_directory, *fCtrHH);
00421 
00422     _memofiles->load(true);
00423 
00424     QPtrList<Memofile> memofiles = _memofiles->getAll();
00425 
00426     Memofile * memofile;
00427 
00428     for ( memofile = memofiles.first(); memofile; memofile = memofiles.next() ) {
00429         writeToPilot(memofile);
00430     }
00431 
00432     _memofiles->save();
00433 
00434     // now that we've copied from the PC to our handheld, remove anything extra from the
00435     // handheld...
00436     deleteUnsyncedHHRecords();
00437 
00438     return true;
00439 
00440 }
00441 
00442 void MemofileConduit::deleteUnsyncedHHRecords()
00443 {
00444     FUNCTIONSETUP;
00445     if ( syncMode()==SyncMode::eCopyPCToHH )
00446     {
00447         Pilot::RecordIDList ids=fDatabase->idList();
00448         Pilot::RecordIDList::iterator it;
00449         for ( it = ids.begin(); it != ids.end(); ++it )
00450         {
00451             if (!_memofiles->find(*it))
00452             {
00453                 DEBUGKPILOT << fname
00454                     << "Deleting record with ID "<< *it <<" from handheld "
00455                     << "(is not on PC, and syncing with PC->HH direction)"
00456                     << endl;
00457                 fDatabase->deleteRecord(*it);
00458                 fLocalDatabase->deleteRecord(*it);
00459             }
00460         }
00461     }
00462 }
00463 
00464 int MemofileConduit::writeToPilot(Memofile * memofile)
00465 {
00466     FUNCTIONSETUP;
00467 
00468     int oldid = memofile->id();
00469 
00470     PilotRecord *r = memofile->pack();
00471 
00472     if (!r) {
00473         DEBUGKPILOT << fname
00474             << ": ERROR: [" << memofile->toString()
00475             << "] could not be written to the pilot."
00476             << endl;
00477         return -1;
00478     }
00479 
00480     int newid = fDatabase->writeRecord(r);
00481     fLocalDatabase->writeRecord(r);
00482 
00483     KPILOT_DELETE(r);
00484 
00485     memofile->setID(newid);
00486 
00487     QString status;
00488     if (oldid <=0) {
00489         fCtrHH->created();
00490         status = "new to pilot";
00491     } else {
00492         fCtrHH->updated();
00493         status = "updated";
00494     }
00495 
00496     DEBUGKPILOT << fname
00497         << ": memofile: [" << memofile->toString()
00498         << "] written to the pilot, [" << status << "]."
00499         << endl;
00500 
00501     return newid;
00502 }
00503 
00504 void MemofileConduit::deleteFromPilot(PilotMemo * memo)
00505 {
00506     FUNCTIONSETUP;
00507 
00508     PilotRecord *r = memo->pack();
00509     if (r) {
00510         r->setDeleted(true);
00511         fDatabase->writeRecord(r);
00512         fLocalDatabase->writeRecord(r);
00513     }
00514     KPILOT_DELETE(r);
00515 
00516     fCtrHH->deleted();
00517 
00518     DEBUGKPILOT << fname
00519         << ": memo: [" << memo->getTitle()
00520         << "] deleted from the pilot."
00521         << endl;
00522 }
00523 
00524 bool MemofileConduit::sync()
00525 {
00526     FUNCTIONSETUP;
00527 
00528     _memofiles->load(false);
00529 
00530     getModifiedFromPilot();
00531 
00532     PilotMemo *memo;
00533     for ( memo = fMemoList.first(); memo; memo = fMemoList.next() ) {
00534         _memofiles->addModifiedMemo(memo);
00535     }
00536 
00537     QPtrList<Memofile> memofiles = _memofiles->getModified();
00538 
00539     Memofile *memofile;
00540     for ( memofile = memofiles.first(); memofile; memofile = memofiles.next() ) {
00541         if (memofile->isDeleted()) {
00542             deleteFromPilot(memofile);
00543         } else {
00544             writeToPilot(memofile);
00545         }
00546     }
00547 
00548     _memofiles->save();
00549 
00550     return true;
00551 }
00552 
00553 void MemofileConduit::cleanup()
00554 {
00555     FUNCTIONSETUP;
00556 
00557     fDatabase->resetSyncFlags();
00558     fDatabase->cleanup();
00559     fLocalDatabase->resetSyncFlags();
00560     fLocalDatabase->cleanup();
00561 
00562     fCtrPC->setEndCount(_memofiles->count());
00563 }
00564 
00565 
00566 #include "memofile-conduit.moc"
00567