00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <qdir.h>
00021 #include <qeventloop.h>
00022 #include <config.h>
00023
00024 #include "kbuildsycoca.h"
00025 #include "kresourcelist.h"
00026 #include "vfolder_menu.h"
00027
00028 #include <kservice.h>
00029 #include <kmimetype.h>
00030 #include <kbuildservicetypefactory.h>
00031 #include <kbuildservicefactory.h>
00032 #include <kbuildservicegroupfactory.h>
00033 #include <kbuildimageiofactory.h>
00034 #include <kbuildprotocolinfofactory.h>
00035 #include <kctimefactory.h>
00036 #include <kdatastream.h>
00037
00038 #include <qdatastream.h>
00039 #include <qfile.h>
00040 #include <qtimer.h>
00041
00042 #include <assert.h>
00043 #include <kapplication.h>
00044 #include <dcopclient.h>
00045 #include <kglobal.h>
00046 #include <kdebug.h>
00047 #include <kdirwatch.h>
00048 #include <kstandarddirs.h>
00049 #include <ksavefile.h>
00050 #include <klocale.h>
00051 #include <kaboutdata.h>
00052 #include <kcmdlineargs.h>
00053 #include <kcrash.h>
00054
00055 #ifdef KBUILDSYCOCA_GUI // KBUILDSYCOCA_GUI is used on win32 to build
00056
00057 # include <qlabel.h>
00058 # include <kmessagebox.h>
00059 bool silent;
00060 bool showprogress;
00061 #endif
00062
00063 #include <stdlib.h>
00064 #include <unistd.h>
00065 #include <time.h>
00066 #include <memory>
00067
00068 typedef QDict<KSycocaEntry> KBSEntryDict;
00069 typedef QValueList<KSycocaEntry::List> KSycocaEntryListList;
00070
00071 static Q_UINT32 newTimestamp = 0;
00072
00073 static KBuildServiceFactory *g_bsf = 0;
00074 static KBuildServiceGroupFactory *g_bsgf = 0;
00075 static KSycocaFactory *g_factory = 0;
00076 static KCTimeInfo *g_ctimeInfo = 0;
00077 static QDict<Q_UINT32> *g_ctimeDict = 0;
00078 static const char *g_resource = 0;
00079 static KBSEntryDict *g_entryDict = 0;
00080 static KBSEntryDict *g_serviceGroupEntryDict = 0;
00081 static KSycocaEntryListList *g_allEntries = 0;
00082 static QStringList *g_changeList = 0;
00083 static QStringList *g_allResourceDirs = 0;
00084 static bool g_changed = false;
00085 static KSycocaEntry::List g_tempStorage;
00086 static VFolderMenu *g_vfolder = 0;
00087
00088 static const char *cSycocaPath = 0;
00089
00090 static bool bGlobalDatabase = false;
00091 static bool bMenuTest = false;
00092
00093 void crashHandler(int)
00094 {
00095
00096
00097 if (cSycocaPath)
00098 unlink(cSycocaPath);
00099 }
00100
00101 static QString sycocaPath()
00102 {
00103 QString path;
00104
00105 if (bGlobalDatabase)
00106 {
00107 path = KGlobal::dirs()->saveLocation("services")+"ksycoca";
00108 }
00109 else
00110 {
00111 QCString ksycoca_env = getenv("KDESYCOCA");
00112 if (ksycoca_env.isEmpty())
00113 path = KGlobal::dirs()->saveLocation("cache")+"ksycoca";
00114 else
00115 path = QFile::decodeName(ksycoca_env);
00116 }
00117
00118 return path;
00119 }
00120
00121 static QString oldSycocaPath()
00122 {
00123 QCString ksycoca_env = getenv("KDESYCOCA");
00124 if (ksycoca_env.isEmpty())
00125 return KGlobal::dirs()->saveLocation("tmp")+"ksycoca";
00126
00127 return QString::null;
00128 }
00129
00130 KBuildSycoca::KBuildSycoca()
00131 : KSycoca( true )
00132 {
00133 }
00134
00135 KBuildSycoca::~KBuildSycoca()
00136 {
00137
00138 }
00139
00140 void KBuildSycoca::processGnomeVfs()
00141 {
00142 QString file = locate("app-reg", "gnome-vfs.applications");
00143 if (file.isEmpty())
00144 {
00145
00146 return;
00147 }
00148
00149 QString app;
00150
00151 char line[1024*64];
00152
00153 FILE *f = fopen(QFile::encodeName(file), "r");
00154 while (!feof(f))
00155 {
00156 if (!fgets(line, sizeof(line)-1, f))
00157 {
00158 break;
00159 }
00160
00161 if (line[0] != '\t')
00162 {
00163 app = QString::fromLatin1(line);
00164 app.truncate(app.length()-1);
00165 }
00166 else if (strncmp(line+1, "mime_types=", 11) == 0)
00167 {
00168 QString mimetypes = QString::fromLatin1(line+12);
00169 mimetypes.truncate(mimetypes.length()-1);
00170 mimetypes.replace(QRegExp("\\*"), "all");
00171 KService *s = g_bsf->findServiceByName(app);
00172 if (!s)
00173 continue;
00174
00175 QStringList &serviceTypes = s->accessServiceTypes();
00176 if (serviceTypes.count() <= 1)
00177 {
00178 serviceTypes += QStringList::split(',', mimetypes);
00179
00180
00181 }
00182 }
00183 }
00184 fclose( f );
00185 }
00186
00187 KSycocaEntry *KBuildSycoca::createEntry(const QString &file, bool addToFactory)
00188 {
00189 Q_UINT32 timeStamp = g_ctimeInfo->ctime(file);
00190 if (!timeStamp)
00191 {
00192 timeStamp = KGlobal::dirs()->calcResourceHash( g_resource, file, true);
00193 }
00194 KSycocaEntry* entry = 0;
00195 if (g_allEntries)
00196 {
00197 assert(g_ctimeDict);
00198 Q_UINT32 *timeP = (*g_ctimeDict)[file];
00199 Q_UINT32 oldTimestamp = timeP ? *timeP : 0;
00200
00201 if (timeStamp && (timeStamp == oldTimestamp))
00202 {
00203
00204 if (g_factory == g_bsgf)
00205 {
00206 entry = g_entryDict->find(file.left(file.length()-10));
00207 }
00208 else if (g_factory == g_bsf)
00209 {
00210 entry = g_entryDict->find(file);
00211 }
00212 else
00213 {
00214 entry = g_entryDict->find(file);
00215 }
00216
00217
00218
00219 g_ctimeDict->remove( file );
00220 }
00221 else if (oldTimestamp)
00222 {
00223 g_changed = true;
00224 kdDebug(7021) << "modified: " << file << endl;
00225 }
00226 else
00227 {
00228 g_changed = true;
00229 kdDebug(7021) << "new: " << file << endl;
00230 }
00231 }
00232 g_ctimeInfo->addCTime(file, timeStamp );
00233 if (!entry)
00234 {
00235
00236 entry = g_factory->createEntry( file, g_resource );
00237 }
00238 if ( entry && entry->isValid() )
00239 {
00240 if (addToFactory)
00241 g_factory->addEntry( entry, g_resource );
00242 else
00243 g_tempStorage.append(entry);
00244 return entry;
00245 }
00246 return 0;
00247 }
00248
00249 void KBuildSycoca::slotCreateEntry(const QString &file, KService **service)
00250 {
00251 KSycocaEntry *entry = createEntry(file, false);
00252 *service = dynamic_cast<KService *>(entry);
00253 }
00254
00255
00256 bool KBuildSycoca::build()
00257 {
00258 typedef QPtrList<KBSEntryDict> KBSEntryDictList;
00259 KBSEntryDictList *entryDictList = 0;
00260 KBSEntryDict *serviceEntryDict = 0;
00261
00262 entryDictList = new KBSEntryDictList();
00263
00264 int i = 0;
00265
00266 for (KSycocaFactory *factory = m_lstFactories->first();
00267 factory;
00268 factory = m_lstFactories->next() )
00269 {
00270 KBSEntryDict *entryDict = new KBSEntryDict();
00271 if (g_allEntries)
00272 {
00273 KSycocaEntry::List list = (*g_allEntries)[i++];
00274 for( KSycocaEntry::List::Iterator it = list.begin();
00275 it != list.end();
00276 ++it)
00277 {
00278 entryDict->insert( (*it)->entryPath(), static_cast<KSycocaEntry *>(*it));
00279 }
00280 }
00281 if (factory == g_bsf)
00282 serviceEntryDict = entryDict;
00283 else if (factory == g_bsgf)
00284 g_serviceGroupEntryDict = entryDict;
00285 entryDictList->append(entryDict);
00286 }
00287
00288 QStringList allResources;
00289
00290 for (KSycocaFactory *factory = m_lstFactories->first();
00291 factory;
00292 factory = m_lstFactories->next() )
00293 {
00294
00295 const KSycocaResourceList *list = factory->resourceList();
00296 if (!list) continue;
00297
00298 for( KSycocaResourceList::ConstIterator it1 = list->begin();
00299 it1 != list->end();
00300 ++it1 )
00301 {
00302 KSycocaResource res = (*it1);
00303 if (!allResources.contains(res.resource))
00304 allResources.append(res.resource);
00305 }
00306 }
00307
00308 g_ctimeInfo = new KCTimeInfo();
00309 bool uptodate = true;
00310
00311 for( QStringList::ConstIterator it1 = allResources.begin();
00312 it1 != allResources.end();
00313 ++it1 )
00314 {
00315 g_changed = false;
00316 g_resource = (*it1).ascii();
00317
00318 QStringList relFiles;
00319
00320 (void) KGlobal::dirs()->findAllResources( g_resource,
00321 QString::null,
00322 true,
00323 true,
00324 relFiles);
00325
00326
00327
00328
00329 g_entryDict = entryDictList->first();
00330 for (g_factory = m_lstFactories->first();
00331 g_factory;
00332 g_factory = m_lstFactories->next(),
00333 g_entryDict = entryDictList->next() )
00334 {
00335
00336 const KSycocaResourceList *list = g_factory->resourceList();
00337 if (!list) continue;
00338
00339 for( KSycocaResourceList::ConstIterator it2 = list->begin();
00340 it2 != list->end();
00341 ++it2 )
00342 {
00343 KSycocaResource res = (*it2);
00344 if (res.resource != (*it1)) continue;
00345
00346
00347 for( QStringList::ConstIterator it3 = relFiles.begin();
00348 it3 != relFiles.end();
00349 ++it3 )
00350 {
00351
00352 if ((*it3).endsWith(res.extension))
00353 createEntry(*it3, true);
00354 }
00355 }
00356 if ((g_factory == g_bsf) && (strcmp(g_resource, "services") == 0))
00357 processGnomeVfs();
00358 }
00359 if (g_changed || !g_allEntries)
00360 {
00361 uptodate = false;
00362 g_changeList->append(g_resource);
00363 }
00364 }
00365
00366 bool result = !uptodate || !g_ctimeDict->isEmpty();
00367
00368 if (result || bMenuTest)
00369 {
00370 g_resource = "apps";
00371 g_factory = g_bsf;
00372 g_entryDict = serviceEntryDict;
00373 g_changed = false;
00374
00375 g_vfolder = new VFolderMenu;
00376 if (!m_trackId.isEmpty())
00377 g_vfolder->setTrackId(m_trackId);
00378
00379 connect(g_vfolder, SIGNAL(newService(const QString &, KService **)),
00380 this, SLOT(slotCreateEntry(const QString &, KService **)));
00381
00382 VFolderMenu::SubMenu *kdeMenu;
00383 if ( QFile::exists( "/etc/xdg/menus/kde-applications.menu" ) )
00384 kdeMenu = g_vfolder->parseMenu("kde-applications.menu", true);
00385 else
00386 kdeMenu = g_vfolder->parseMenu("applications.menu", true);
00387
00388 KServiceGroup *entry = g_bsgf->addNew("/", kdeMenu->directoryFile, 0, false);
00389 entry->setLayoutInfo(kdeMenu->layoutList);
00390 createMenu(QString::null, QString::null, kdeMenu);
00391
00392 KServiceGroup::Ptr g(entry);
00393 createMenuAttribute( g );
00394
00395 (void) existingResourceDirs();
00396 *g_allResourceDirs += g_vfolder->allDirectories();
00397
00398 disconnect(g_vfolder, SIGNAL(newService(const QString &, KService **)),
00399 this, SLOT(slotCreateEntry(const QString &, KService **)));
00400
00401 if (g_changed || !g_allEntries)
00402 {
00403 uptodate = false;
00404 g_changeList->append(g_resource);
00405 }
00406 if (bMenuTest)
00407 return false;
00408 }
00409
00410 return result;
00411 }
00412
00413 void KBuildSycoca::createMenuAttribute( KServiceGroup::Ptr entry )
00414 {
00415 KServiceGroup::List list = entry->entries(true, true);
00416 KServiceGroup::List::ConstIterator it = list.begin();
00417 for (; it != list.end(); ++it) {
00418 KSycocaEntry * e = *it;
00419 if (e->isType(KST_KServiceGroup)) {
00420 KServiceGroup::Ptr g(static_cast<KServiceGroup *>(e));
00421 createMenuAttribute( g );
00422 }
00423 }
00424 }
00425
00426
00427 void KBuildSycoca::createMenu(QString caption, QString name, VFolderMenu::SubMenu *menu)
00428 {
00429 for(VFolderMenu::SubMenu *subMenu = menu->subMenus.first(); subMenu; subMenu = menu->subMenus.next())
00430 {
00431 QString subName = name+subMenu->name+"/";
00432
00433 QString directoryFile = subMenu->directoryFile;
00434 if (directoryFile.isEmpty())
00435 directoryFile = subName+".directory";
00436 Q_UINT32 timeStamp = g_ctimeInfo->ctime(directoryFile);
00437 if (!timeStamp)
00438 {
00439 timeStamp = KGlobal::dirs()->calcResourceHash( g_resource, directoryFile, true);
00440 }
00441
00442 KServiceGroup* entry = 0;
00443 if (g_allEntries)
00444 {
00445 Q_UINT32 *timeP = (*g_ctimeDict)[directoryFile];
00446 Q_UINT32 oldTimestamp = timeP ? *timeP : 0;
00447
00448 if (timeStamp && (timeStamp == oldTimestamp))
00449 {
00450 entry = dynamic_cast<KServiceGroup *> (g_serviceGroupEntryDict->find(subName));
00451 if (entry && (entry->directoryEntryPath() != directoryFile))
00452 entry = 0;
00453 }
00454 }
00455 g_ctimeInfo->addCTime(directoryFile, timeStamp);
00456
00457 entry = g_bsgf->addNew(subName, subMenu->directoryFile, entry, subMenu->isDeleted);
00458 entry->setLayoutInfo(subMenu->layoutList);
00459 if (! (bMenuTest && entry->noDisplay()) )
00460 createMenu(caption + entry->caption() + "/", subName, subMenu);
00461 }
00462 if (caption.isEmpty())
00463 caption += "/";
00464 if (name.isEmpty())
00465 name += "/";
00466 for(QDictIterator<KService> it(menu->items); it.current(); ++it)
00467 {
00468 if (bMenuTest)
00469 {
00470 if (!menu->isDeleted && !it.current()->noDisplay())
00471 printf("%s\t%s\t%s\n", caption.local8Bit().data(), it.current()->menuId().local8Bit().data(), locate("apps", it.current()->desktopEntryPath()).local8Bit().data());
00472 }
00473 else
00474 {
00475 g_bsf->addEntry( it.current(), g_resource );
00476 g_bsgf->addNewEntryTo(name, it.current());
00477 }
00478 }
00479 }
00480
00481 bool KBuildSycoca::recreate()
00482 {
00483 QString path(sycocaPath());
00484 #ifdef Q_WS_WIN
00485 printf("kbuildsycoca: path='%s'\n", (const char*)path);
00486 #endif
00487
00488
00489
00490 std::auto_ptr<KSaveFile> database( new KSaveFile(path) );
00491 if (database->status() == EACCES && QFile::exists(path))
00492 {
00493 QFile::remove( path );
00494 database.reset( new KSaveFile(path) );
00495 }
00496 if (database->status() != 0)
00497 {
00498 fprintf(stderr, "kbuildsycoca: ERROR creating database '%s'! %s\n", path.local8Bit().data(),strerror(database->status()));
00499 #ifdef KBUILDSYCOCA_GUI // KBUILDSYCOCA_GUI is used on win32 to build
00500
00501 if (!silent)
00502 KMessageBox::error(0, i18n("Error creating database '%1'.\nCheck that the permissions are correct on the directory and the disk is not full.\n").arg(path.local8Bit().data()), i18n("KBuildSycoca"));
00503 #endif
00504 return false;
00505 }
00506
00507 m_str = database->dataStream();
00508
00509 kdDebug(7021) << "Recreating ksycoca file (" << path << ", version " << KSycoca::version() << ")" << endl;
00510
00511
00512
00513 KSycocaFactory *stf = new KBuildServiceTypeFactory;
00514 g_bsgf = new KBuildServiceGroupFactory();
00515 g_bsf = new KBuildServiceFactory(stf, g_bsgf);
00516 (void) new KBuildImageIOFactory();
00517 (void) new KBuildProtocolInfoFactory();
00518
00519 if( build())
00520 {
00521 save();
00522 if (m_str->device()->status())
00523 database->abort();
00524 m_str = 0L;
00525 if (!database->close())
00526 {
00527 fprintf(stderr, "kbuildsycoca: ERROR writing database '%s'!\n", database->name().local8Bit().data());
00528 fprintf(stderr, "kbuildsycoca: Disk full?\n");
00529 #ifdef KBUILDSYCOCA_GUI
00530 if (!silent)
00531 KMessageBox::error(0, i18n("Error writing database '%1'.\nCheck that the permissions are correct on the directory and the disk is not full.\n").arg(path.local8Bit().data()), i18n("KBuildSycoca"));
00532 #endif
00533 return false;
00534 }
00535 }
00536 else
00537 {
00538 m_str = 0L;
00539 database->abort();
00540 if (bMenuTest)
00541 return true;
00542 kdDebug(7021) << "Database is up to date" << endl;
00543 }
00544
00545 if (!bGlobalDatabase)
00546 {
00547
00548 QString stamppath = path + "stamp";
00549 QFile ksycocastamp(stamppath);
00550 ksycocastamp.open( IO_WriteOnly );
00551 QDataStream str( &ksycocastamp );
00552 str << newTimestamp;
00553 str << existingResourceDirs();
00554 if (g_vfolder)
00555 str << g_vfolder->allDirectories();
00556 }
00557 return true;
00558 }
00559
00560 void KBuildSycoca::save()
00561 {
00562
00563 m_str->device()->at(0);
00564
00565 (*m_str) << (Q_INT32) KSycoca::version();
00566 KSycocaFactory * servicetypeFactory = 0L;
00567 KSycocaFactory * serviceFactory = 0L;
00568 for(KSycocaFactory *factory = m_lstFactories->first();
00569 factory;
00570 factory = m_lstFactories->next())
00571 {
00572 Q_INT32 aId;
00573 Q_INT32 aOffset;
00574 aId = factory->factoryId();
00575 if ( aId == KST_KServiceTypeFactory )
00576 servicetypeFactory = factory;
00577 else if ( aId == KST_KServiceFactory )
00578 serviceFactory = factory;
00579 aOffset = factory->offset();
00580 (*m_str) << aId;
00581 (*m_str) << aOffset;
00582 }
00583 (*m_str) << (Q_INT32) 0;
00584
00585 (*m_str) << KGlobal::dirs()->kfsstnd_prefixes();
00586 (*m_str) << newTimestamp;
00587 (*m_str) << KGlobal::locale()->language();
00588 (*m_str) << KGlobal::dirs()->calcResourceHash("services", "update_ksycoca", true);
00589 (*m_str) << (*g_allResourceDirs);
00590
00591
00592 for(KSycocaFactory *factory = m_lstFactories->first();
00593 factory;
00594 factory = m_lstFactories->next())
00595 {
00596 factory->save(*m_str);
00597 if (m_str->device()->status())
00598 return;
00599 }
00600
00601 int endOfData = m_str->device()->at();
00602
00603
00604 m_str->device()->at(0);
00605
00606 (*m_str) << (Q_INT32) KSycoca::version();
00607 for(KSycocaFactory *factory = m_lstFactories->first();
00608 factory;
00609 factory = m_lstFactories->next())
00610 {
00611 Q_INT32 aId;
00612 Q_INT32 aOffset;
00613 aId = factory->factoryId();
00614 aOffset = factory->offset();
00615 (*m_str) << aId;
00616 (*m_str) << aOffset;
00617 }
00618 (*m_str) << (Q_INT32) 0;
00619
00620
00621 m_str->device()->at(endOfData);
00622 }
00623
00624 bool KBuildSycoca::checkDirTimestamps( const QString& dirname, const QDateTime& stamp, bool top )
00625 {
00626 if( top )
00627 {
00628 QFileInfo inf( dirname );
00629 if( inf.lastModified() > stamp )
00630 {
00631 kdDebug( 7021 ) << "timestamp changed:" << dirname << endl;
00632 return false;
00633 }
00634 }
00635 QDir dir( dirname );
00636 const QFileInfoList *list = dir.entryInfoList( QDir::DefaultFilter, QDir::Unsorted );
00637 if (!list)
00638 return true;
00639
00640 for( QFileInfoListIterator it( *list );
00641 it.current() != NULL;
00642 ++it )
00643 {
00644 QFileInfo* fi = it.current();
00645 if( fi->fileName() == "." || fi->fileName() == ".." )
00646 continue;
00647 if( fi->lastModified() > stamp )
00648 {
00649 kdDebug( 7201 ) << "timestamp changed:" << fi->filePath() << endl;
00650 return false;
00651 }
00652 if( fi->isDir() && !checkDirTimestamps( fi->filePath(), stamp, false ))
00653 return false;
00654 }
00655 return true;
00656 }
00657
00658
00659
00660
00661
00662 bool KBuildSycoca::checkTimestamps( Q_UINT32 timestamp, const QStringList &dirs )
00663 {
00664 kdDebug( 7021 ) << "checking file timestamps" << endl;
00665 QDateTime stamp;
00666 stamp.setTime_t( timestamp );
00667 for( QStringList::ConstIterator it = dirs.begin();
00668 it != dirs.end();
00669 ++it )
00670 {
00671 if( !checkDirTimestamps( *it, stamp, true ))
00672 return false;
00673 }
00674 kdDebug( 7021 ) << "timestamps check ok" << endl;
00675 return true;
00676 }
00677
00678 QStringList KBuildSycoca::existingResourceDirs()
00679 {
00680 static QStringList* dirs = NULL;
00681 if( dirs != NULL )
00682 return *dirs;
00683 dirs = new QStringList;
00684 g_allResourceDirs = new QStringList;
00685
00686 QStringList resources;
00687 resources += KBuildServiceTypeFactory::resourceTypes();
00688 resources += KBuildServiceGroupFactory::resourceTypes();
00689 resources += KBuildServiceFactory::resourceTypes();
00690 resources += KBuildImageIOFactory::resourceTypes();
00691 resources += KBuildProtocolInfoFactory::resourceTypes();
00692 while( !resources.empty())
00693 {
00694 QString res = resources.front();
00695 *dirs += KGlobal::dirs()->resourceDirs( res.latin1());
00696 resources.remove( res );
00697 }
00698
00699 *g_allResourceDirs = *dirs;
00700
00701 for( QStringList::Iterator it = dirs->begin();
00702 it != dirs->end(); )
00703 {
00704 QFileInfo inf( *it );
00705 if( !inf.exists() || !inf.isReadable() )
00706 it = dirs->remove( it );
00707 else
00708 ++it;
00709 }
00710 return *dirs;
00711 }
00712
00713 static KCmdLineOptions options[] = {
00714 { "nosignal", I18N_NOOP("Do not signal applications to update"), 0 },
00715 { "noincremental", I18N_NOOP("Disable incremental update, re-read everything"), 0 },
00716 { "checkstamps", I18N_NOOP("Check file timestamps"), 0 },
00717 { "nocheckfiles", I18N_NOOP("Disable checking files (dangerous)"), 0 },
00718 { "global", I18N_NOOP("Create global database"), 0 },
00719 { "menutest", I18N_NOOP("Perform menu generation test run only"), 0 },
00720 { "track <menu-id>", I18N_NOOP("Track menu id for debug purposes"), 0 },
00721 #ifdef KBUILDSYCOCA_GUI
00722 { "silent", I18N_NOOP("Silent - work without windows and stderr"), 0 },
00723 { "showprogress", I18N_NOOP("Show progress information (even if 'silent' mode is on)"), 0 },
00724 #endif
00725 KCmdLineLastOption
00726 };
00727
00728 static const char appName[] = "kbuildsycoca";
00729 static const char appVersion[] = "1.1";
00730
00731 class WaitForSignal : public QObject
00732 {
00733 public:
00734 ~WaitForSignal() { kapp->eventLoop()->exitLoop(); }
00735 };
00736
00737 extern "C" KDE_EXPORT int kdemain(int argc, char **argv)
00738 {
00739 KLocale::setMainCatalogue("kdelibs");
00740 KAboutData d(appName, I18N_NOOP("KBuildSycoca"), appVersion,
00741 I18N_NOOP("Rebuilds the system configuration cache."),
00742 KAboutData::License_GPL, "(c) 1999-2002 KDE Developers");
00743 d.addAuthor("David Faure", I18N_NOOP("Author"), "faure@kde.org");
00744 d.addAuthor("Waldo Bastian", I18N_NOOP("Author"), "bastian@kde.org");
00745
00746 KCmdLineArgs::init(argc, argv, &d);
00747 KCmdLineArgs::addCmdLineOptions(options);
00748 KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
00749 bGlobalDatabase = args->isSet("global");
00750 bMenuTest = args->isSet("menutest");
00751
00752 if (bGlobalDatabase)
00753 {
00754 setenv("KDEHOME", "-", 1);
00755 setenv("KDEROOTHOME", "-", 1);
00756 }
00757
00758 KApplication::disableAutoDcopRegistration();
00759 #ifdef KBUILDSYCOCA_GUI
00760 KApplication k;
00761 #else
00762 KApplication k(false, false);
00763 #endif
00764 k.disableSessionManagement();
00765
00766 #ifdef KBUILDSYCOCA_GUI
00767 silent = args->isSet("silent");
00768 showprogress = args->isSet("showprogress");
00769 QLabel progress( QString("<p><br><nobr> %1 </nobr><br>").arg( i18n("Reloading KDE configuration, please wait...") ), 0, "", Qt::WType_Dialog | Qt::WStyle_DialogBorder | Qt::WStyle_Customize| Qt::WStyle_Title );
00770 QString capt = i18n("KDE Configuration Manager");
00771 if (!silent) {
00772 if (KMessageBox::No == KMessageBox::questionYesNo(0, i18n("Do you want to reload KDE configuration?"), capt, i18n("Reload"), i18n("Do Not Reload")))
00773 return 0;
00774 }
00775 if (!silent || showprogress) {
00776 progress.setCaption( capt );
00777 progress.show();
00778 }
00779 #endif
00780
00781 KCrash::setCrashHandler(KCrash::defaultCrashHandler);
00782 KCrash::setEmergencySaveFunction(crashHandler);
00783 KCrash::setApplicationName(QString(appName));
00784
00785
00786 KLocale::setMainCatalogue("kdelibs");
00787
00788
00789 KGlobal::locale();
00790 KGlobal::dirs()->addResourceType("app-reg", "share/application-registry" );
00791
00792 DCOPClient *dcopClient = new DCOPClient();
00793
00794 while(true)
00795 {
00796 QCString registeredName = dcopClient->registerAs(appName, false);
00797 if (registeredName.isEmpty())
00798 {
00799 fprintf(stderr, "Warning: %s is unable to register with DCOP.\n", appName);
00800 break;
00801 }
00802 else if (registeredName == appName)
00803 {
00804 break;
00805 }
00806 fprintf(stderr, "Waiting for already running %s to finish.\n", appName);
00807
00808 dcopClient->setNotifications( true );
00809 while (dcopClient->isApplicationRegistered(appName))
00810 {
00811 WaitForSignal *obj = new WaitForSignal;
00812 obj->connect(dcopClient, SIGNAL(applicationRemoved(const QCString &)),
00813 SLOT(deleteLater()));
00814 kapp->eventLoop()->enterLoop();
00815 }
00816 dcopClient->setNotifications( false );
00817 }
00818 fprintf(stderr, "%s running...\n", appName);
00819
00820 bool checkfiles = bGlobalDatabase || args->isSet("checkfiles");
00821
00822 bool incremental = !bGlobalDatabase && args->isSet("incremental") && checkfiles;
00823 if (incremental || !checkfiles)
00824 {
00825 KSycoca::self()->disableAutoRebuild();
00826 QString current_language = KGlobal::locale()->language();
00827 QString ksycoca_language = KSycoca::self()->language();
00828 Q_UINT32 current_update_sig = KGlobal::dirs()->calcResourceHash("services", "update_ksycoca", true);
00829 Q_UINT32 ksycoca_update_sig = KSycoca::self()->updateSignature();
00830
00831 if ((current_update_sig != ksycoca_update_sig) ||
00832 (current_language != ksycoca_language) ||
00833 (KSycoca::self()->timeStamp() == 0))
00834 {
00835 incremental = false;
00836 checkfiles = true;
00837 delete KSycoca::self();
00838 }
00839 }
00840
00841 g_changeList = new QStringList;
00842
00843 bool checkstamps = incremental && args->isSet("checkstamps") && checkfiles;
00844 Q_UINT32 filestamp = 0;
00845 QStringList oldresourcedirs;
00846 if( checkstamps && incremental )
00847 {
00848 QString path = sycocaPath()+"stamp";
00849 QCString qPath = QFile::encodeName(path);
00850 cSycocaPath = qPath.data();
00851 QFile ksycocastamp(path);
00852 if( ksycocastamp.open( IO_ReadOnly ))
00853 {
00854 QDataStream str( &ksycocastamp );
00855 if (!str.atEnd())
00856 str >> filestamp;
00857 if (!str.atEnd())
00858 {
00859 str >> oldresourcedirs;
00860 if( oldresourcedirs != KBuildSycoca::existingResourceDirs())
00861 checkstamps = false;
00862 }
00863 else
00864 {
00865 checkstamps = false;
00866 }
00867 if (!str.atEnd())
00868 {
00869 QStringList extraResourceDirs;
00870 str >> extraResourceDirs;
00871 oldresourcedirs += extraResourceDirs;
00872 }
00873 }
00874 else
00875 {
00876 checkstamps = false;
00877 }
00878 cSycocaPath = 0;
00879 }
00880
00881 newTimestamp = (Q_UINT32) time(0);
00882
00883 if( checkfiles && ( !checkstamps || !KBuildSycoca::checkTimestamps( filestamp, oldresourcedirs )))
00884 {
00885 QCString qSycocaPath = QFile::encodeName(sycocaPath());
00886 cSycocaPath = qSycocaPath.data();
00887
00888 g_allEntries = 0;
00889 g_ctimeDict = 0;
00890 if (incremental)
00891 {
00892 qWarning("Reusing existing ksycoca");
00893 KSycoca *oldSycoca = KSycoca::self();
00894 KSycocaFactoryList *factories = new KSycocaFactoryList;
00895 g_allEntries = new KSycocaEntryListList;
00896 g_ctimeDict = new QDict<Q_UINT32>(523);
00897
00898
00899 factories->append( new KServiceTypeFactory );
00900 factories->append( new KServiceGroupFactory );
00901 factories->append( new KServiceFactory );
00902 factories->append( new KImageIOFactory );
00903 factories->append( new KProtocolInfoFactory );
00904
00905
00906 for (KSycocaFactory *factory = factories->first();
00907 factory;
00908 factory = factories->next() )
00909 {
00910 KSycocaEntry::List list;
00911 list = factory->allEntries();
00912 g_allEntries->append( list );
00913 }
00914 delete factories; factories = 0;
00915 KCTimeInfo *ctimeInfo = new KCTimeInfo;
00916 ctimeInfo->fillCTimeDict(*g_ctimeDict);
00917 delete oldSycoca;
00918 }
00919 cSycocaPath = 0;
00920
00921 KBuildSycoca *sycoca= new KBuildSycoca;
00922 if (args->isSet("track"))
00923 sycoca->setTrackId(QString::fromLocal8Bit(args->getOption("track")));
00924 if (!sycoca->recreate()) {
00925 #ifdef KBUILDSYCOCA_GUI
00926 if (!silent || showprogress)
00927 progress.close();
00928 #endif
00929 return -1;
00930 }
00931
00932 if (bGlobalDatabase)
00933 {
00934
00935
00936 QString applnkDir = KGlobal::dirs()->saveLocation("apps", QString::null, false);
00937 ::rmdir(QFile::encodeName(applnkDir));
00938 QString servicetypesDir = KGlobal::dirs()->saveLocation("servicetypes", QString::null, false);
00939 ::rmdir(QFile::encodeName(servicetypesDir));
00940 }
00941 }
00942
00943 if (!bGlobalDatabase)
00944 {
00945
00946 QString oldPath = oldSycocaPath();
00947 if (!oldPath.isEmpty())
00948 {
00949 KTempFile tmp;
00950 if (tmp.status() == 0)
00951 {
00952 QString tmpFile = tmp.name();
00953 tmp.unlink();
00954 symlink(QFile::encodeName(sycocaPath()), QFile::encodeName(tmpFile));
00955 rename(QFile::encodeName(tmpFile), QFile::encodeName(oldPath));
00956 }
00957 }
00958 }
00959
00960 if (args->isSet("signal"))
00961 {
00962
00963 QByteArray data;
00964 QDataStream stream(data, IO_WriteOnly);
00965 stream << *g_changeList;
00966 dcopClient->send( "*", "ksycoca", "notifyDatabaseChanged(QStringList)", data );
00967 }
00968
00969 #ifdef KBUILDSYCOCA_GUI
00970 if (!silent) {
00971 progress.close();
00972 KMessageBox::information(0, i18n("Configuration information reloaded successfully."), capt);
00973 }
00974 #endif
00975 return 0;
00976 }
00977
00978 #include "kbuildsycoca.moc"