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
00032
00033
00034 #include "options.h"
00035
00036 #include <stdlib.h>
00037
00038 #include <qdir.h>
00039 #include <qfileinfo.h>
00040 #include <qhbox.h>
00041 #include <qlabel.h>
00042 #include <qlayout.h>
00043 #include <qpushbutton.h>
00044 #include <qregexp.h>
00045 #include <qstringlist.h>
00046 #include <qtabwidget.h>
00047 #include <qtextview.h>
00048 #include <qtimer.h>
00049
00050 #include <dcopclient.h>
00051 #include <kaboutapplication.h>
00052 #include <kactivelabel.h>
00053 #include <kapplication.h>
00054 #include <kglobal.h>
00055 #include <kiconloader.h>
00056 #include <kinstance.h>
00057 #include <klibloader.h>
00058 #include <kmessagebox.h>
00059 #include <kservice.h>
00060 #include <kservicetype.h>
00061 #include <kstandarddirs.h>
00062
00063 #include "pilotSerialDatabase.h"
00064 #include "pilotLocalDatabase.h"
00065
00066 #include "plugin.moc"
00067
00068 ConduitConfigBase::ConduitConfigBase(QWidget *parent,
00069 const char *name) :
00070 QObject(parent,name),
00071 fModified(false),
00072 fWidget(0L),
00073 fConduitName(i18n("Unnamed"))
00074 {
00075 FUNCTIONSETUP;
00076 }
00077
00078 ConduitConfigBase::~ConduitConfigBase()
00079 {
00080 FUNCTIONSETUP;
00081 }
00082
00083 void ConduitConfigBase::modified()
00084 {
00085 fModified=true;
00086 emit changed(true);
00087 }
00088
00089 QString ConduitConfigBase::maybeSaveText() const
00090 {
00091 FUNCTIONSETUP;
00092
00093 return i18n("<qt>The <i>%1</i> conduit's settings have been changed. Do you "
00094 "want to save the changes before continuing?</qt>").arg(this->conduitName());
00095 }
00096
00097 bool ConduitConfigBase::maybeSave()
00098 {
00099 FUNCTIONSETUP;
00100
00101 if (!isModified()) return true;
00102
00103 int r = KMessageBox::questionYesNoCancel(fWidget,
00104 maybeSaveText(),
00105 i18n("%1 Conduit").arg(this->conduitName()), KStdGuiItem::save(), KStdGuiItem::discard());
00106 if (r == KMessageBox::Cancel) return false;
00107 if (r == KMessageBox::Yes) commit();
00108 return true;
00109 }
00110
00111 QWidget *ConduitConfigBase::aboutPage(QWidget *parent, KAboutData *ad)
00112 {
00113 FUNCTIONSETUP;
00114
00115 QWidget *w = new QWidget(parent, "aboutpage");
00116
00117 QString s;
00118 QLabel *text;
00119 KIconLoader *l = KGlobal::iconLoader();
00120 const KAboutData *p = ad ? ad : KGlobal::instance()->aboutData();
00121
00122 QGridLayout *grid = new QGridLayout(w, 5, 4, SPACING);
00123
00124 grid->addColSpacing(0, SPACING);
00125 grid->addColSpacing(4, SPACING);
00126
00127
00128 QPixmap applicationIcon =
00129 l->loadIcon(QString::fromLatin1(p->appName()),
00130 KIcon::Desktop,
00131 64, KIcon::DefaultState, 0L,
00132 true);
00133
00134 if (applicationIcon.isNull())
00135 {
00136 applicationIcon = l->loadIcon(QString::fromLatin1("kpilot"),
00137 KIcon::Desktop);
00138 }
00139
00140 text = new QLabel(w);
00141
00142
00143
00144 text->setText(i18n("Send questions and comments to kdepim-users@kde.org"));
00145 text->adjustSize();
00146
00147 int linewidth = text->size().width();
00148 int lineheight = text->size().height();
00149
00150
00151 text->setText(QString::null);
00152 text->setPixmap(applicationIcon);
00153 text->adjustSize();
00154 grid->addWidget(text, 0, 1);
00155
00156
00157 KActiveLabel *linktext = new KActiveLabel(w);
00158 grid->addRowSpacing(1,kMax(100,6*lineheight));
00159 grid->addRowSpacing(2,kMax(100,6*lineheight));
00160 grid->addColSpacing(2,SPACING+linewidth/2);
00161 grid->addColSpacing(3,SPACING+linewidth/2);
00162 grid->setRowStretch(1,50);
00163 grid->setRowStretch(2,50);
00164 grid->setColStretch(2,50);
00165 grid->setColStretch(3,50);
00166 linktext->setMinimumSize(linewidth,kMax(260,60+12*lineheight));
00167 linktext->setFixedHeight(kMax(260,60+12*lineheight));
00168 linktext->setVScrollBarMode(QScrollView::Auto);
00169 text = new QLabel(w);
00170 grid->addMultiCellWidget(text,0,0,2,3);
00171 grid->addMultiCellWidget(linktext,1,2,1,3);
00172
00173
00174 s = CSL1("<qt><h3>");
00175 s += p->programName();
00176 s += ' ';
00177 s += p->version();
00178 s += CSL1("</h3>");
00179 s += p->copyrightStatement() + CSL1("<br></qt>");
00180 text->setText(s);
00181
00182 linktext->append(p->shortDescription() + CSL1("<br>"));
00183
00184 if (!p->homepage().isEmpty())
00185 {
00186 s = QString::null;
00187 s += CSL1("<a href=\"%1\">").arg(p->homepage());
00188 s += p->homepage();
00189 s += CSL1("</a><br>");
00190 linktext->append(s);
00191 }
00192
00193 s = QString::null;
00194 s += i18n("Send questions and comments to <a href=\"mailto:%1\">%2</a>.")
00195 .arg( CSL1("kdepim-users@kde.org") )
00196 .arg( CSL1("kdepim-users@kde.org") );
00197 s += ' ';
00198 s += i18n("Send bug reports to <a href=\"mailto:%1\">%2</a>.")
00199 .arg(p->bugAddress())
00200 .arg(p->bugAddress());
00201 s += ' ';
00202 s += i18n("For trademark information, see the "
00203 "<a href=\"help:/kpilot/trademarks.html\">KPilot User's Guide</a>.");
00204 s += CSL1("<br>");
00205 linktext->append(s);
00206 linktext->append(QString::null);
00207
00208
00209
00210 QValueList<KAboutPerson> pl = p->authors();
00211 QValueList<KAboutPerson>::ConstIterator i;
00212
00213 s = i18n("<b>Authors:</b> ");
00214
00215 QString comma = CSL1(", ");
00216
00217 unsigned int count=1;
00218 for (i=pl.begin(); i!=pl.end(); ++i)
00219 {
00220 s.append(CSL1("%1 (<i>%2</i>)%3")
00221 .arg((*i).name())
00222 .arg((*i).task())
00223 .arg(count<pl.count() ? comma : QString::null)
00224 );
00225 count++;
00226 }
00227 linktext->append(s);
00228
00229 s = QString::null;
00230 pl = p->credits();
00231 if (pl.count()>0)
00232 {
00233 count=1;
00234 s.append(i18n("<b>Credits:</b> "));
00235 for (i=pl.begin(); i!=pl.end(); ++i)
00236 {
00237 s.append(CSL1("%1 (<i>%2</i>)%3")
00238 .arg((*i).name())
00239 .arg((*i).task())
00240 .arg(count<pl.count() ? comma : QString::null)
00241 );
00242 count++;
00243 }
00244 }
00245 linktext->append(s);
00246 linktext->ensureVisible(0,0);
00247
00248 w->adjustSize();
00249
00250 return w;
00251 }
00252
00253 void ConduitConfigBase::addAboutPage(QTabWidget *tw,
00254 KAboutData *ad)
00255 {
00256 FUNCTIONSETUP;
00257
00258 Q_ASSERT(tw);
00259
00260 QWidget *w = aboutPage(tw,ad);
00261 QSize sz = w->size();
00262
00263 if (sz.width() < tw->size().width())
00264 {
00265 sz.setWidth(tw->size().width());
00266 }
00267 if (sz.height() < tw->size().height())
00268 {
00269 sz.setHeight(tw->size().height());
00270 }
00271
00272 tw->resize(sz);
00273 tw->addTab(w, i18n("About"));
00274 tw->adjustSize();
00275 }
00276
00277
00278
00279 ConduitAction::ConduitAction(KPilotLink *p,
00280 const char *name,
00281 const QStringList &args) :
00282 SyncAction(p,name),
00283 fDatabase(0L),
00284 fLocalDatabase(0L),
00285 fCtrHH(0L),
00286 fCtrPC(0L),
00287 fSyncDirection(args),
00288 fConflictResolution(SyncAction::eAskUser),
00289 fFirstSync(false)
00290 {
00291 FUNCTIONSETUP;
00292
00293 QString cResolution(args.grep(QRegExp(CSL1("--conflictResolution \\d*"))).first());
00294 if (cResolution.isEmpty())
00295 {
00296 fConflictResolution=(SyncAction::ConflictResolution)
00297 cResolution.replace(QRegExp(CSL1("--conflictResolution (\\d*)")), CSL1("\\1")).toInt();
00298 }
00299
00300 for (QStringList::ConstIterator it = args.begin();
00301 it != args.end();
00302 ++it)
00303 {
00304 DEBUGKPILOT << fname << ": " << *it << endl;
00305 }
00306
00307 DEBUGKPILOT << fname << ": Direction=" << fSyncDirection.name() << endl;
00308 fCtrHH = new CUDCounter(i18n("Handheld"));
00309 fCtrPC = new CUDCounter(i18n("PC"));
00310 }
00311
00312 ConduitAction::~ConduitAction()
00313 {
00314 FUNCTIONSETUP;
00315
00316 KPILOT_DELETE(fDatabase);
00317 KPILOT_DELETE(fLocalDatabase);
00318
00319 KPILOT_DELETE(fCtrHH);
00320 KPILOT_DELETE(fCtrPC);
00321 }
00322
00323 bool ConduitAction::openDatabases(const QString &name, bool *retrieved)
00324 {
00325 FUNCTIONSETUP;
00326
00327 DEBUGKPILOT << fname
00328 << ": Trying to open database "
00329 << name << endl;
00330 DEBUGKPILOT << fname
00331 << ": Mode="
00332 << (syncMode().isTest() ? "test " : "")
00333 << (syncMode().isLocal() ? "local " : "")
00334 << endl ;
00335
00336 KPILOT_DELETE(fLocalDatabase);
00337
00338 QString localPathName = PilotLocalDatabase::getDBPath() + name;
00339
00340
00341
00342
00343 localPathName.replace(CSL1("DBBackup/"), CSL1("conduits/"));
00344
00345 DEBUGKPILOT << fname << ": localPathName: [" << localPathName
00346 << "]" << endl;
00347
00348 PilotLocalDatabase *localDB = new PilotLocalDatabase( localPathName );
00349
00350 if (!localDB)
00351 {
00352 WARNINGKPILOT << "Could not initialize object for local copy of database \""
00353 << name
00354 << "\"" << endl;
00355 if (retrieved) *retrieved = false;
00356 return false;
00357 }
00358
00359
00360 if (!localDB->isOpen() )
00361 {
00362 QString dbpath(localDB->dbPathName());
00363 KPILOT_DELETE(localDB);
00364 DEBUGKPILOT << fname
00365 << ": Backup database " << dbpath
00366 << " not found." << endl;
00367 struct DBInfo dbinfo;
00368
00369
00370 if (deviceLink()->findDatabase(Pilot::toPilot( name ), &dbinfo)<0 )
00371 {
00372 WARNINGKPILOT << "Could not get DBInfo for " << name << endl;
00373 if (retrieved) *retrieved = false;
00374 return false;
00375 }
00376
00377 DEBUGKPILOT << fname
00378 << ": Found Palm database: " << dbinfo.name <<endl
00379 << fname << ": type = " << dbinfo.type
00380 << " creator = " << dbinfo.creator
00381 << " version = " << dbinfo.version
00382 << " index = " << dbinfo.index << endl;
00383 dbinfo.flags &= ~dlpDBFlagOpen;
00384
00385
00386 QFileInfo fi(dbpath);
00387 QString path(QFileInfo(dbpath).dir(true).absPath());
00388 if (!path.endsWith(CSL1("/"))) path.append(CSL1("/"));
00389 if (!KStandardDirs::exists(path))
00390 {
00391 DEBUGKPILOT << fname << ": Trying to create path for database: <"
00392 << path << ">" << endl;
00393 KStandardDirs::makeDir(path);
00394 }
00395 if (!KStandardDirs::exists(path))
00396 {
00397 DEBUGKPILOT << fname << ": Database directory does not exist." << endl;
00398 if (retrieved) *retrieved = false;
00399 return false;
00400 }
00401
00402 if (!deviceLink()->retrieveDatabase(dbpath, &dbinfo) )
00403 {
00404 WARNINGKPILOT << "Could not retrieve database "
00405 << name << " from the handheld." << endl;
00406 if (retrieved) *retrieved = false;
00407 return false;
00408 }
00409 localDB = new PilotLocalDatabase( localPathName );
00410 if (!localDB || !localDB->isOpen())
00411 {
00412 WARNINGKPILOT << "local backup of database " << name << " could not be initialized." << endl;
00413 if (retrieved) *retrieved = false;
00414 return false;
00415 }
00416 if (retrieved) *retrieved=true;
00417 }
00418 fLocalDatabase = localDB;
00419
00420 fDatabase = deviceLink()->database( name );
00421
00422 if (!fDatabase)
00423 {
00424 WARNINGKPILOT << "Could not open database \""
00425 << name
00426 << "\" on the pilot."
00427 << endl;
00428 }
00429 else
00430 {
00431 fCtrHH->setStartCount(fDatabase->recordCount());
00432 }
00433
00434 return (fDatabase && fDatabase->isOpen() &&
00435 fLocalDatabase && fLocalDatabase->isOpen() );
00436 }
00437
00438
00439 bool ConduitAction::changeSync(SyncMode::Mode m)
00440 {
00441 FUNCTIONSETUP;
00442
00443 if ( fSyncDirection.isSync() && SyncMode::eFullSync == m)
00444 {
00445 fSyncDirection.setMode(m);
00446 return true;
00447 }
00448 return false;
00449 }
00450
00451 void ConduitAction::finished()
00452 {
00453 FUNCTIONSETUP;
00454
00455 if (fDatabase && fCtrHH)
00456 fCtrHH->setEndCount(fDatabase->recordCount());
00457
00458 if (fCtrHH && fCtrPC)
00459 {
00460 addSyncLogEntry(fCtrHH->moo() +"\n",false);
00461 DEBUGKPILOT << fname << ": " << fCtrHH->moo() << endl;
00462 addSyncLogEntry(fCtrPC->moo() +"\n",false);
00463 DEBUGKPILOT << fname << ": " << fCtrPC->moo() << endl;
00464
00465
00466
00467
00468 int hhVolatility = fCtrHH->percentDeleted() +
00469 fCtrHH->percentUpdated() +
00470 fCtrHH->percentCreated();
00471
00472 int pcVolatility = fCtrPC->percentDeleted() +
00473 fCtrPC->percentUpdated() +
00474 fCtrPC->percentCreated();
00475
00476
00477
00478 int allowedVolatility = 70;
00479
00480 QString caption = i18n("Large Changes Detected");
00481
00482 QString query = i18n("The %1 conduit has made a "
00483 "large number of changes to your %2. Do you want "
00484 "to allow this change?\nDetails:\n\t%3");
00485
00486 if (hhVolatility > allowedVolatility)
00487 {
00488 query = query.arg(fConduitName)
00489 .arg(fCtrHH->type()).arg(fCtrHH->moo());
00490
00491 DEBUGKPILOT << fname << ": Yikes, lots of volatility "
00492 << "caught. Check with user: [" << query
00493 << "]." << endl;
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508 }
00509
00510
00511 }
00512
00513 }
00514
00515
00516 ConduitProxy::ConduitProxy(KPilotLink *p,
00517 const QString &name,
00518 const SyncAction::SyncMode &m) :
00519 ConduitAction(p,name.latin1(),m.list()),
00520 fDesktopName(name)
00521 {
00522 FUNCTIONSETUP;
00523 }
00524
00525 bool ConduitProxy::exec()
00526 {
00527 FUNCTIONSETUP;
00528
00529
00530 KSharedPtr < KService > o = KService::serviceByDesktopName(fDesktopName);
00531 if (!o)
00532 {
00533 WARNINGKPILOT << "Can't find desktop file for conduit "
00534 << fDesktopName
00535 << endl;
00536 addSyncLogEntry(i18n("Could not find conduit %1.").arg(fDesktopName));
00537 return false;
00538 }
00539
00540
00541
00542 fLibraryName = o->library();
00543 DEBUGKPILOT << fname
00544 << ": Loading desktop "
00545 << fDesktopName
00546 << " with lib "
00547 << fLibraryName
00548 << endl;
00549
00550 KLibrary *library = KLibLoader::self()->library(
00551 QFile::encodeName(fLibraryName));
00552 if (!library)
00553 {
00554 WARNINGKPILOT << "Can't load library "
00555 << fLibraryName
00556 << " - "
00557 << KLibLoader::self()->lastErrorMessage()
00558 << endl;
00559 addSyncLogEntry(i18n("Could not load conduit %1.").arg(fDesktopName));
00560 return false;
00561 }
00562
00563 unsigned long version = PluginUtility::pluginVersion(library);
00564 if ( Pilot::PLUGIN_API != version )
00565 {
00566 WARNINGKPILOT << "Library "
00567 << fLibraryName
00568 << " has version "
00569 << version
00570 << endl;
00571 addSyncLogEntry(i18n("Conduit %1 has wrong version (%2).").arg(fDesktopName).arg(version));
00572 return false;
00573 }
00574
00575 KLibFactory *factory = library->factory();
00576 if (!factory)
00577 {
00578 WARNINGKPILOT << "Can't find factory in library "
00579 << fLibraryName
00580 << endl;
00581 addSyncLogEntry(i18n("Could not initialize conduit %1.").arg(fDesktopName));
00582 return false;
00583 }
00584
00585 QStringList l = syncMode().list();
00586
00587 DEBUGKPILOT << fname << ": Flags: " << syncMode().name() << endl;
00588
00589 QObject *object = factory->create(fHandle,name(),"SyncAction",l);
00590
00591 if (!object)
00592 {
00593 WARNINGKPILOT << "Can't create SyncAction." << endl;
00594 addSyncLogEntry(i18n("Could not create conduit %1.").arg(fDesktopName));
00595 return false;
00596 }
00597
00598 fConduit = dynamic_cast<ConduitAction *>(object);
00599
00600 if (!fConduit)
00601 {
00602 WARNINGKPILOT << "Can't cast to ConduitAction." << endl;
00603 addSyncLogEntry(i18n("Could not create conduit %1.").arg(fDesktopName));
00604 return false;
00605 }
00606
00607 addSyncLogEntry(i18n("[Conduit %1]").arg(fDesktopName));
00608
00609
00610 QObject::connect(fConduit,SIGNAL(syncDone(SyncAction *)),
00611 this,SLOT(execDone(SyncAction *)));
00612
00613 QObject::connect(fConduit,SIGNAL(logMessage(const QString &)),
00614 this,SIGNAL(logMessage(const QString &)));
00615 QObject::connect(fConduit,SIGNAL(logError(const QString &)),
00616 this,SIGNAL(logError(const QString &)));
00617 QObject::connect(fConduit,SIGNAL(logProgress(const QString &,int)),
00618 this,SIGNAL(logProgress(const QString &,int)));
00619
00620 QTimer::singleShot(0,fConduit,SLOT(execConduit()));
00621 return true;
00622 }
00623
00624 void ConduitProxy::execDone(SyncAction *p)
00625 {
00626 FUNCTIONSETUP;
00627
00628 if (p!=fConduit)
00629 {
00630 WARNINGKPILOT << "Unknown conduit @"
00631 << (void *) p
00632 << " finished."
00633 << endl;
00634 emit syncDone(this);
00635 return;
00636 }
00637
00638
00639 fConduit->finished();
00640
00641 addSyncLogEntry(CSL1("\n"),false);
00642
00643 KPILOT_DELETE(p);
00644
00645 emit syncDone(this);
00646 }
00647
00648
00649 namespace PluginUtility
00650 {
00651
00652 QString findArgument(const QStringList &a, const QString &arg)
00653 {
00654 FUNCTIONSETUP;
00655
00656 QString search;
00657
00658 if (arg.startsWith( CSL1("--") ))
00659 {
00660 search = arg;
00661 }
00662 else
00663 {
00664 search = CSL1("--") + arg;
00665 }
00666 search.append( CSL1("=") );
00667
00668
00669 QStringList::ConstIterator end = a.end();
00670 for (QStringList::ConstIterator i = a.begin(); i != end; ++i)
00671 {
00672 if ((*i).startsWith( search ))
00673 {
00674 QString s = (*i).mid(search.length());
00675 return s;
00676 }
00677 }
00678
00679 return QString::null;
00680 }
00681
00682 bool isRunning(const QCString &n)
00683 {
00684 DCOPClient *dcop = KApplication::kApplication()->dcopClient();
00685 QCStringList apps = dcop->registeredApplications();
00686 return apps.contains(n);
00687 }
00688
00689
00690 unsigned long pluginVersion(const KLibrary *lib)
00691 {
00692 QString symbol = CSL1("version_");
00693 symbol.append(lib->name());
00694
00695 if (!lib->hasSymbol(symbol.latin1())) return 0;
00696
00697 unsigned long *p = (unsigned long *)(lib->symbol(symbol.latin1()));
00698 return *p;
00699 }
00700
00701
00702 QString pluginVersionString(const KLibrary *lib)
00703 {
00704 QString symbol= CSL1("id_");
00705 symbol.append(lib->name());
00706
00707 if (!lib->hasSymbol(symbol.latin1())) return QString::null;
00708
00709 return QString::fromLatin1(*((const char **)(lib->symbol(symbol.latin1()))));
00710 }
00711
00712
00713 }
00714
00715
00716 CUDCounter::CUDCounter(QString s) :
00717 fC(0),fU(0),fD(0),fStart(0),fEnd(0),fType(s)
00718 {
00719 }
00720
00721 void CUDCounter::created(unsigned int c)
00722 {
00723 fC += c;
00724 }
00725
00726 void CUDCounter::updated(unsigned int c)
00727 {
00728 fU += c;
00729 }
00730
00731 void CUDCounter::deleted(unsigned int c)
00732 {
00733 fD += c;
00734 }
00735
00736 void CUDCounter::setStartCount(unsigned int t)
00737 {
00738 fStart = t;
00739 }
00740
00741 void CUDCounter::setEndCount(unsigned int t)
00742 {
00743 fEnd = t;
00744 }
00745
00746 QString CUDCounter::moo() const
00747 {
00748 QString result = fType + ": " +
00749 i18n("Start: %1. End: %2. ").arg(fStart).arg(fEnd);
00750
00751 if (fC > 0) result += i18n("%1 new. ").arg(fC);
00752 if (fU > 0) result += i18n("%1 changed. ").arg(fU);
00753 if (fD > 0) result += i18n("%1 deleted. ").arg(fD);
00754
00755 if ( (fC+fU+fD) <= 0) result += i18n("No changes made. ");
00756
00757 return result;
00758 }
00759
00760