kpilot

pilotSerialDatabase.cc

Go to the documentation of this file.
00001 /* KPilot
00002 **
00003 ** Copyright (C) 1998-2001 by Dan Pilone
00004 ** Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
00005 **
00006 ** Databases approached through DLP / Pilot-link look different,
00007 ** so this file defines an API for them.
00008 */
00009 
00010 /*
00011 ** This program is free software; you can redistribute it and/or modify
00012 ** it under the terms of the GNU Lesser General Public License as published by
00013 ** the Free Software Foundation; either version 2.1 of the License, or
00014 ** (at your option) any later version.
00015 **
00016 ** This program is distributed in the hope that it will be useful,
00017 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00019 ** GNU Lesser General Public License for more details.
00020 **
00021 ** You should have received a copy of the GNU Lesser General Public License
00022 ** along with this program in a file called COPYING; if not, write to
00023 ** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
00024 ** MA 02110-1301, USA.
00025 */
00026 
00027 /*
00028 ** Bug reports and questions can be sent to kde-pim@kde.org
00029 */
00030 #include "options.h"
00031 
00032 #include <time.h>
00033 #include <iostream>
00034 
00035 #include <pi-dlp.h>
00036 
00037 #include <qfile.h>
00038 
00039 #include <klocale.h>
00040 #include <kdebug.h>
00041 #include <kglobal.h>
00042 
00043 #include "pilotRecord.h"
00044 #include "pilotSerialDatabase.h"
00045 #include "kpilotdevicelink.h"
00046 
00047 PilotSerialDatabase::PilotSerialDatabase(KPilotDeviceLink *l,
00048     const QString &dbName) :
00049     PilotDatabase(dbName),
00050     fDBName( dbName ),
00051     fDBHandle(-1),
00052     fDBSocket(l->pilotSocket())
00053 {
00054     FUNCTIONSETUP;
00055     openDatabase();
00056 }
00057 
00058 PilotSerialDatabase::PilotSerialDatabase( KPilotDeviceLink *l, const DBInfo *info ) :
00059     PilotDatabase( info ? Pilot::fromPilot( info->name ) : QString::null ),
00060     fDBName( QString::null ),
00061     fDBHandle( -1 ),
00062     fDBSocket( l->pilotSocket() )
00063 {
00064     // Rather unclear  why both the base class and this one have separate names.
00065     fDBName = name();
00066     setDBOpen(false);
00067     if (fDBName.isEmpty() || !info)
00068     {
00069         WARNINGKPILOT << "Bad database name requested." << endl;
00070         return;
00071     }
00072 
00073     int db;
00074     if (dlp_OpenDB(fDBSocket, 0, dlpOpenReadWrite, info->name, &db) < 0)
00075     {
00076         WARNINGKPILOT << "Cannot open database on handheld." << endl;
00077         return;
00078     }
00079     setDBHandle(db);
00080     setDBOpen(true);
00081 }
00082 
00083 PilotSerialDatabase::~PilotSerialDatabase()
00084 {
00085     FUNCTIONSETUP;
00086     closeDatabase();
00087 }
00088 
00089 QString PilotSerialDatabase::dbPathName() const
00090 {
00091     QString s = CSL1("Pilot:");
00092     s.append(fDBName);
00093     return s;
00094 }
00095 
00096 // Reads the application block info
00097 int PilotSerialDatabase::readAppBlock(unsigned char *buffer, int maxLen)
00098 {
00099     FUNCTIONSETUP;
00100     if (!isOpen())
00101     {
00102         WARNINGKPILOT << "DB not open" << endl;
00103         return -1;
00104     }
00105     pi_buffer_t *buf = pi_buffer_new(maxLen);
00106     int r = dlp_ReadAppBlock(fDBSocket, getDBHandle(), 0 /* offset */, maxLen, buf);
00107     if (r>=0)
00108     {
00109         memcpy(buffer, buf->data, KMAX(maxLen, r));
00110     }
00111     pi_buffer_free(buf);
00112     return r;
00113 }
00114 
00115 // Writes the application block info.
00116 int PilotSerialDatabase::writeAppBlock(unsigned char *buffer, int len)
00117 {
00118     FUNCTIONSETUP;
00119     if (!isOpen())
00120     {
00121         WARNINGKPILOT << "DB not open" << endl;
00122         return -1;
00123     }
00124     return dlp_WriteAppBlock(fDBSocket, getDBHandle(), buffer, len);
00125 }
00126 
00127     // returns the number of records in the database
00128 unsigned int PilotSerialDatabase::recordCount() const
00129 {
00130     int idlen;
00131     // dlp_ReadOpenDBInfo returns the number of bytes read and sets idlen to the # of recs
00132     if (isOpen() && dlp_ReadOpenDBInfo(fDBSocket, getDBHandle(), &idlen)>0)
00133     {
00134         return idlen;
00135     }
00136     else
00137     {
00138         return 0;
00139     }
00140 }
00141 
00142 
00143 // Returns a QValueList of all record ids in the database.
00144 QValueList<recordid_t> PilotSerialDatabase::idList()
00145 {
00146     QValueList<recordid_t> idlist;
00147     int idlen=recordCount();
00148     if (idlen<=0) return idlist;
00149 
00150     recordid_t *idarr=new recordid_t[idlen];
00151     int idlenread;
00152     int r = dlp_ReadRecordIDList (fDBSocket, getDBHandle(), 0, 0, idlen, idarr, &idlenread);
00153 
00154     if ( (r<0) || (idlenread<1) )
00155     {
00156         WARNINGKPILOT << "Failed to read ID list from database." << endl;
00157         return idlist;
00158     }
00159 
00160     // now create the QValue list from the idarr:
00161     for (idlen=0; idlen<idlenread; idlen++)
00162     {
00163         idlist.append(idarr[idlen]);
00164     }
00165     delete[] idarr;
00166     return idlist;
00167 }
00168 
00169 
00170 // Reads a record from database by id, returns record length
00171 PilotRecord *PilotSerialDatabase::readRecordById(recordid_t id)
00172 {
00173     FUNCTIONSETUPL(3);
00174     int index, attr, category;
00175 
00176     if (!isOpen())
00177     {
00178         WARNINGKPILOT << "DB not open" << endl;
00179         return 0L;
00180     }
00181     if (id>0xFFFFFF)
00182     {
00183         WARNINGKPILOT <<  "Encountered an invalid record id "
00184             << id << endl;
00185         return 0L;
00186     }
00187     pi_buffer_t *b = pi_buffer_new(InitialBufferSize);
00188     if (dlp_ReadRecordById(fDBSocket,getDBHandle(),id,b,&index,&attr,&category) >= 0)
00189     {
00190         return new PilotRecord(b, attr, category, id);
00191     }
00192     return 0L;
00193 }
00194 
00195 // Reads a record from database, returns the record length
00196 PilotRecord *PilotSerialDatabase::readRecordByIndex(int index)
00197 {
00198     FUNCTIONSETUPL(3);
00199 
00200     if (!isOpen())
00201     {
00202         WARNINGKPILOT << "DB not open" << endl;
00203         return 0L;
00204     }
00205 
00206     int attr, category;
00207     recordid_t id;
00208     PilotRecord *rec = 0L;
00209 
00210     pi_buffer_t *b = pi_buffer_new(InitialBufferSize);
00211     if (dlp_ReadRecordByIndex(fDBSocket, getDBHandle(), index,
00212         b, &id, &attr, &category) >= 0)
00213     {
00214         rec = new PilotRecord(b, attr, category, id);
00215     }
00216 
00217 
00218     return rec;
00219 }
00220 
00221 // Reads the next record from database in category 'category'
00222 PilotRecord *PilotSerialDatabase::readNextRecInCategory(int category)
00223 {
00224     FUNCTIONSETUP;
00225     int index, attr;
00226     recordid_t id;
00227 
00228     if (!isOpen())
00229     {
00230         WARNINGKPILOT << "DB not open" << endl;
00231         return 0L;
00232     }
00233     pi_buffer_t *b = pi_buffer_new(InitialBufferSize);
00234     if (dlp_ReadNextRecInCategory(fDBSocket, getDBHandle(),
00235         category,b,&id,&index,&attr) >= 0)
00236         return new PilotRecord(b, attr, category, id);
00237     return 0L;
00238 }
00239 
00240 // Reads the next record from database that has the dirty flag set.
00241 PilotRecord *PilotSerialDatabase::readNextModifiedRec(int *ind)
00242 {
00243     FUNCTIONSETUP;
00244     int index, attr, category;
00245     recordid_t id;
00246 
00247     if (!isOpen())
00248     {
00249         WARNINGKPILOT << "DB not open" << endl;
00250         return 0L;
00251     }
00252     pi_buffer_t *b = pi_buffer_new(InitialBufferSize);
00253     if (dlp_ReadNextModifiedRec(fDBSocket, getDBHandle(), b, &id, &index, &attr, &category) >= 0)
00254     {
00255         if (ind) *ind=index;
00256         return new PilotRecord(b, attr, category, id);
00257     }
00258     return 0L;
00259 }
00260 
00261 // Writes a new record to database (if 'id' == 0 or id>0xFFFFFF, one will be assigned and returned in 'newid')
00262 recordid_t PilotSerialDatabase::writeRecord(PilotRecord * newRecord)
00263 {
00264     FUNCTIONSETUP;
00265     recordid_t newid;
00266     int success;
00267 
00268     if (!isOpen())
00269     {
00270         WARNINGKPILOT << "DB not open" << endl;
00271         return 0;
00272     }
00273     // Do some sanity checking to prevent invalid UniqueIDs from being written
00274     // to the handheld (RecordIDs are only 3 bytes!!!). Under normal conditions
00275     // this check should never yield true, so write out an error to indicate
00276     // someone messed up full time...
00277     if (newRecord->id()>0xFFFFFF)
00278     {
00279         WARNINGKPILOT << "Encountered an invalid record id "
00280             << newRecord->id() << ", resetting it to zero." << endl;
00281         newRecord->setID(0);
00282     }
00283     success =
00284         dlp_WriteRecord(fDBSocket, getDBHandle(),
00285         newRecord->attributes(), newRecord->id(),
00286         newRecord->category(), newRecord->data(),
00287         newRecord->size(), &newid);
00288     if ( (newRecord->id() != newid) && (newid!=0) )
00289         newRecord->setID(newid);
00290     return newid;
00291 }
00292 
00293 // 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
00294 int PilotSerialDatabase::deleteRecord(recordid_t id, bool all)
00295 {
00296     FUNCTIONSETUP;
00297     if (!isOpen())
00298     {
00299         WARNINGKPILOT <<"DB not open"<<endl;
00300         return -1;
00301     }
00302     return dlp_DeleteRecord(fDBSocket, getDBHandle(), all?1:0, id);
00303 }
00304 
00305 
00306 // Resets all records in the database to not dirty.
00307 int PilotSerialDatabase::resetSyncFlags()
00308 {
00309     FUNCTIONSETUP;
00310     if (!isOpen())
00311     {
00312         WARNINGKPILOT << "DB not open" << endl;
00313         return -1;
00314     }
00315     return dlp_ResetSyncFlags(fDBSocket, getDBHandle());
00316 }
00317 
00318 // Resets next record index to beginning
00319 int PilotSerialDatabase::resetDBIndex()
00320 {
00321     FUNCTIONSETUP;
00322     if (!isOpen())
00323     {
00324         WARNINGKPILOT << "DB not open" << endl;
00325         return -1;
00326     }
00327     return dlp_ResetDBIndex(fDBSocket, getDBHandle());
00328 }
00329 
00330 // Purges all Archived/Deleted records from Palm Pilot database
00331 int PilotSerialDatabase::cleanup()
00332 {
00333     FUNCTIONSETUP;
00334     if (!isOpen())
00335     {
00336         WARNINGKPILOT << "DB not open" << endl;
00337         return -1;
00338     }
00339     return dlp_CleanUpDatabase(fDBSocket, getDBHandle());
00340 }
00341 
00342 void PilotSerialDatabase::openDatabase()
00343 {
00344     FUNCTIONSETUP;
00345     int db;
00346 
00347     setDBOpen(false);
00348 
00349     QString s = getDBName();
00350     if (s.isEmpty())
00351     {
00352         WARNINGKPILOT << "Bad DB name, " << s << " string given." << endl;
00353         return;
00354     }
00355 
00356     QCString encodedName = QFile::encodeName(s);
00357     if (encodedName.isEmpty())
00358     {
00359         WARNINGKPILOT << "Bad DB name, "
00360             << (encodedName.isNull() ? "null" : "empty")
00361             << " string given."
00362             << endl;
00363         return;
00364     }
00365 
00366     char encodedNameBuffer[PATH_MAX];
00367     strlcpy(encodedNameBuffer,(const char *)encodedName,PATH_MAX);
00368 
00369     DEBUGKPILOT << fname << ": opening database: [" 
00370         << encodedNameBuffer << "]" << endl;
00371 
00372     if (dlp_OpenDB(fDBSocket, 0, dlpOpenReadWrite,
00373         encodedNameBuffer, &db) < 0)
00374     {
00375         WARNINGKPILOT << "Cannot open database on handheld." << endl;
00376         return;
00377     }
00378     setDBHandle(db);
00379     setDBOpen(true);
00380 }
00381 
00382 bool PilotSerialDatabase::createDatabase(long creator, long type, int cardno, int flags, int version)
00383 {
00384     FUNCTIONSETUP;
00385     int db;
00386 
00387     // 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)
00388     if (isOpen()) return true;
00389     // The latin1 seems ok, database names are latin1.
00390     int res=dlp_CreateDB(fDBSocket,
00391         creator, type, cardno, flags, version,
00392         Pilot::toPilot(getDBName()), &db);
00393     if (res<0) {
00394         WARNINGKPILOT << "Cannot create database " << getDBName() << " on the handheld" << endl;
00395         return false;
00396     }
00397     // TODO: Do I have to open it explicitly???
00398     setDBHandle(db);
00399     setDBOpen(true);
00400     return true;
00401 }
00402 
00403 void PilotSerialDatabase::closeDatabase()
00404 {
00405     FUNCTIONSETUP;
00406     if (!isOpen() )
00407     {
00408         return;
00409     }
00410 
00411     DEBUGKPILOT << fname << ": Closing DB handle #" << getDBHandle() << endl;
00412     dlp_CloseDB(fDBSocket, getDBHandle());
00413     DEBUGKPILOT << fname << ": after closing" << endl;
00414     setDBOpen(false);
00415 }
00416 
00417 int PilotSerialDatabase::deleteDatabase()
00418 {
00419     FUNCTIONSETUP;
00420 
00421     if (isOpen()) closeDatabase();
00422 
00423     return dlp_DeleteDB(fDBSocket, 0, Pilot::toPilot(fDBName));
00424 }
00425 
00426 
00427 
00428 /* virtual */ PilotDatabase::DBType PilotSerialDatabase::dbType() const
00429 {
00430     return eSerialDB;
00431 }
00432