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 Wed Jul 28 23:57:49 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003