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 static const char *kpilotlink_id = "$Id: kpilotlink.cc,v 1.43 2003/08/03 11:15:59 kainhofe Exp $";
00028
00029 #include "options.h"
00030
00031 #include <pi-source.h>
00032 #include <pi-socket.h>
00033 #include <pi-dlp.h>
00034 #include <pi-file.h>
00035 #include <pi-version.h>
00036
00037 #ifndef PILOT_LINK_VERSION
00038 #error "You need at least pilot-link version 0.9.5"
00039 #endif
00040
00041 #define PILOT_LINK_NUMBER ((100*PILOT_LINK_VERSION) + \
00042 PILOT_LINK_MAJOR)
00043
00044 #include <sys/stat.h>
00045 #include <sys/types.h>
00046 #include <stdio.h>
00047 #include <unistd.h>
00048 #include <fcntl.h>
00049 #include <errno.h>
00050
00051 #include <iostream>
00052
00053 #include <qdir.h>
00054 #include <qtimer.h>
00055 #include <qdatetime.h>
00056 #include <qsocketnotifier.h>
00057
00058 #include <kconfig.h>
00059 #include <kmessagebox.h>
00060
00061 #include "pilotUser.h"
00062 #include "pilotSysInfo.h"
00063 #include "pilotCard.h"
00064
00065 #include "kpilotlink.moc"
00066
00067
00068
00069 KPilotDeviceLink *KPilotDeviceLink::fDeviceLink = 0L;
00070
00071 KPilotDeviceLink::KPilotDeviceLink(QObject * parent, const char *name) :
00072 QObject(parent, name),
00073 fStatus(Init),
00074 fPilotPath(QString::null),
00075 fDeviceType(None),
00076 fRetries(0),
00077 fOpenTimer(0L),
00078 fSocketNotifier(0L),
00079 fSocketNotifierActive(false),
00080 fPilotMasterSocket(-1),
00081 fCurrentPilotSocket(-1)
00082 {
00083 FUNCTIONSETUP;
00084
00085 #ifdef DEBUG
00086 DEBUGDAEMON << fname
00087 << ": Pilot-link version " << PILOT_LINK_NUMBER
00088 << endl;
00089 #endif
00090
00091 Q_ASSERT(fDeviceLink == 0L);
00092 fDeviceLink = this;
00093 messagesMask=0xffffffff;
00094
00095 (void) kpilotlink_id;
00096 }
00097
00098 KPilotDeviceLink::~KPilotDeviceLink()
00099 {
00100 FUNCTIONSETUP;
00101 close();
00102 fDeviceLink = 0L;
00103 }
00104
00105 KPilotDeviceLink *KPilotDeviceLink::init(QObject * parent, const char *name)
00106 {
00107 FUNCTIONSETUP;
00108
00109 Q_ASSERT(!fDeviceLink);
00110
00111 return new KPilotDeviceLink(parent, name);
00112 }
00113
00114 void KPilotDeviceLink::close()
00115 {
00116 FUNCTIONSETUP;
00117
00118 KPILOT_DELETE(fOpenTimer);
00119 KPILOT_DELETE(fSocketNotifier);
00120 fSocketNotifierActive=false;
00121 #ifdef DEBUG
00122 DEBUGDAEMON << fname
00123 << ": Closing sockets "
00124 << fCurrentPilotSocket
00125 << " and "
00126 << fPilotMasterSocket
00127 << endl;
00128 #endif
00129 if (fCurrentPilotSocket != -1)
00130 {
00131 pi_close(fCurrentPilotSocket);
00132
00133
00134 ::close(fCurrentPilotSocket);
00135 }
00136 if (fPilotMasterSocket != -1)
00137 {
00138 pi_close(fPilotMasterSocket);
00139 ::close(fPilotMasterSocket);
00140 }
00141 fPilotMasterSocket = (-1);
00142 fCurrentPilotSocket = (-1);
00143 }
00144
00145 void KPilotDeviceLink::reset(DeviceType t, const QString & dP)
00146 {
00147 FUNCTIONSETUP;
00148
00149 fStatus = Init;
00150 fRetries = 0;
00151
00152
00153
00154
00155 close();
00156 fPilotPath = QString::null;
00157
00158 fDeviceType = t;
00159 if (t == None)
00160 return;
00161 fDeviceType=OldStyleUSB;
00162
00163 fPilotPath = dP;
00164 if (fPilotPath.isEmpty())
00165 return;
00166
00167 reset();
00168 }
00169
00170 void KPilotDeviceLink::reset()
00171 {
00172 FUNCTIONSETUP;
00173
00174 messages=0;
00175 close();
00176
00177 checkDevice();
00178
00179
00180 fOpenTimer = new QTimer(this);
00181 QObject::connect(fOpenTimer, SIGNAL(timeout()),
00182 this, SLOT(openDevice()));
00183 fOpenTimer->start(1000, false);
00184
00185 fStatus = WaitingForDevice;
00186 }
00187
00188 void KPilotDeviceLink::checkDevice()
00189 {
00190
00191
00192
00193 QFileInfo fi(fPilotPath);
00194 if (fi.exists())
00195 {
00196
00197
00198 if (!(fi.isReadable() && fi.isWritable()))
00199 {
00200 emit logError(i18n("Pilot device %1 is not read-write.")
00201 .arg(fPilotPath));
00202 }
00203 }
00204 else
00205 {
00206
00207
00208
00209 emit logError(i18n("Pilot device %1 doesn't exist. "
00210 "Assuming the device uses DevFS.")
00211 .arg(fPilotPath));
00212 }
00213 }
00214
00215
00216 void KPilotDeviceLink::openDevice()
00217 {
00218 FUNCTIONSETUPL(2);
00219
00220
00221
00222
00223 if (fStatus == WaitingForDevice)
00224 {
00225 fStatus = FoundDevice;
00226 }
00227
00228 shouldPrint(OpenMessage,i18n("Trying to open device %1...")
00229 .arg(fPilotPath));
00230
00231 if (open())
00232 {
00233 emit logMessage(i18n("Device link ready."));
00234 }
00235 else
00236 {
00237 shouldPrint(OpenFailMessage,i18n("Could not open device: %1 "
00238 "(will retry)").
00239 arg(fPilotPath));
00240
00241 if (fStatus != PilotLinkError)
00242 {
00243 fOpenTimer->start(1000, false);
00244 }
00245 }
00246 }
00247
00248 bool KPilotDeviceLink::open()
00249 {
00250 FUNCTIONSETUPL(2);
00251
00252 struct pi_sockaddr addr;
00253 int ret;
00254 int e = 0;
00255 QString msg;
00256
00257 if (fCurrentPilotSocket != -1)
00258 {
00259
00260 pi_close(fCurrentPilotSocket);
00261 ::close(fCurrentPilotSocket);
00262 }
00263 fCurrentPilotSocket = (-1);
00264
00265 if (fPilotMasterSocket == -1)
00266 {
00267 if (fPilotPath.isEmpty())
00268 {
00269 kdWarning() << k_funcinfo
00270 << ": No point in trying empty device."
00271 << endl;
00272
00273 msg = i18n("The Pilot device is not configured yet.");
00274 e = 0;
00275 goto errInit;
00276 }
00277 #ifdef DEBUG
00278 DEBUGDAEMON << fname << ": Typing to open " << fPilotPath << endl;
00279 #endif
00280
00281 #if PILOT_LINK_NUMBER < 10
00282 fPilotMasterSocket = pi_socket(PI_AF_SLP,
00283 PI_SOCK_STREAM, PI_PF_PADP);
00284 #else
00285 fPilotMasterSocket = pi_socket(PI_AF_PILOT,
00286 PI_SOCK_STREAM, PI_PF_DLP);
00287 #endif
00288
00289 if (fPilotMasterSocket<1)
00290 {
00291 e = errno;
00292 msg = i18n("Cannot create socket for communicating "
00293 "with the Pilot");
00294 goto errInit;
00295 }
00296
00297 #ifdef DEBUG
00298 DEBUGDAEMON << fname
00299 << ": Got master " << fPilotMasterSocket << endl;
00300 #endif
00301
00302 fStatus = CreatedSocket;
00303 }
00304
00305 Q_ASSERT(fStatus == CreatedSocket);
00306
00307 #ifdef DEBUG
00308 DEBUGDAEMON << fname << ": Binding to path " << fPilotPath << endl;
00309 #endif
00310
00311 #if PILOT_LINK_NUMBER < 10
00312 addr.pi_family = PI_AF_SLP;
00313 #else
00314 addr.pi_family = PI_AF_PILOT;
00315 #endif
00316 strncpy(addr.pi_device, QFile::encodeName(fPilotPath),sizeof(addr.pi_device));
00317
00318
00319 ret = pi_bind(fPilotMasterSocket,
00320 (struct sockaddr *) &addr, sizeof(addr));
00321
00322 if (ret >= 0)
00323 {
00324 fStatus = DeviceOpen;
00325 fOpenTimer->stop();
00326
00327 fSocketNotifier = new QSocketNotifier(fPilotMasterSocket,
00328 QSocketNotifier::Read, this);
00329 QObject::connect(fSocketNotifier, SIGNAL(activated(int)),
00330 this, SLOT(acceptDevice()));
00331 fSocketNotifierActive=true;
00332 return true;
00333 }
00334 else
00335 {
00336 #ifdef DEBUG
00337 DEBUGDAEMON << fname
00338 << ": Tried "
00339 << addr.pi_device
00340 << " and got "
00341 << strerror(errno)
00342 << endl;
00343 #endif
00344
00345 if (isTransient() && (fRetries < 5))
00346 {
00347 return false;
00348 }
00349 e = errno;
00350 msg = i18n("Cannot open Pilot port \"%1\". ");
00351
00352 fOpenTimer->stop();
00353
00354
00355 }
00356
00357
00358
00359
00360
00361
00362
00363 errInit:
00364 close();
00365
00366 if (msg.find('%'))
00367 {
00368 if (fPilotPath.isEmpty())
00369 {
00370 msg = msg.arg(i18n("(empty)"));
00371 }
00372 else
00373 {
00374 msg = msg.arg(fPilotPath);
00375 }
00376 }
00377 switch (e)
00378 {
00379 case ENOENT:
00380 msg += i18n(" The port does not exist.");
00381 break;
00382 case ENODEV:
00383 msg += i18n(" These is no such device.");
00384 break;
00385 case EPERM:
00386 msg += i18n(" You don't have permission to open the "
00387 "Pilot device.");
00388 break;
00389 default:
00390 msg += i18n(" Check Pilot path and permissions.");
00391 }
00392
00393
00394
00395
00396
00397
00398 kdError() << k_funcinfo << ": " << msg << endl;
00399 if (e)
00400 {
00401 kdError() << k_funcinfo
00402 << ": (" << strerror(e) << ")" << endl;
00403 }
00404
00405 fStatus = PilotLinkError;
00406 emit logError(msg);
00407 return false;
00408 }
00409
00410 void KPilotDeviceLink::acceptDevice()
00411 {
00412 FUNCTIONSETUP;
00413
00414 int ret;
00415
00416 if (!fSocketNotifierActive)
00417 {
00418 if (!fAcceptedCount)
00419 {
00420 kdWarning() << k_funcinfo << ": Accidentally in acceptDevice()"
00421 << endl;
00422 }
00423 fAcceptedCount++;
00424 if (fAcceptedCount>10)
00425 {
00426
00427 KPILOT_DELETE(fSocketNotifier);
00428 }
00429 return;
00430 }
00431
00432 if (fSocketNotifier)
00433 {
00434
00435 fSocketNotifierActive=false;
00436 }
00437
00438 #ifdef DEBUG
00439 DEBUGDAEMON << fname
00440 << ": Current status "
00441 << statusString()
00442 << " and master " << fPilotMasterSocket << endl;
00443 #endif
00444
00445 ret = pi_listen(fPilotMasterSocket, 1);
00446 if (ret == -1)
00447 {
00448 char *s = strerror(errno);
00449
00450 kdWarning() << "pi_listen: " << s << endl;
00451
00452
00453
00454 emit logError(i18n("Can't listen on Pilot socket (%1)").
00455 arg(QString::fromLocal8Bit(s)));
00456
00457 close();
00458 return;
00459 }
00460
00461 emit logProgress(QString::null,10);
00462
00463 fCurrentPilotSocket = pi_accept(fPilotMasterSocket, 0, 0);
00464 if (fCurrentPilotSocket == -1)
00465 {
00466 char *s = strerror(errno);
00467
00468 kdWarning() << "pi_accept: " << s << endl;
00469
00470 emit logError(i18n("Can't accept Pilot (%1)")
00471 .arg(QString::fromLocal8Bit(s)));
00472
00473 fStatus = PilotLinkError;
00474 close();
00475 return;
00476 }
00477
00478 if ((fStatus != DeviceOpen) || (fPilotMasterSocket == -1))
00479 {
00480 fStatus = PilotLinkError;
00481 kdError() << k_funcinfo
00482 << ": Already connected or unable to connect!"
00483 << endl;
00484 emit logError(TODO_I18N("Can't accept Pilot (%1)")
00485 .arg(TODO_I18N("already connected")));
00486 close();
00487 return;
00488 }
00489
00490 emit logProgress(QString::null, 30);
00491
00492 fPilotSysInfo = new KPilotSysInfo;
00493 if (dlp_ReadSysInfo(fCurrentPilotSocket, fPilotSysInfo->sysInfo()) < 0)
00494 {
00495 emit logError(i18n("Unable to read system information from Pilot"));
00496 fStatus=PilotLinkError;
00497 return;
00498 }
00499 #ifdef DEBUG
00500 else
00501 {
00502 DEBUGDAEMON << fname
00503 << ": RomVersion=" << fPilotSysInfo->getRomVersion()
00504 << " Locale=" << fPilotSysInfo->getLocale()
00505 #if PILOT_LINK_NUMBER < 10
00506
00507 #else
00508 << " Product=" << fPilotSysInfo->getProductID()
00509 #endif
00510 << endl;
00511 }
00512 #endif
00513 fPilotSysInfo->boundsCheck();
00514
00515 emit logProgress(QString::null, 60);
00516 fPilotUser = new KPilotUser;
00517
00518
00519 #ifdef DEBUG
00520 DEBUGDAEMON << fname << ": Reading user info @"
00521 << (int) fPilotUser << endl;
00522 DEBUGDAEMON << fname << ": Buffer @"
00523 << (int) fPilotUser->pilotUser() << endl;
00524 #endif
00525
00526 dlp_ReadUserInfo(fCurrentPilotSocket, fPilotUser->pilotUser());
00527 fPilotUser->boundsCheck();
00528
00529 #ifdef DEBUG
00530 DEBUGDAEMON << fname
00531 << ": Read user name " << fPilotUser->getUserName() << endl;
00532 #endif
00533
00534 emit logProgress(i18n("Checking last PC..."), 90);
00535
00536
00537 if ((ret=dlp_OpenConduit(fCurrentPilotSocket)) < 0)
00538 {
00539 DEBUGDAEMON << k_funcinfo
00540 << ": dlp_OpenConduit returned " << ret << endl;
00541
00542 #if 0
00543 fStatus = SyncDone;
00544 emit logMessage(i18n
00545 ("Exiting on cancel. All data not restored."));
00546 return;
00547 #endif
00548 emit logError(i18n("Could not read user information from the Pilot. "
00549 "Perhaps you have a password set on the device?"));
00550 }
00551 fStatus = AcceptedDevice;
00552
00553
00554 emit logProgress(QString::null, 100);
00555 emit deviceReady();
00556 }
00557
00558 void KPilotDeviceLink::tickle() const
00559 {
00560 FUNCTIONSETUP;
00561 pi_tickle(pilotSocket());
00562 }
00563
00564
00565 int KPilotDeviceLink::installFiles(const QStringList & l, const bool deleteFiles)
00566 {
00567 FUNCTIONSETUP;
00568
00569 QStringList::ConstIterator i;
00570 int k = 0;
00571 int n = 0;
00572
00573 for (i = l.begin(); i != l.end(); ++i)
00574 {
00575 emit logProgress(QString::null,
00576 (int) ((100.0 / l.count()) * (float) n));
00577
00578 if (installFile(*i, deleteFiles))
00579 k++;
00580 n++;
00581 }
00582 emit logProgress(QString::null, 100);
00583
00584 return k;
00585 }
00586
00587 bool KPilotDeviceLink::installFile(const QString & f, const bool deleteFile)
00588 {
00589 FUNCTIONSETUP;
00590
00591 #ifdef DEBUG
00592 DEBUGDAEMON << fname << ": Installing file " << f << endl;
00593 #endif
00594
00595 if (!QFile::exists(f))
00596 return false;
00597
00598 struct pi_file *pf =
00599 pi_file_open(const_cast < char *>
00600 ((const char *) QFile::encodeName(f)));
00601
00602 if (!f)
00603 {
00604 kdWarning() << k_funcinfo
00605 << ": Can't open file " << f << endl;
00606 emit logError(i18n
00607 ("<qt>Can't install the file "%1".</qt>").
00608 arg(f));
00609 return false;
00610 }
00611
00612 if (pi_file_install(pf, fCurrentPilotSocket, 0) < 0)
00613 {
00614 kdWarning() << k_funcinfo
00615 << ": Can't pi_file_install " << f << endl;
00616 emit logError(i18n
00617 ("<qt>Can't install the file "%1".</qt>").
00618 arg(f));
00619 return false;
00620 }
00621
00622 pi_file_close(pf);
00623 if (deleteFile) QFile::remove(f);
00624
00625 return true;
00626 }
00627
00628
00629 void KPilotDeviceLink::addSyncLogEntry(const QString & entry, bool log)
00630 {
00631 FUNCTIONSETUP;
00632 if (entry.isEmpty()) return;
00633
00634 QString t(entry);
00635
00636 #if (PILOT_LINK_VERSION * 1000 + PILOT_LINK_MAJOR * 10 + PILOT_LINK_MINOR) < 110
00637 t.append("X");
00638 #endif
00639
00640 dlp_AddSyncLogEntry(fCurrentPilotSocket,
00641 const_cast < char *>(t.latin1()));
00642 if (log)
00643 {
00644 emit logMessage(entry);
00645 }
00646 }
00647
00648 int KPilotDeviceLink::openConduit()
00649 {
00650 return dlp_OpenConduit(fCurrentPilotSocket);
00651 }
00652
00653 QString KPilotDeviceLink::deviceTypeString(int i) const
00654 {
00655 FUNCTIONSETUP;
00656 switch (i)
00657 {
00658 case None:
00659 return QString::fromLatin1("None");
00660 case Serial:
00661 return QString::fromLatin1("Serial");
00662 case OldStyleUSB:
00663 return QString::fromLatin1("OldStyleUSB");
00664 case DevFSUSB:
00665 return QString::fromLatin1("DevFSUSB");
00666 default:
00667 return QString::fromLatin1("<unknown>");
00668 }
00669 }
00670
00671 QString KPilotDeviceLink::statusString() const
00672 {
00673 FUNCTIONSETUP;
00674 QString s = QString::fromLatin1("KPilotDeviceLink=");
00675
00676
00677 switch (fStatus)
00678 {
00679 case Init:
00680 s.append(QString::fromLatin1("Init"));
00681 break;
00682 case WaitingForDevice:
00683 s.append(QString::fromLatin1("WaitingForDevice"));
00684 break;
00685 case FoundDevice:
00686 s.append(QString::fromLatin1("FoundDevice"));
00687 break;
00688 case CreatedSocket:
00689 s.append(QString::fromLatin1("CreatedSocket"));
00690 break;
00691 case DeviceOpen:
00692 s.append(QString::fromLatin1("DeviceOpen"));
00693 break;
00694 case AcceptedDevice:
00695 s.append(QString::fromLatin1("AcceptedDevice"));
00696 break;
00697 case SyncDone:
00698 s.append(QString::fromLatin1("SyncDone"));
00699 break;
00700 case PilotLinkError:
00701 s.append(QString::fromLatin1("PilotLinkError"));
00702 break;
00703 }
00704
00705 return s;
00706 }
00707
00708
00709 void KPilotDeviceLink::finishSync()
00710 {
00711 FUNCTIONSETUP ;
00712
00713 getPilotUser()->setLastSyncPC((unsigned long) gethostid());
00714 getPilotUser()->setLastSyncDate(time(0));
00715
00716 dlp_WriteUserInfo(pilotSocket(),getPilotUser()->pilotUser());
00717 addSyncLogEntry(i18n("End of HotSync\n"));
00718 dlp_EndOfSync(pilotSocket(), 0);
00719 }
00720
00721 int KPilotDeviceLink::getNextDatabase(int index,struct DBInfo *dbinfo)
00722 {
00723 FUNCTIONSETUP;
00724
00725 return dlp_ReadDBList(pilotSocket(),0,dlpDBListRAM,index,dbinfo);
00726 }
00727
00728
00729 int KPilotDeviceLink::findDatabase(const char *name, struct DBInfo *dbinfo,
00730 int index, long type, long creator)
00731 {
00732 FUNCTIONSETUP;
00733 return dlp_FindDBInfo(pilotSocket(), 0, index,
00734 const_cast<char *>(name), type, creator, dbinfo);
00735 }
00736
00737 bool KPilotDeviceLink::retrieveDatabase(const QString &fullBackupName,
00738 DBInfo *info)
00739 {
00740 FUNCTIONSETUP;
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750 struct pi_file *f;
00751 f = pi_file_create(const_cast < char *>
00752 ((const char *) (QFile::encodeName(fullBackupName))),
00753 info);
00754
00755 if (f == 0)
00756 {
00757 kdWarning() << k_funcinfo
00758 << ": Failed, unable to create file" << endl;
00759 return false;
00760 }
00761
00762 if (pi_file_retrieve(f, pilotSocket(), 0) < 0)
00763 {
00764 kdWarning() << k_funcinfo
00765 << ": Failed, unable to back up database" << endl;
00766
00767 pi_file_close(f);
00768 return false;
00769 }
00770
00771 pi_file_close(f);
00772 return true;
00773 }
00774
00775
00776 QPtrList<DBInfo> KPilotDeviceLink::getDBList(int cardno, int flags)
00777 {
00778 bool cont=true;
00779 QPtrList<DBInfo>dbs;
00780 int index=0;
00781 while (cont)
00782 {
00783 DBInfo*dbi=new DBInfo();
00784 if (dlp_ReadDBList(pilotSocket(), cardno, flags, index, dbi)<0) {
00785 KPILOT_DELETE(dbi);
00786 cont=false;
00787 } else {
00788 index=dbi->index+1;
00789 dbs.append(dbi);
00790 }
00791 }
00792 return dbs;
00793 }
00794
00795 KPilotCard *KPilotDeviceLink::getCardInfo(int card)
00796 {
00797 KPilotCard *cardinfo=new KPilotCard();
00798 if (dlp_ReadStorageInfo(pilotSocket(), card, cardinfo->cardInfo())<0)
00799 {
00800 KPILOT_DELETE(cardinfo);
00801 return 0L;
00802 };
00803 return cardinfo;
00804 }
00805
00806 QDateTime KPilotDeviceLink::getTime()
00807 {
00808 QDateTime time;
00809 time_t palmtime;
00810 if (dlp_GetSysDateTime(pilotSocket(), &palmtime))
00811 {
00812 time.setTime_t(palmtime);
00813 }
00814 return time;
00815 }
00816
00817 bool KPilotDeviceLink::setTime(const time_t &pctime)
00818 {
00819
00820
00821 return dlp_SetSysDateTime(pilotSocket(), pctime);
00822 }
00823
00824
00825
00826 unsigned long KPilotDeviceLink::ROMversion() const
00827 {
00828 unsigned long rom;
00829 dlp_ReadFeature(pilotSocket(),
00830 makelong(const_cast<char *>("psys")), 1, &rom);
00831 return rom;
00832 }
00833 unsigned long KPilotDeviceLink::majorVersion() const
00834 {
00835 unsigned long rom=ROMversion();
00836 return (((rom >> 28) & 0xf) * 10)+ ((rom >> 24) & 0xf);
00837 }
00838 unsigned long KPilotDeviceLink::minorVersion() const
00839 {
00840 unsigned long int rom=ROMversion();
00841 return (((rom >> 20) & 0xf) * 10)+ ((rom >> 16) & 0xf);
00842 }
00843
00844 const int KPilotDeviceLink::messagesType=
00845 (int)OpenFailMessage ;
00846
00847 void KPilotDeviceLink::shouldPrint(int m,const QString &s)
00848 {
00849 if (!(messages & m))
00850 {
00851 if (messagesType & m) { emit logError(s); }
00852 else { emit logMessage(s); }
00853 messages |= (m & messagesMask);
00854 }
00855 }
00856
00857 bool operator < (const db & a, const db & b) {
00858 if (a.creator == b.creator)
00859 {
00860 if (a.type != b.type)
00861 {
00862 if (a.type == pi_mktag('a', 'p', 'p', 'l'))
00863 return false;
00864 else
00865 return true;
00866 }
00867 }
00868
00869 return a.maxblock < b.maxblock;
00870 }