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