kpilot Library API Documentation

pilotLocalDatabase.cc

00001 /* pilotLocalDatabase.cc                        KPilot
00002 **
00003 ** Copyright (C) 1998-2001 by Dan Pilone
00004 **
00005 ** This defines an interface to Pilot databases on the local disk.
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., 59 Temple Place, Suite 330, Boston,
00022 ** MA 02111-1307, USA.
00023 */
00024 
00025 /*
00026 ** Bug reports and questions can be sent to kde-pim@kde.org
00027 */
00028 
00029 
00030 static const char *pilotlocaldatabase_id =
00031         "$Id: pilotLocalDatabase.cc,v 1.7.4.8 2003/04/12 14:40:19 adridg Exp $";
00032 
00033 #include "options.h"
00034 
00035 #include <stdio.h>
00036 #include <unistd.h>
00037 
00038 #include <iostream>
00039 
00040 #include <qstring.h>
00041 #include <qfile.h>
00042 #include <qregexp.h>
00043 #include <qdatetime.h>
00044 
00045 #include <kdebug.h>
00046 #include <kglobal.h>
00047 #include <kstandarddirs.h>
00048 
00049 
00050 #include "pilotLocalDatabase.h"
00051 
00052 PilotLocalDatabase::PilotLocalDatabase(const QString & path,
00053         const QString & dbName, bool useDefaultPath,
00054         QObject *p, const char *n) :
00055         PilotDatabase(p,n),
00056         fPathName(path),
00057         fDBName(dbName),
00058         fAppInfo(0L),
00059         fAppLen(0),
00060         fNumRecords(0),
00061         fCurrentRecord(0),
00062         fPendingRec(-1)
00063 {
00064         FUNCTIONSETUP;
00065         fixupDBName();
00066         openDatabase();
00067 
00068         if (!isDBOpen() && useDefaultPath)
00069         {
00070                 if (fPathBase && !fPathBase->isEmpty())
00071                 {
00072                         fPathName = *fPathBase;
00073                 }
00074                 else
00075                 {
00076                         fPathName = KGlobal::dirs()->saveLocation("data",
00077                                 CSL1("kpilot/DBBackup/"));
00078                 }
00079                 fixupDBName();
00080                 openDatabase();
00081                 if (!isDBOpen())
00082                         fPathName=path;
00083         }
00084 
00085         /* NOTREACHED */
00086         (void) pilotlocaldatabase_id;
00087 }
00088 
00089 PilotLocalDatabase::PilotLocalDatabase(const QString & dbName,
00090         QObject *p, const char *n) :
00091         PilotDatabase(p,n),
00092         fPathName(QString::null),
00093         fDBName(dbName),
00094         fAppInfo(0L),
00095         fAppLen(0),
00096         fNumRecords(0),
00097         fCurrentRecord(0),
00098         fPendingRec(-1)
00099 {
00100         FUNCTIONSETUP;
00101         if (fPathBase && !fPathBase->isEmpty())
00102         {
00103                 fPathName = *fPathBase;
00104         }
00105         else
00106         {
00107                 fPathName = KGlobal::dirs()->saveLocation("data",
00108                         CSL1("kpilot/DBBackup/"));
00109         }
00110 
00111         fixupDBName();
00112         openDatabase();
00113 }
00114 
00115 
00116 PilotLocalDatabase::~PilotLocalDatabase()
00117 {
00118         FUNCTIONSETUP;
00119         int i;
00120 
00121         closeDatabase();
00122         delete[]fAppInfo;
00123         for (i = 0; i < fNumRecords; i++)
00124         {
00125                 delete fRecords[i];
00126         }
00127 }
00128 
00129 // Changes any forward slashes to underscores
00130 void PilotLocalDatabase::fixupDBName()
00131 {
00132         FUNCTIONSETUP;
00133 #if QT_VERSION < 0x30100
00134         fDBName = fDBName.replace(QRegExp(CSL1("/")),CSL1("_"));
00135 #else
00136         // Actually, I don't know if this char-replace
00137         // is more efficient than the QString one.
00138         fDBName = fDBName.replace('/', CSL1("_"));
00139 #endif
00140 }
00141 
00142 bool PilotLocalDatabase::createDatabase(long creator, long type, int, int flags, int version)
00143 {
00144         FUNCTIONSETUP;
00145 
00146         // if the database is already open, we cannot create it again. How about completely resetting it? (i.e. deleting it and the createing it again)
00147         if (isDBOpen()) {
00148 #ifdef DEBUG
00149                 DEBUGCONDUIT<<"Database "<<fDBName<<" already open. Cannot recreate it."<<endl;
00150 #endif
00151                 return true;
00152         }
00153 
00154 #ifdef DEBUG
00155         DEBUGCONDUIT<<"Creating database "<<fDBName<<endl;
00156 #endif
00157 
00158         // Database names seem to be latin1.
00159         memcpy(&fDBInfo.name[0], fDBName.latin1(), 34*sizeof(char));
00160         fDBInfo.creator=creator;
00161         fDBInfo.type=type;
00162         fDBInfo.more=0;
00163         fDBInfo.flags=flags;
00164         fDBInfo.miscFlags=0;
00165         fDBInfo.version=version;
00166         fDBInfo.modnum=0;
00167         fDBInfo.index=0;
00168 
00169 #if QT_VERSION < 0x30100
00170 #define TODAY_T epoch.secsTo(QDateTime::currentDateTime())
00171         QDateTime epoch;
00172         epoch.setTime_t((time_t)0);
00173 #else
00174 #define TODAY_T (QDateTime::currentDateTime()).toTime_t()
00175 #endif
00176         fDBInfo.createDate=TODAY_T;
00177         fDBInfo.modifyDate=TODAY_T;
00178         fDBInfo.backupDate=TODAY_T;
00179 #undef TODAY_T
00180 
00181 
00182         delete[] fAppInfo;
00183         fAppInfo=0L;
00184         fAppLen=0;
00185 
00186         for (int i=0; i<fNumRecords; i++) {
00187                 KPILOT_DELETE(fRecords[i]);
00188                 fRecords[i]=NULL;
00189         }
00190         fNumRecords=0;
00191         fCurrentRecord=0;
00192         fPendingRec=0;
00193 
00194         // TODO: Do I have to open it explicitely???
00195         setDBOpen(true);
00196         return true;
00197 }
00198 
00199 int PilotLocalDatabase::deleteDatabase()
00200 {
00201         FUNCTIONSETUP;
00202         if (isDBOpen()) closeDatabase();
00203 
00204         QString dbpath=dbPathName();
00205         QFile fl(dbpath);
00206         if (QFile::remove(dbPathName()))
00207                 return 0;
00208         else
00209                 return -1;
00210 }
00211 
00212 
00213 
00214 // Reads the application block info
00215 int PilotLocalDatabase::readAppBlock(unsigned char *buffer, int)
00216 {
00217         FUNCTIONSETUP;
00218 
00219         if (!isDBOpen())
00220         {
00221                 kdError() << k_funcinfo << ": DB not open!" << endl;
00222                 return -1;
00223         }
00224 
00225         memcpy((void *) buffer, fAppInfo, fAppLen);
00226         return fAppLen;
00227 }
00228 
00229 int PilotLocalDatabase::writeAppBlock(unsigned char *buffer, int len)
00230 {
00231         FUNCTIONSETUP;
00232 
00233         if (isDBOpen() == false)
00234         {
00235                 kdError() << k_funcinfo << ": DB not open!" << endl;
00236                 return -1;
00237         }
00238         delete[]fAppInfo;
00239         fAppLen = len;
00240         fAppInfo = new char[fAppLen];
00241 
00242         memcpy(fAppInfo, (void *) buffer, fAppLen);
00243         return 0;
00244 }
00245 
00246 
00247 // returns the number of records in the database
00248 int PilotLocalDatabase::recordCount()
00249 {
00250         return fNumRecords;
00251 }
00252 
00253 
00254 // Returns a QValueList of all record ids in the database.
00255 QValueList<recordid_t> PilotLocalDatabase::idList()
00256 {
00257         int idlen=recordCount();
00258         QValueList<recordid_t> idlist;
00259         if (idlen<=0) return idlist;
00260 
00261         // now create the QValue list from the idarr:
00262         for (int id=0; id<idlen; id++)
00263         {
00264                 idlist.append(fRecords[id]->getID());
00265         }
00266         return idlist;
00267 }
00268 
00269 // Reads a record from database by id, returns record length
00270 PilotRecord *PilotLocalDatabase::readRecordById(recordid_t id)
00271 {
00272         FUNCTIONSETUP;
00273 
00274         int i;
00275 
00276         fPendingRec = -1;
00277         if (isDBOpen() == false)
00278         {
00279                 DEBUGKPILOT << fDBName << ": DB not open!" << endl;
00280                 return 0L;
00281         }
00282         for (i = 0; i < fNumRecords; i++)
00283         {
00284                 if (fRecords[i]->getID() == id)
00285                 {
00286                         PilotRecord *newRecord = new PilotRecord(fRecords[i]);
00287 
00288                         return newRecord;
00289                 }
00290         }
00291         return 0L;
00292 }
00293 
00294 // Reads a record from database, returns the record length
00295 PilotRecord *PilotLocalDatabase::readRecordByIndex(int index)
00296 {
00297         FUNCTIONSETUP;
00298         fPendingRec = (-1);
00299         if (isDBOpen() == false)
00300         {
00301                 kdError() << k_funcinfo << ": DB not open!" << endl;
00302                 return 0L;
00303         }
00304         if (index >= fNumRecords)
00305                 return 0L;
00306         PilotRecord *newRecord = new PilotRecord(fRecords[index]);
00307 
00308         return newRecord;
00309 }
00310 
00311 // Reads the next record from database in category 'category'
00312 PilotRecord *PilotLocalDatabase::readNextRecInCategory(int category)
00313 {
00314         FUNCTIONSETUP;
00315         fPendingRec = -1;
00316         if (isDBOpen() == false)
00317         {
00318                 kdError() << k_funcinfo << ": DB not open!" << endl;
00319                 return 0L;
00320         }
00321         while ((fCurrentRecord < fNumRecords)
00322                 && (fRecords[fCurrentRecord]->getCat() != category))
00323         {
00324                 fCurrentRecord++;
00325         }
00326         if (fCurrentRecord == fNumRecords)
00327                 return 0L;
00328         PilotRecord *newRecord = new PilotRecord(fRecords[fCurrentRecord]);
00329 
00330         fCurrentRecord++;       // so we skip it next time
00331         return newRecord;
00332 }
00333 
00334 // Reads the next record from database that has the dirty flag set.
00335 PilotRecord *PilotLocalDatabase::readNextModifiedRec(int *ind)
00336 {
00337         FUNCTIONSETUP;
00338 
00339         if (isDBOpen() == false)
00340         {
00341                 kdError() << k_funcinfo << ": DB not open!" << endl;
00342                 return 0L;
00343         }
00344         // Should this also check for deleted?
00345         while ((fCurrentRecord < fNumRecords)
00346                 && !(fRecords[fCurrentRecord]->getAttrib() & dlpRecAttrDirty))
00347         {
00348                 fCurrentRecord++;
00349         }
00350         if (fCurrentRecord == fNumRecords)
00351                 return 0L;
00352         PilotRecord *newRecord = new PilotRecord(fRecords[fCurrentRecord]);
00353         if (ind) *ind=fCurrentRecord;
00354 
00355         fPendingRec = fCurrentRecord;   // Record which one needs the new id
00356         fCurrentRecord++;       // so we skip it next time
00357         return newRecord;
00358 }
00359 
00360 // Writes a new ID to the record specified the index.  Not supported on Serial connections
00361 recordid_t PilotLocalDatabase::writeID(PilotRecord * rec)
00362 {
00363         FUNCTIONSETUP;
00364 
00365         if (isDBOpen() == false)
00366         {
00367                 kdError() << k_funcinfo << ": DB not open!" << endl;
00368                 return 0;
00369         }
00370         if (fPendingRec == -1)
00371         {
00372                 kdError() << k_funcinfo <<
00373                         ": Last call was _NOT_ readNextModifiedRec()" << endl;
00374                 return 0;
00375         }
00376         fRecords[fPendingRec]->setID(rec->getID());
00377         fPendingRec = -1;
00378         return rec->getID();
00379 }
00380 
00381 // Writes a new record to database (if 'id' == 0, it is assumed that this is a new record to be installed on pilot)
00382 recordid_t PilotLocalDatabase::writeRecord(PilotRecord * newRecord)
00383 {
00384         FUNCTIONSETUP;
00385         int i;
00386 
00387         fPendingRec = -1;
00388         if (isDBOpen() == false)
00389         {
00390                 kdError() << k_funcinfo << ": DB not open!" << endl;
00391                 return 0;
00392         }
00393         // We can't do this since it's possible the local apps need to rewrite a record
00394         // that also exists on the pilot, ie: it would already have a uid but incorrectly
00395         // get marked as clean.  So it's up to the app to mark them clean/dirty as appropriate.
00396 //     if(id != 0)
00397 //      {
00398 //      // This must have come from the pilot, so turn off the modified flags
00399 //      flags = flags & ~dlpRecAttrDirty;
00400 //      }
00401 //     else
00402 //      flags = flags | dlpRecAttrDirty;
00403 
00404         // Instead of making the app do it, assume that whenever a record is
00405         // written to the database it is dirty.  (You can clean up the database with
00406         // resetSyncFlags().)  This will make things get copied twice during a hot-sync
00407         // but shouldn't cause any other major headaches.
00408         newRecord->setAttrib(newRecord->getAttrib() | dlpRecAttrDirty);
00409 
00410         // First check to see if we have this record:
00411         if (newRecord->getID() != 0)
00412         {
00413                 for (i = 0; i < fNumRecords; i++)
00414                         if (fRecords[i]->getID() == newRecord->getID())
00415                         {
00416                                 delete fRecords[i];
00417 
00418                                 fRecords[i] = new PilotRecord(newRecord);
00419                                 return 0;
00420                         }
00421         }
00422         // Ok, we don't have it, so just tack it on.
00423         fRecords[fNumRecords++] = new PilotRecord(newRecord);
00424         return newRecord->getID();
00425 }
00426 
00427 // Deletes a record with the given recordid_t from the database, or all records, if all is set to true. The recordid_t will be ignored in this case
00428 int PilotLocalDatabase::deleteRecord(recordid_t id, bool all)
00429 {
00430         FUNCTIONSETUP;
00431         if (isDBOpen() == false)
00432         {
00433                 kdError() << k_funcinfo <<": DB not open"<<endl;
00434                 return -1;
00435         }
00436 
00437         if (all)
00438         {
00439                 for (int i=0; i<fNumRecords; i++)
00440                 {
00441                         delete fRecords[i];
00442                         fRecords[i]=0L;
00443                 }
00444                 fNumRecords=0;
00445                 fCurrentRecord=0;
00446                 fPendingRec=0;
00447                 return 0;
00448         }
00449         else
00450         {
00451                 int i=0;
00452                 while ( (i<fNumRecords) && (fRecords[i]->getID()!=id) )
00453                         i++;
00454                 if (fRecords[i]->getID() == id)
00455                 {
00456                         delete fRecords[i];
00457                         for (int j=i+1; j<fNumRecords; j++)
00458                         {
00459                                 fRecords[j-1]=fRecords[j];
00460                         }
00461                         fNumRecords--;
00462                 }
00463                 else
00464                 {
00465                         // Record with this id does not exist!
00466                         return -1;
00467                 }
00468         }
00469         return 0;
00470 }
00471 
00472 
00473 // Resets all records in the database to not dirty.
00474 int PilotLocalDatabase::resetSyncFlags()
00475 {
00476         FUNCTIONSETUP;
00477 
00478         int i;
00479 
00480         fPendingRec = -1;
00481         if (isDBOpen() == false)
00482         {
00483                 kdError() << k_funcinfo << ": DB not open!" << endl;
00484                 return -1;
00485         }
00486         for (i = 0; i < fNumRecords; i++)
00487                 fRecords[i]->setAttrib(fRecords[i]->
00488                         getAttrib() & ~dlpRecAttrDirty);
00489         return 0;
00490 }
00491 
00492 // Resets next record index to beginning
00493 int PilotLocalDatabase::resetDBIndex()
00494 {
00495         FUNCTIONSETUP;
00496         fPendingRec = -1;
00497         if (isDBOpen() == false)
00498         {
00499                 kdError() << k_funcinfo << ": DB not open!" << endl;
00500                 return -1;
00501         }
00502         fCurrentRecord = 0;
00503         return 0;
00504 }
00505 
00506 // Purges all Archived/Deleted records from Palm Pilot database
00507 int PilotLocalDatabase::cleanup()
00508 {
00509         FUNCTIONSETUP;
00510         fPendingRec = -1;
00511         if (isDBOpen() == false)
00512         {
00513                 kdError() << k_funcinfo << ": DB not open!" << endl;
00514                 return -1;
00515         }
00516         int i, j;
00517 
00518         for (i = 0; (i < fNumRecords) && (fRecords[i]);)
00519                 if (fRecords[i]->getAttrib() & dlpRecAttrDeleted)
00520                 {
00521                         delete fRecords[i];
00522 
00523                         if ((i + 1) < fNumRecords)
00524                                 for (j = i + 1; j < fNumRecords; j++)
00525                                         fRecords[j - 1] = fRecords[j];
00526                         else
00527                                 fRecords[i] = 0L;
00528                         fNumRecords--;
00529                 }
00530                 else
00531                         i++;
00532 
00533         // Don't have to do anything.  Will be taken care of by closeDatabase()...
00534         // Changed!
00535         return 0;
00536 }
00537 
00538 QString PilotLocalDatabase::dbPathName() const
00539 {
00540         FUNCTIONSETUP;
00541         QString tempName(fPathName);
00542         QString slash = CSL1("/");
00543 
00544         if (!tempName.endsWith(slash)) tempName += slash;
00545         tempName += getDBName();
00546         tempName += CSL1(".pdb");
00547         return tempName;
00548 }
00549 
00550 void PilotLocalDatabase::openDatabase()
00551 {
00552         FUNCTIONSETUP;
00553 
00554         void *tmpBuffer;
00555         pi_file *dbFile;
00556         int size, attr, cat;
00557         pi_uid_t id;
00558 
00559         QString tempName = dbPathName();
00560         QCString fileName = QFile::encodeName(tempName);
00561         dbFile = pi_file_open(const_cast < char *>((const char *) fileName));
00562 
00563         if (dbFile == 0L)
00564         {
00565                 kdError() << k_funcinfo
00566                         << ": Failed to open " << tempName << endl;
00567                 return;
00568         }
00569         pi_file_get_info(dbFile, &fDBInfo);
00570         pi_file_get_app_info(dbFile, &tmpBuffer, &fAppLen);
00571         fAppInfo = new char[fAppLen];
00572 
00573         memcpy(fAppInfo, tmpBuffer, fAppLen);
00574         while (pi_file_read_record(dbFile, fCurrentRecord,
00575                         &tmpBuffer, &size, &attr, &cat, &id) == 0)
00576         {
00577                 fRecords[fCurrentRecord] =
00578                         new PilotRecord(tmpBuffer, size, attr, cat, id);
00579                 fCurrentRecord++;
00580         }
00581         pi_file_close(dbFile);  // We done with it once we've read it in.
00582         fNumRecords = fCurrentRecord;
00583         fCurrentRecord = 0;
00584         setDBOpen(true);
00585 }
00586 
00587 void PilotLocalDatabase::closeDatabase()
00588 {
00589         FUNCTIONSETUP;
00590         pi_file *dbFile;
00591         int i;
00592 
00593         if (isDBOpen() == false)
00594         {
00595 #ifdef DEBUG
00596                 DEBUGCONDUIT<<"Database "<<fDBName<<" is not open. Cannot close and write it"<<endl;
00597 #endif
00598                 return;
00599         }
00600 
00601         QString tempName_ = dbPathName();
00602         QString newName_ = tempName_ + CSL1(".bak");
00603         QCString tempName = QFile::encodeName(tempName_);
00604         QCString newName = QFile::encodeName(newName_);
00605 
00606         dbFile = pi_file_create(const_cast < char *>((const char *)newName),
00607                 &fDBInfo);
00608 #ifdef DEBUG
00609         DEBUGCONDUIT<<"Created temp file "<<newName<<" for the database file "<<dbPathName()<<endl;
00610 #endif
00611 
00612         pi_file_set_app_info(dbFile, fAppInfo, fAppLen);
00613         for (i = 0; i < fNumRecords; i++)
00614         {
00615                 pi_file_append_record(dbFile,
00616                         fRecords[i]->getData(),
00617                         fRecords[i]->getLen(),
00618                         fRecords[i]->getAttrib(), fRecords[i]->getCat(),
00619                         fRecords[i]->getID());
00620         }
00621 
00622         pi_file_close(dbFile);
00623         unlink((const char *) QFile::encodeName(tempName));
00624         rename((const char *) QFile::encodeName(newName),
00625                 (const char *) QFile::encodeName(tempName));
00626         setDBOpen(false);
00627 }
00628 
00629 
00630 QString *PilotLocalDatabase::fPathBase = 0L;
00631 
00632 void PilotLocalDatabase::setDBPath(const QString &s)
00633 {
00634         FUNCTIONSETUP;
00635 
00636 #ifdef DEBUG
00637         DEBUGDAEMON << fname
00638                 << ": Setting default DB path to "
00639                 << s
00640                 << endl;
00641 #endif
00642 
00643         if (!fPathBase)
00644         {
00645                 fPathBase = new QString(s);
00646         }
00647         else
00648         {
00649                 *fPathBase = s;
00650         }
00651 }
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Sun Feb 15 11:40:44 2004 by doxygen 1.3.5 written by Dimitri van Heesch, © 1997-2001