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