00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 static const char *pilotlocaldatabase_id =
00032 "$Id: pilotLocalDatabase.cc 452989 2005-08-24 21:20:38Z adridg $";
00033
00034 #include "options.h"
00035
00036 #include <stdio.h>
00037 #include <unistd.h>
00038 #include <assert.h>
00039
00040 #include <iostream>
00041
00042 #include <qstring.h>
00043 #include <qfile.h>
00044 #include <qregexp.h>
00045 #include <qdatetime.h>
00046 #include <qtextcodec.h>
00047 #include <qvaluevector.h>
00048
00049 #include <kdebug.h>
00050 #include <kglobal.h>
00051 #include <kstandarddirs.h>
00052
00053 #include "pilotAppCategory.h"
00054 #include "pilotLocalDatabase.h"
00055
00056 typedef QValueVector<PilotRecord *> Records;
00057
00058 class PilotLocalDatabase::Private : public Records
00059 {
00060 public:
00061 static const int DEFAULT_SIZE = 128;
00062 Private(int size=DEFAULT_SIZE) : Records(size) { resetIndex(); }
00063 ~Private() { deleteRecords(); }
00064
00065 void deleteRecords()
00066 {
00067 for (unsigned int i=0; i<size(); i++)
00068 {
00069 delete at(i);
00070 }
00071 clear();
00072 resetIndex();
00073 }
00074
00075 void resetIndex() { current = 0; pending = -1; }
00076
00077 unsigned int current;
00078 int pending;
00079 } ;
00080
00081 PilotLocalDatabase::PilotLocalDatabase(const QString & path,
00082 const QString & dbName, bool useDefaultPath) :
00083 PilotDatabase(dbName),
00084 fPathName(path),
00085 fDBName(dbName),
00086 fAppInfo(0L),
00087 fAppLen(0),
00088 d(0L)
00089 {
00090 FUNCTIONSETUP;
00091 fixupDBName();
00092 openDatabase();
00093
00094 if (!isDBOpen() && useDefaultPath)
00095 {
00096 if (fPathBase && !fPathBase->isEmpty())
00097 {
00098 fPathName = *fPathBase;
00099 }
00100 else
00101 {
00102 fPathName = KGlobal::dirs()->saveLocation("data",
00103 CSL1("kpilot/DBBackup/"));
00104 }
00105 fixupDBName();
00106 openDatabase();
00107 if (!isDBOpen())
00108 fPathName=path;
00109 }
00110
00111
00112 (void) pilotlocaldatabase_id;
00113 }
00114
00115 PilotLocalDatabase::PilotLocalDatabase(const QString & dbName,
00116 bool useConduitDBs) :
00117 PilotDatabase(dbName),
00118 fPathName(QString::null),
00119 fDBName(dbName),
00120 fAppInfo(0L),
00121 fAppLen(0),
00122 d(0L)
00123 {
00124 FUNCTIONSETUP;
00125 if (fPathBase && !fPathBase->isEmpty() )
00126 {
00127 fPathName = *fPathBase;
00128 if (useConduitDBs)
00129 fPathName.replace(CSL1("DBBackup/"), CSL1("conduits/"));
00130 }
00131 else
00132 {
00133 fPathName = KGlobal::dirs()->saveLocation("data",
00134 CSL1("kpilot/")+(useConduitDBs?CSL1("conduits/"):CSL1("DBBackup/")));
00135 }
00136
00137 fixupDBName();
00138 openDatabase();
00139 }
00140
00141 PilotLocalDatabase::PilotLocalDatabase(const QString &dbName) :
00142 PilotDatabase( QString() ),
00143 fPathName( QString() ),
00144 fDBName( QString() ),
00145 fAppInfo(0L),
00146 fAppLen(0),
00147 d(0L)
00148 {
00149 FUNCTIONSETUP;
00150
00151 int p = dbName.findRev( '/' );
00152 if (p<0)
00153 {
00154
00155 fPathName = CSL1(".");
00156 fDBName = dbName;
00157 }
00158 else
00159 {
00160 fPathName = dbName.left(p);
00161 fDBName = dbName.mid(p+1);
00162 }
00163 openDatabase();
00164 }
00165
00166 PilotLocalDatabase::~PilotLocalDatabase()
00167 {
00168 FUNCTIONSETUP;
00169
00170 closeDatabase();
00171 delete[]fAppInfo;
00172 delete d;
00173 }
00174
00175
00176 void PilotLocalDatabase::fixupDBName()
00177 {
00178 FUNCTIONSETUP;
00179 fDBName = fDBName.replace(CSL1("/"),CSL1("_"));
00180 }
00181
00182 bool PilotLocalDatabase::createDatabase(long creator, long type, int, int flags, int version)
00183 {
00184 FUNCTIONSETUP;
00185
00186
00187 if (isDBOpen()) {
00188 #ifdef DEBUG
00189 DEBUGCONDUIT<<"Database "<<fDBName<<" already open. Cannot recreate it."<<endl;
00190 #endif
00191 return true;
00192 }
00193
00194 #ifdef DEBUG
00195 DEBUGCONDUIT<<"Creating database "<<fDBName<<endl;
00196 #endif
00197
00198
00199 memcpy(&fDBInfo.name[0], PilotAppCategory::codec()->fromUnicode(fDBName), 34*sizeof(char));
00200 fDBInfo.creator=creator;
00201 fDBInfo.type=type;
00202 fDBInfo.more=0;
00203 fDBInfo.flags=flags;
00204 fDBInfo.miscFlags=0;
00205 fDBInfo.version=version;
00206 fDBInfo.modnum=0;
00207 fDBInfo.index=0;
00208 fDBInfo.createDate=(QDateTime::currentDateTime()).toTime_t();
00209 fDBInfo.modifyDate=(QDateTime::currentDateTime()).toTime_t();
00210 fDBInfo.backupDate=(QDateTime::currentDateTime()).toTime_t();
00211
00212 delete[] fAppInfo;
00213 fAppInfo=0L;
00214 fAppLen=0;
00215
00216 d = new Private;
00217
00218
00219 setDBOpen(true);
00220 return true;
00221 }
00222
00223 int PilotLocalDatabase::deleteDatabase()
00224 {
00225 FUNCTIONSETUP;
00226 if (isDBOpen()) closeDatabase();
00227
00228 QString dbpath=dbPathName();
00229 QFile fl(dbpath);
00230 if (QFile::remove(dbPathName()))
00231 return 0;
00232 else
00233 return -1;
00234 }
00235
00236
00237
00238
00239 int PilotLocalDatabase::readAppBlock(unsigned char *buffer, int size)
00240 {
00241 FUNCTIONSETUP;
00242
00243 size_t m = kMin((size_t)size,(size_t)fAppLen);
00244
00245 if (!isDBOpen())
00246 {
00247 kdError() << k_funcinfo << ": DB not open!" << endl;
00248 memset(buffer,0,m);
00249 return -1;
00250 }
00251
00252 memcpy((void *) buffer, fAppInfo, m);
00253 return fAppLen;
00254 }
00255
00256 int PilotLocalDatabase::writeAppBlock(unsigned char *buffer, int len)
00257 {
00258 FUNCTIONSETUP;
00259
00260 if (isDBOpen() == false)
00261 {
00262 kdError() << k_funcinfo << ": DB not open!" << endl;
00263 return -1;
00264 }
00265 delete[]fAppInfo;
00266 fAppLen = len;
00267 fAppInfo = new char[fAppLen];
00268
00269 memcpy(fAppInfo, (void *) buffer, fAppLen);
00270 return 0;
00271 }
00272
00273
00274
00275 int PilotLocalDatabase::recordCount()
00276 {
00277 return d->size();
00278 }
00279
00280
00281
00282 QValueList<recordid_t> PilotLocalDatabase::idList()
00283 {
00284 int idlen=recordCount();
00285 QValueList<recordid_t> idlist;
00286 if (idlen<=0) return idlist;
00287
00288
00289 for (int i=0; i<idlen; i++)
00290 {
00291 idlist.append((*d)[i]->id());
00292 }
00293
00294 return idlist;
00295 }
00296
00297
00298 PilotRecord *PilotLocalDatabase::readRecordById(recordid_t id)
00299 {
00300 FUNCTIONSETUP;
00301
00302 d->pending = -1;
00303 if (isDBOpen() == false)
00304 {
00305 kdWarning() << k_funcinfo << fDBName << ": DB not open!" << endl;
00306 return 0L;
00307 }
00308
00309
00310 for (unsigned int i = 0; i < d->size(); i++)
00311 {
00312 if ((*d)[i]->id() == id)
00313 {
00314 PilotRecord *newRecord = new PilotRecord((*d)[i]);
00315 d->current = i;
00316 return newRecord;
00317 }
00318 }
00319 return 0L;
00320 }
00321
00322
00323 PilotRecord *PilotLocalDatabase::readRecordByIndex(int index)
00324 {
00325 FUNCTIONSETUP;
00326 d->pending = -1;
00327 if (isDBOpen() == false)
00328 {
00329 kdWarning() << k_funcinfo << ": DB not open!" << endl;
00330 return 0L;
00331 }
00332 #ifdef DEBUG
00333 DEBUGKPILOT << "Index=" << index << " Count=" << recordCount() << endl;
00334 #endif
00335 if (index >= recordCount())
00336 return 0L;
00337 PilotRecord *newRecord = new PilotRecord((*d)[index]);
00338 d->current = index;
00339
00340 return newRecord;
00341 }
00342
00343
00344 PilotRecord *PilotLocalDatabase::readNextRecInCategory(int category)
00345 {
00346 FUNCTIONSETUP;
00347 d->pending = -1;
00348 if (isDBOpen() == false)
00349 {
00350 kdWarning() << k_funcinfo << ": DB not open!" << endl;
00351 return 0L;
00352 }
00353
00354 while ((d->current < d->size())
00355 && ((*d)[d->current]->category() != category))
00356 {
00357 d->current++;
00358 }
00359
00360 if (d->current >= d->size())
00361 return 0L;
00362 PilotRecord *newRecord = new PilotRecord((*d)[d->current]);
00363
00364 d->current++;
00365 return newRecord;
00366 }
00367
00368 const PilotRecord *PilotLocalDatabase::findNextNewRecord()
00369 {
00370 FUNCTIONSETUP;
00371
00372 if (isDBOpen() == false)
00373 {
00374 kdWarning() << k_funcinfo << ": DB not open!" << endl;
00375 return 0L;
00376 }
00377 #ifdef DEBUG
00378 DEBUGKPILOT << fname << ": looking for new record from " << d->current << endl;
00379 #endif
00380
00381 while ((d->current < d->size())
00382 && ((*d)[d->current]->id() != 0 ))
00383 {
00384 d->current++;
00385 }
00386
00387 if (d->current >= d->size())
00388 return 0L;
00389
00390 d->pending = d->current;
00391 d->current++;
00392 return (*d)[d->pending];
00393 }
00394
00395 PilotRecord *PilotLocalDatabase::readNextModifiedRec(int *ind)
00396 {
00397 FUNCTIONSETUP;
00398
00399 if (isDBOpen() == false)
00400 {
00401 kdWarning() << k_funcinfo << ": DB not open!" << endl;
00402 return 0L;
00403 }
00404
00405 d->pending = -1;
00406
00407 while ((d->current < d->size())
00408 && !((*d)[d->current]->isModified()) && ((*d)[d->current]->id()>0 ))
00409 {
00410 d->current++;
00411 }
00412
00413 if (d->current >= d->size())
00414 return 0L;
00415 PilotRecord *newRecord = new PilotRecord((*d)[d->current]);
00416 if (ind) *ind=d->current;
00417
00418 d->pending = d->current;
00419 d->current++;
00420 return newRecord;
00421 }
00422
00423
00424 recordid_t PilotLocalDatabase::updateID(recordid_t id)
00425 {
00426 FUNCTIONSETUP;
00427
00428 if (isDBOpen() == false)
00429 {
00430 kdError() << k_funcinfo << ": DB not open!" << endl;
00431 return 0;
00432 }
00433 if (d->pending < 0)
00434 {
00435 kdError() << k_funcinfo <<
00436 ": Last call was _NOT_ readNextModifiedRec()" << endl;
00437 return 0;
00438 }
00439 (*d)[d->pending]->setID(id);
00440 d->pending = -1;
00441 return id;
00442 }
00443
00444
00445 recordid_t PilotLocalDatabase::writeRecord(PilotRecord * newRecord)
00446 {
00447 FUNCTIONSETUP;
00448
00449 if (isDBOpen() == false)
00450 {
00451 kdError() << k_funcinfo << ": DB not open!" << endl;
00452 return 0;
00453 }
00454
00455 d->pending = -1;
00456 if (!newRecord)
00457 {
00458 kdError() << k_funcinfo << ": Record to be written is invalid!" << endl;
00459 return 0;
00460 }
00461
00462
00463
00464
00465
00466 newRecord->setModified( true );
00467
00468
00469 if (newRecord->id() != 0)
00470 {
00471 for (unsigned int i = 0; i < d->size(); i++)
00472 if ((*d)[i]->id() == newRecord->id())
00473 {
00474 delete (*d)[i];
00475
00476 (*d)[i] = new PilotRecord(newRecord);
00477 return 0;
00478 }
00479 }
00480
00481 d->append( new PilotRecord(newRecord) );
00482 return newRecord->id();
00483 }
00484
00485
00486 int PilotLocalDatabase::deleteRecord(recordid_t id, bool all)
00487 {
00488 FUNCTIONSETUP;
00489 if (isDBOpen() == false)
00490 {
00491 kdError() << k_funcinfo <<": DB not open"<<endl;
00492 return -1;
00493 }
00494 d->resetIndex();
00495 if (all)
00496 {
00497 d->deleteRecords();
00498 d->clear();
00499 return 0;
00500 }
00501 else
00502 {
00503 Private::Iterator i;
00504 for ( i=d->begin() ; i!=d->end(); ++i)
00505 {
00506 if ((*i) && (*i)->id() == id) break;
00507 }
00508 if ( (i!=d->end()) && (*i) && (*i)->id() == id)
00509 {
00510 d->erase(i);
00511 }
00512 else
00513 {
00514
00515 return -1;
00516 }
00517 }
00518 return 0;
00519 }
00520
00521
00522
00523 int PilotLocalDatabase::resetSyncFlags()
00524 {
00525 FUNCTIONSETUP;
00526
00527 if (isDBOpen() == false)
00528 {
00529 kdError() << k_funcinfo << ": DB not open!" << endl;
00530 return -1;
00531 }
00532 d->pending = -1;
00533 for (unsigned int i = 0; i < d->size(); i++)
00534 {
00535 (*d)[i]->setModified( false );
00536 }
00537 return 0;
00538 }
00539
00540
00541 int PilotLocalDatabase::resetDBIndex()
00542 {
00543 FUNCTIONSETUP;
00544 if (isDBOpen() == false)
00545 {
00546 kdWarning() << k_funcinfo << ": DB not open!" << endl;
00547 return -1;
00548 }
00549 d->resetIndex();
00550 return 0;
00551 }
00552
00553
00554 int PilotLocalDatabase::cleanup()
00555 {
00556 FUNCTIONSETUP;
00557 if (isDBOpen() == false)
00558 {
00559 kdWarning() << k_funcinfo << ": DB not open!" << endl;
00560 return -1;
00561 }
00562 d->resetIndex();
00563
00564
00565
00566
00567 Private::Iterator i = d->begin();
00568 while ( i!=d->end() )
00569 {
00570 if ( (*i)->isDeleted() || (*i)->isArchived() )
00571 {
00572 delete (*i);
00573 i = d->erase(i);
00574 }
00575 else
00576 {
00577 ++i;
00578 }
00579 }
00580
00581
00582
00583 return 0;
00584 }
00585
00586 QString PilotLocalDatabase::dbPathName() const
00587 {
00588 FUNCTIONSETUP;
00589 QString tempName(fPathName);
00590 QString slash = CSL1("/");
00591
00592 if (!tempName.endsWith(slash)) tempName += slash;
00593 tempName += getDBName();
00594 tempName += CSL1(".pdb");
00595 return tempName;
00596 }
00597
00598 void PilotLocalDatabase::openDatabase()
00599 {
00600 FUNCTIONSETUP;
00601
00602 pi_file *dbFile;
00603
00604 setDBOpen(false);
00605 char buffer[PATH_MAX];
00606 memset(buffer,0,PATH_MAX);
00607 strlcpy(buffer,QFile::encodeName(dbPathName()),PATH_MAX);
00608
00609 dbFile = pi_file_open(buffer);
00610 if (dbFile == 0L)
00611 {
00612 #ifdef DEBUG
00613 DEBUGCONDUIT << fname << ": Failed to open " << dbPathName() << endl;
00614 #endif
00615 return;
00616 }
00617
00618
00619 PI_SIZE_T size = 0;
00620 void *tmpBuffer;
00621 pi_file_get_info(dbFile, &fDBInfo);
00622 pi_file_get_app_info(dbFile, &tmpBuffer, &size);
00623 fAppLen = size;
00624 fAppInfo = new char[fAppLen];
00625 memcpy(fAppInfo, tmpBuffer, fAppLen);
00626
00627 int count;
00628 pi_file_get_entries(dbFile, &count);
00629 if (count >= 0)
00630 {
00631 KPILOT_DELETE(d);
00632 d = new Private(count);
00633 }
00634
00635 int attr, cat;
00636 recordid_t id;
00637 unsigned int i = 0;
00638 while (pi_file_read_record(dbFile, i,
00639 &tmpBuffer, &size, &attr, &cat, &id) == 0)
00640 {
00641 (*d)[i] = new PilotRecord(tmpBuffer, size, attr, cat, id);
00642 i++;
00643 }
00644 pi_file_close(dbFile);
00645 setDBOpen(true);
00646 }
00647
00648 void PilotLocalDatabase::closeDatabase()
00649 {
00650 FUNCTIONSETUP;
00651 pi_file *dbFile;
00652
00653 if (isDBOpen() == false)
00654 {
00655 #ifdef DEBUG
00656 DEBUGCONDUIT << fname << ": Database "<<fDBName<<" is not open. Cannot close and write it"<<endl;
00657 #endif
00658 return;
00659 }
00660
00661 QString newName = dbPathName() + CSL1(".new");
00662 char buf[PATH_MAX];
00663 memset(buf,0,PATH_MAX);
00664 strlcpy(buf,QFile::encodeName(newName),PATH_MAX);
00665
00666 #ifdef DEBUG
00667 DEBUGCONDUIT << fname
00668 << ": Creating temp file " << buf
00669 << " for the database file " << dbPathName() << endl;
00670 #endif
00671
00672 dbFile = pi_file_create(buf,&fDBInfo);
00673 pi_file_set_app_info(dbFile, fAppInfo, fAppLen);
00674 for (unsigned int i = 0; i < d->size(); i++)
00675 {
00676 if (((*d)[i]->id() == 0) && ((*d)[i]->isDeleted()))
00677 {
00678
00679 }
00680 else
00681 {
00682 pi_file_append_record(dbFile,
00683 (*d)[i]->data(),
00684 (*d)[i]->size(),
00685 (*d)[i]->attributes(), (*d)[i]->category(),
00686 (*d)[i]->id());
00687 }
00688 }
00689
00690 pi_file_close(dbFile);
00691 QFile::remove(dbPathName());
00692 rename((const char *) QFile::encodeName(newName),
00693 (const char *) QFile::encodeName(dbPathName()));
00694 setDBOpen(false);
00695 }
00696
00697
00698 QString *PilotLocalDatabase::fPathBase = 0L;
00699
00700 void PilotLocalDatabase::setDBPath(const QString &s)
00701 {
00702 FUNCTIONSETUP;
00703
00704 #ifdef DEBUG
00705 DEBUGDAEMON << fname
00706 << ": Setting default DB path to "
00707 << s
00708 << endl;
00709 #endif
00710
00711 if (!fPathBase)
00712 {
00713 fPathBase = new QString(s);
00714 }
00715 else
00716 {
00717 *fPathBase = s;
00718 }
00719 }
00720
00721 PilotDatabase::DBType PilotLocalDatabase::dbType() const
00722 {
00723 return eLocalDB;
00724 }
00725