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