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