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