kpilot/lib

pilotSerialDatabase.cc

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(QString::null),
00051     fDBHandle(-1),
00052     fDBSocket(l->pilotSocket())
00053 {
00054     FUNCTIONSETUP;
00055     fDBName = dbName;
00056 
00057     openDatabase();
00058 
00059 }
00060 
00061 PilotSerialDatabase::~PilotSerialDatabase()
00062 {
00063     FUNCTIONSETUP;
00064     closeDatabase();
00065 }
00066 
00067 QString PilotSerialDatabase::dbPathName() const
00068 {
00069     QString s = CSL1("Pilot:");
00070     s.append(fDBName);
00071     return s;
00072 }
00073 
00074 // Reads the application block info
00075 int PilotSerialDatabase::readAppBlock(unsigned char *buffer, int maxLen)
00076 {
00077     FUNCTIONSETUP;
00078     if (!isOpen())
00079     {
00080         kdError() << k_funcinfo << ": DB not open" << endl;
00081         return -1;
00082     }
00083     pi_buffer_t *buf = pi_buffer_new(maxLen);
00084     int r = dlp_ReadAppBlock(fDBSocket, getDBHandle(), 0 /* offset */, maxLen, buf);
00085     if (r>=0)
00086     {
00087         memcpy(buffer, buf->data, KMAX(maxLen, r));
00088     }
00089     pi_buffer_free(buf);
00090     return r;
00091 }
00092 
00093 // Writes the application block info.
00094 int PilotSerialDatabase::writeAppBlock(unsigned char *buffer, int len)
00095 {
00096     FUNCTIONSETUP;
00097     if (!isOpen())
00098     {
00099         kdError() << k_funcinfo << ": DB not open" << endl;
00100         return -1;
00101     }
00102     return dlp_WriteAppBlock(fDBSocket, getDBHandle(), buffer, len);
00103 }
00104 
00105     // returns the number of records in the database
00106 unsigned int PilotSerialDatabase::recordCount() const
00107 {
00108     int idlen;
00109     // dlp_ReadOpenDBInfo returns the number of bytes read and sets idlen to the # of recs
00110     if (isOpen() && dlp_ReadOpenDBInfo(fDBSocket, getDBHandle(), &idlen)>0)
00111     {
00112         return idlen;
00113     }
00114     else
00115     {
00116         return 0;
00117     }
00118 }
00119 
00120 
00121 // Returns a QValueList of all record ids in the database.
00122 QValueList<recordid_t> PilotSerialDatabase::idList()
00123 {
00124     QValueList<recordid_t> idlist;
00125     int idlen=recordCount();
00126     if (idlen<=0) return idlist;
00127 
00128     recordid_t *idarr=new recordid_t[idlen];
00129     int idlenread;
00130     int r = dlp_ReadRecordIDList (fDBSocket, getDBHandle(), 0, 0, idlen, idarr, &idlenread);
00131 
00132     if ( (r<0) || (idlenread<1) )
00133     {
00134         kdWarning() << k_funcinfo << ": Failed to read ID list from database." << endl;
00135         return idlist;
00136     }
00137 
00138     // now create the QValue list from the idarr:
00139     for (idlen=0; idlen<idlenread; idlen++)
00140     {
00141         idlist.append(idarr[idlen]);
00142     }
00143     delete[] idarr;
00144     return idlist;
00145 }
00146 
00147 
00148 // Reads a record from database by id, returns record length
00149 PilotRecord *PilotSerialDatabase::readRecordById(recordid_t id)
00150 {
00151     FUNCTIONSETUPL(3);
00152     int index, attr, category;
00153 
00154     if (!isOpen())
00155     {
00156         kdError() << k_funcinfo << ": DB not open" << endl;
00157         return 0L;
00158     }
00159     if (id>0xFFFFFF)
00160     {
00161         kdError() << k_funcinfo <<  " Encountered an invalid record id "
00162             <<id<<endl;;
00163         return 0L;
00164     }
00165     pi_buffer_t *b = pi_buffer_new(InitialBufferSize);
00166     if (dlp_ReadRecordById(fDBSocket,getDBHandle(),id,b,&index,&attr,&category) >= 0)
00167     {
00168         return new PilotRecord(b, attr, category, id);
00169     }
00170     return 0L;
00171 }
00172 
00173 // Reads a record from database, returns the record length
00174 PilotRecord *PilotSerialDatabase::readRecordByIndex(int index)
00175 {
00176     FUNCTIONSETUPL(3);
00177 
00178     if (!isOpen())
00179     {
00180         kdError() << k_funcinfo << ": DB not open" << endl;
00181         return 0L;
00182     }
00183 
00184     int attr, category;
00185     recordid_t id;
00186     PilotRecord *rec = 0L;
00187 
00188     pi_buffer_t *b = pi_buffer_new(InitialBufferSize);
00189     if (dlp_ReadRecordByIndex(fDBSocket, getDBHandle(), index,
00190         b, &id, &attr, &category) >= 0)
00191     {
00192         rec = new PilotRecord(b, attr, category, id);
00193     }
00194 
00195 
00196     return rec;
00197 }
00198 
00199 // Reads the next record from database in category 'category'
00200 PilotRecord *PilotSerialDatabase::readNextRecInCategory(int category)
00201 {
00202     FUNCTIONSETUP;
00203     int index, attr;
00204     recordid_t id;
00205 
00206     if (!isOpen())
00207     {
00208         kdError() << k_funcinfo << ": DB not open" << endl;
00209         return 0L;
00210     }
00211     pi_buffer_t *b = pi_buffer_new(InitialBufferSize);
00212     if (dlp_ReadNextRecInCategory(fDBSocket, getDBHandle(),
00213         category,b,&id,&index,&attr) >= 0)
00214         return new PilotRecord(b, attr, category, id);
00215     return 0L;
00216 }
00217 
00218 // Reads the next record from database that has the dirty flag set.
00219 PilotRecord *PilotSerialDatabase::readNextModifiedRec(int *ind)
00220 {
00221     FUNCTIONSETUP;
00222     int index, attr, category;
00223     recordid_t id;
00224 
00225     if (!isOpen())
00226     {
00227         kdError() << k_funcinfo << ": DB not open" << endl;
00228         return 0L;
00229     }
00230     pi_buffer_t *b = pi_buffer_new(InitialBufferSize);
00231     if (dlp_ReadNextModifiedRec(fDBSocket, getDBHandle(), b, &id, &index, &attr, &category) >= 0)
00232     {
00233         if (ind) *ind=index;
00234         return new PilotRecord(b, attr, category, id);
00235     }
00236     return 0L;
00237 }
00238 
00239 // Writes a new record to database (if 'id' == 0 or id>0xFFFFFF, one will be assigned and returned in 'newid')
00240 recordid_t PilotSerialDatabase::writeRecord(PilotRecord * newRecord)
00241 {
00242     FUNCTIONSETUP;
00243     recordid_t newid;
00244     int success;
00245 
00246     if (!isOpen())
00247     {
00248         kdError() << k_funcinfo << ": DB not open" << endl;
00249         return 0;
00250     }
00251     // Do some sanity checking to prevent invalid UniqueIDs from being written
00252     // to the handheld (RecordIDs are only 3 bytes!!!). Under normal conditions
00253     // this check should never yield true, so write out an error to indicate
00254     // someone messed up full time...
00255     if (newRecord->id()>0xFFFFFF)
00256     {
00257         kdError() << k_funcinfo << "Encountered an invalid record id "
00258             <<newRecord->id()<<", resetting it to zero.";
00259         newRecord->setID(0);
00260     }
00261     success =
00262         dlp_WriteRecord(fDBSocket, getDBHandle(),
00263         newRecord->attributes(), newRecord->id(),
00264         newRecord->category(), newRecord->data(),
00265         newRecord->size(), &newid);
00266     if ( (newRecord->id() != newid) && (newid!=0) )
00267         newRecord->setID(newid);
00268     return newid;
00269 }
00270 
00271 // 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
00272 int PilotSerialDatabase::deleteRecord(recordid_t id, bool all)
00273 {
00274     FUNCTIONSETUP;
00275     if (!isOpen())
00276     {
00277         kdError() << k_funcinfo <<": DB not open"<<endl;
00278         return -1;
00279     }
00280     return dlp_DeleteRecord(fDBSocket, getDBHandle(), all?1:0, id);
00281 }
00282 
00283 
00284 // Resets all records in the database to not dirty.
00285 int PilotSerialDatabase::resetSyncFlags()
00286 {
00287     FUNCTIONSETUP;
00288     if (!isOpen())
00289     {
00290         kdError() << k_funcinfo << ": DB not open" << endl;
00291         return -1;
00292     }
00293     return dlp_ResetSyncFlags(fDBSocket, getDBHandle());
00294 }
00295 
00296 // Resets next record index to beginning
00297 int PilotSerialDatabase::resetDBIndex()
00298 {
00299     FUNCTIONSETUP;
00300     if (!isOpen())
00301     {
00302         kdError() << k_funcinfo << ": DB not open" << endl;
00303         return -1;
00304     }
00305     return dlp_ResetDBIndex(fDBSocket, getDBHandle());
00306 }
00307 
00308 // Purges all Archived/Deleted records from Palm Pilot database
00309 int PilotSerialDatabase::cleanup()
00310 {
00311     FUNCTIONSETUP;
00312     if (!isOpen())
00313     {
00314         kdError() << k_funcinfo << ": DB not open" << endl;
00315         return -1;
00316     }
00317     return dlp_CleanUpDatabase(fDBSocket, getDBHandle());
00318 }
00319 
00320 void PilotSerialDatabase::openDatabase()
00321 {
00322     FUNCTIONSETUP;
00323     int db;
00324 
00325     setDBOpen(false);
00326 
00327     QString s = getDBName();
00328     if (s.isEmpty())
00329     {
00330         kdError() << k_funcinfo << ": Bad DB name, "
00331             << (s.isNull() ? "null" : "empty")
00332             << " string given."
00333             << endl;
00334         return;
00335     }
00336 
00337     QCString encodedName = QFile::encodeName(s);
00338     if (encodedName.isEmpty())
00339     {
00340         kdError() << k_funcinfo << ": Bad DB name, "
00341             << (encodedName.isNull() ? "null" : "empty")
00342             << " string given."
00343             << endl;
00344         return;
00345     }
00346 
00347     char encodedNameBuffer[PATH_MAX];
00348     strlcpy(encodedNameBuffer,(const char *)encodedName,PATH_MAX);
00349 
00350     if (dlp_OpenDB(fDBSocket, 0, dlpOpenReadWrite,
00351         encodedNameBuffer, &db) < 0)
00352     {
00353         kdError() << k_funcinfo
00354             << i18n("Cannot open database")
00355             << i18n("Pilot database error") << endl;
00356         return;
00357     }
00358     setDBHandle(db);
00359     setDBOpen(true);
00360 }
00361 
00362 bool PilotSerialDatabase::createDatabase(long creator, long type, int cardno, int flags, int version)
00363 {
00364     FUNCTIONSETUP;
00365     int db;
00366 
00367     // 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)
00368     if (isOpen()) return true;
00369     // The latin1 seems ok, database names are latin1.
00370     int res=dlp_CreateDB(fDBSocket,
00371         creator, type, cardno, flags, version,
00372         Pilot::toPilot(getDBName()), &db);
00373     if (res<0) {
00374         kdError() <<k_funcinfo
00375             << i18n("Cannot create database %1 on the handheld").arg(getDBName())<<endl;
00376         return false;
00377     }
00378     // TODO: Do I have to open it explicitly???
00379     setDBHandle(db);
00380     setDBOpen(true);
00381     return true;
00382 }
00383 
00384 void PilotSerialDatabase::closeDatabase()
00385 {
00386     FUNCTIONSETUP;
00387     if (!isOpen() ) return;
00388 
00389     dlp_CloseDB(fDBSocket, getDBHandle());
00390     setDBOpen(false);
00391 }
00392 
00393 int PilotSerialDatabase::deleteDatabase()
00394 {
00395     FUNCTIONSETUP;
00396 
00397     if (isOpen()) closeDatabase();
00398 
00399     return dlp_DeleteDB(fDBSocket, 0, Pilot::toPilot(fDBName));
00400 }
00401 
00402 
00403 
00404 /* virtual */ PilotDatabase::DBType PilotSerialDatabase::dbType() const
00405 {
00406     return eSerialDB;
00407 }
00408 
KDE Home | KDE Accessibility Home | Description of Access Keys