• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

KDED

kbuildsycoca.cpp

Go to the documentation of this file.
00001 /*  This file is part of the KDE libraries
00002  *  Copyright (C) 1999 David Faure <faure@kde.org>
00003  *  Copyright (C) 2002-2003 Waldo Bastian <bastian@kde.org>
00004  *
00005  *  This library is free software; you can redistribute it and/or
00006  *  modify it under the terms of the GNU Library General Public
00007  *  License version 2 as published by the Free Software Foundation;
00008  *
00009  *  This library is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  *  Library General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU Library General Public License
00015  *  along with this library; see the file COPYING.LIB.  If not, write to
00016  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  *  Boston, MA 02110-1301, USA.
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                         // GUI version of kbuildsycoca, so-called "kbuildsycocaw".
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> // auto_ptr
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    // If we crash while reading sycoca, we delete the database
00096    // in an attempt to recover.
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 //      kdDebug(7021) << "gnome-vfs.applications not found." << endl;
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 //             kdDebug(7021) << "Adding gnome mimetypes for '" << app << "'.\n";
00180 //             kdDebug(7021) << "ServiceTypes=" << s->serviceTypes().join(":") << endl;
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          // Re-use old entry
00204          if (g_factory == g_bsgf) // Strip .directory from service-group entries
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          // remove from g_ctimeDict; if g_ctimeDict is not empty
00217          // after all files have been processed, it means
00218          // some files were removed since last time
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       // Create a new entry
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 // returns false if the database is up to date
00256 bool KBuildSycoca::build()
00257 {
00258   typedef QPtrList<KBSEntryDict> KBSEntryDictList;
00259   KBSEntryDictList *entryDictList = 0;
00260   KBSEntryDict *serviceEntryDict = 0;
00261 
00262   entryDictList = new KBSEntryDictList();
00263   // Convert for each factory the entryList to a Dict.
00264   int i = 0;
00265   // For each factory
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   // For each factory
00290   for (KSycocaFactory *factory = m_lstFactories->first();
00291        factory;
00292        factory = m_lstFactories->next() )
00293   {
00294     // For each resource the factory deals with
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(); // This is a build factory too, don't delete!!
00309   bool uptodate = true;
00310   // For all resources
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, // Recursive!
00323                                                true, // uniq
00324                                                relFiles);
00325 
00326 
00327      // Now find all factories that use this resource....
00328      // For each factory
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         // For each resource the factory deals with
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            // For each file in the resource
00347            for( QStringList::ConstIterator it3 = relFiles.begin();
00348                 it3 != relFiles.end();
00349                 ++it3 )
00350            {
00351                // Check if file matches filter
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 = g_vfolder->parseMenu("applications.menu", true);
00383 
00384      KServiceGroup *entry = g_bsgf->addNew("/", kdeMenu->directoryFile, 0, false);
00385      entry->setLayoutInfo(kdeMenu->layoutList);
00386      createMenu(QString::null, QString::null, kdeMenu);
00387 
00388      KServiceGroup::Ptr g(entry);
00389 
00390      (void) existingResourceDirs();
00391      *g_allResourceDirs += g_vfolder->allDirectories();
00392 
00393      disconnect(g_vfolder, SIGNAL(newService(const QString &, KService **)),
00394              this, SLOT(slotCreateEntry(const QString &, KService **)));
00395 
00396      if (g_changed || !g_allEntries)
00397      {
00398         uptodate = false;
00399         g_changeList->append(g_resource);
00400      }
00401      if (bMenuTest)
00402         return false;
00403   }
00404 
00405   return result;
00406 }
00407 
00408 void KBuildSycoca::createMenu(QString caption, QString name, VFolderMenu::SubMenu *menu)
00409 {
00410   for(VFolderMenu::SubMenu *subMenu = menu->subMenus.first(); subMenu; subMenu = menu->subMenus.next())
00411   {
00412      QString subName = name+subMenu->name+"/";
00413 
00414      QString directoryFile = subMenu->directoryFile;
00415      if (directoryFile.isEmpty())
00416         directoryFile = subName+".directory";
00417      Q_UINT32 timeStamp = g_ctimeInfo->ctime(directoryFile);
00418      if (!timeStamp)
00419      {
00420         timeStamp = KGlobal::dirs()->calcResourceHash( g_resource, directoryFile, true);
00421      }
00422 
00423      KServiceGroup* entry = 0;
00424      if (g_allEntries)
00425      {
00426         Q_UINT32 *timeP = (*g_ctimeDict)[directoryFile];
00427         Q_UINT32 oldTimestamp = timeP ? *timeP : 0;
00428 
00429         if (timeStamp && (timeStamp == oldTimestamp))
00430         {
00431             entry = dynamic_cast<KServiceGroup *> (g_serviceGroupEntryDict->find(subName));
00432             if (entry && (entry->directoryEntryPath() != directoryFile))
00433                 entry = 0; // Can't reuse this one!
00434         }
00435      }
00436      g_ctimeInfo->addCTime(directoryFile, timeStamp);
00437 
00438      entry = g_bsgf->addNew(subName, subMenu->directoryFile, entry, subMenu->isDeleted);
00439      entry->setLayoutInfo(subMenu->layoutList);
00440      if (! (bMenuTest && entry->noDisplay()) )
00441         createMenu(caption + entry->caption() + "/", subName, subMenu);
00442   }
00443   if (caption.isEmpty())
00444      caption += "/";
00445   if (name.isEmpty())
00446      name += "/";
00447   for(QDictIterator<KService> it(menu->items); it.current(); ++it)
00448   {
00449      if (bMenuTest)
00450      {
00451         if (!menu->isDeleted && !it.current()->noDisplay())
00452           printf("%s\t%s\t%s\n", caption.local8Bit().data(), it.current()->menuId().local8Bit().data(), locate("apps", it.current()->desktopEntryPath()).local8Bit().data());
00453      }
00454      else
00455      {
00456         g_bsf->addEntry( it.current(), g_resource );
00457         g_bsgf->addNewEntryTo(name, it.current());
00458      }
00459   }
00460 }
00461 
00462 bool KBuildSycoca::recreate()
00463 {
00464   QString path(sycocaPath());
00465 #ifdef Q_WS_WIN
00466   printf("kbuildsycoca: path='%s'\n", (const char*)path);
00467 #endif
00468 
00469   // KSaveFile first writes to a temp file.
00470   // Upon close() it moves the stuff to the right place.
00471   std::auto_ptr<KSaveFile> database( new KSaveFile(path) );
00472   if (database->status() == EACCES && QFile::exists(path))
00473   {
00474     QFile::remove( path );
00475     database.reset( new KSaveFile(path) ); // try again
00476   }
00477   if (database->status() != 0)
00478   {
00479     fprintf(stderr, "kbuildsycoca: ERROR creating database '%s'! %s\n", path.local8Bit().data(),strerror(database->status()));
00480 #ifdef KBUILDSYCOCA_GUI // KBUILDSYCOCA_GUI is used on win32 to build 
00481                         // GUI version of kbuildsycoca, so-called "kbuildsycocaw".
00482     if (!silent)
00483       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"));
00484 #endif
00485     return false;
00486   }
00487 
00488   m_str = database->dataStream();
00489 
00490   kdDebug(7021) << "Recreating ksycoca file (" << path << ", version " << KSycoca::version() << ")" << endl;
00491 
00492   // It is very important to build the servicetype one first
00493   // Both are registered in KSycoca, no need to keep the pointers
00494   KSycocaFactory *stf = new KBuildServiceTypeFactory;
00495   g_bsgf = new KBuildServiceGroupFactory();
00496   g_bsf = new KBuildServiceFactory(stf, g_bsgf);
00497   (void) new KBuildImageIOFactory();
00498   (void) new KBuildProtocolInfoFactory();
00499 
00500   if( build()) // Parse dirs
00501   {
00502     save(); // Save database
00503     if (m_str->device()->status())
00504       database->abort(); // Error
00505     m_str = 0L;
00506     if (!database->close())
00507     {
00508       fprintf(stderr, "kbuildsycoca: ERROR writing database '%s'!\n", database->name().local8Bit().data());
00509       fprintf(stderr, "kbuildsycoca: Disk full?\n");
00510 #ifdef KBUILDSYCOCA_GUI
00511       if (!silent)
00512         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"));
00513 #endif
00514       return false;
00515     }
00516   }
00517   else
00518   {
00519     m_str = 0L;
00520     database->abort();
00521     if (bMenuTest)
00522        return true;
00523     kdDebug(7021) << "Database is up to date" << endl;
00524   }
00525 
00526   if (!bGlobalDatabase)
00527   {
00528     // update the timestamp file
00529     QString stamppath = path + "stamp";
00530     QFile ksycocastamp(stamppath);
00531     ksycocastamp.open( IO_WriteOnly );
00532     QDataStream str( &ksycocastamp );
00533     str << newTimestamp;
00534     str << existingResourceDirs();
00535     if (g_vfolder)
00536         str << g_vfolder->allDirectories(); // Extra resource dirs
00537   }
00538   return true;
00539 }
00540 
00541 void KBuildSycoca::save()
00542 {
00543    // Write header (#pass 1)
00544    m_str->device()->at(0);
00545 
00546    (*m_str) << (Q_INT32) KSycoca::version();
00547    KSycocaFactory * servicetypeFactory = 0L;
00548    KSycocaFactory * serviceFactory = 0L;
00549    for(KSycocaFactory *factory = m_lstFactories->first();
00550        factory;
00551        factory = m_lstFactories->next())
00552    {
00553       Q_INT32 aId;
00554       Q_INT32 aOffset;
00555       aId = factory->factoryId();
00556       if ( aId == KST_KServiceTypeFactory )
00557          servicetypeFactory = factory;
00558       else if ( aId == KST_KServiceFactory )
00559          serviceFactory = factory;
00560       aOffset = factory->offset();
00561       (*m_str) << aId;
00562       (*m_str) << aOffset;
00563    }
00564    (*m_str) << (Q_INT32) 0; // No more factories.
00565    // Write KDEDIRS
00566    (*m_str) << KGlobal::dirs()->kfsstnd_prefixes();
00567    (*m_str) << newTimestamp;
00568    (*m_str) << KGlobal::locale()->language();
00569    (*m_str) << KGlobal::dirs()->calcResourceHash("services", "update_ksycoca", true);
00570    (*m_str) << (*g_allResourceDirs);
00571 
00572    // Write factory data....
00573    for(KSycocaFactory *factory = m_lstFactories->first();
00574        factory;
00575        factory = m_lstFactories->next())
00576    {
00577       factory->save(*m_str);
00578       if (m_str->device()->status())
00579          return; // error
00580    }
00581 
00582    int endOfData = m_str->device()->at();
00583 
00584    // Write header (#pass 2)
00585    m_str->device()->at(0);
00586 
00587    (*m_str) << (Q_INT32) KSycoca::version();
00588    for(KSycocaFactory *factory = m_lstFactories->first();
00589        factory;
00590        factory = m_lstFactories->next())
00591    {
00592       Q_INT32 aId;
00593       Q_INT32 aOffset;
00594       aId = factory->factoryId();
00595       aOffset = factory->offset();
00596       (*m_str) << aId;
00597       (*m_str) << aOffset;
00598    }
00599    (*m_str) << (Q_INT32) 0; // No more factories.
00600 
00601    // Jump to end of database
00602    m_str->device()->at(endOfData);
00603 }
00604 
00605 bool KBuildSycoca::checkDirTimestamps( const QString& dirname, const QDateTime& stamp, bool top )
00606 {
00607    if( top )
00608    {
00609       QFileInfo inf( dirname );
00610       if( inf.lastModified() > stamp )
00611          {
00612          kdDebug( 7021 ) << "timestamp changed:" << dirname << endl;
00613          return false;
00614          }
00615    }
00616    QDir dir( dirname );
00617    const QFileInfoList *list = dir.entryInfoList( QDir::DefaultFilter, QDir::Unsorted );
00618    if (!list)
00619       return true;
00620 
00621    for( QFileInfoListIterator it( *list );
00622         it.current() != NULL;
00623         ++it )
00624    {
00625       QFileInfo* fi = it.current();
00626       if( fi->fileName() == "." || fi->fileName() == ".." )
00627          continue;
00628       if( fi->lastModified() > stamp )
00629       {
00630          kdDebug( 7201 ) << "timestamp changed:" << fi->filePath() << endl;
00631          return false;
00632       }
00633       if( fi->isDir() && !checkDirTimestamps( fi->filePath(), stamp, false ))
00634             return false;
00635    }
00636    return true;
00637 }
00638 
00639 // check times of last modification of all files on which ksycoca depens,
00640 // and also their directories
00641 // if all of them all older than the timestamp in file ksycocastamp, this
00642 // means that there's no need to rebuild ksycoca
00643 bool KBuildSycoca::checkTimestamps( Q_UINT32 timestamp, const QStringList &dirs )
00644 {
00645    kdDebug( 7021 ) << "checking file timestamps" << endl;
00646    QDateTime stamp;
00647    stamp.setTime_t( timestamp );
00648    for( QStringList::ConstIterator it = dirs.begin();
00649         it != dirs.end();
00650         ++it )
00651    {
00652       if( !checkDirTimestamps( *it, stamp, true ))
00653             return false;
00654    }
00655    kdDebug( 7021 ) << "timestamps check ok" << endl;
00656    return true;
00657 }
00658 
00659 QStringList KBuildSycoca::existingResourceDirs()
00660 {
00661    static QStringList* dirs = NULL;
00662    if( dirs != NULL )
00663        return *dirs;
00664    dirs = new QStringList;
00665    g_allResourceDirs = new QStringList;
00666    // these are all resources cached by ksycoca
00667    QStringList resources;
00668    resources += KBuildServiceTypeFactory::resourceTypes();
00669    resources += KBuildServiceGroupFactory::resourceTypes();
00670    resources += KBuildServiceFactory::resourceTypes();
00671    resources += KBuildImageIOFactory::resourceTypes();
00672    resources += KBuildProtocolInfoFactory::resourceTypes();
00673    while( !resources.empty())
00674    {
00675       QString res = resources.front();
00676       *dirs += KGlobal::dirs()->resourceDirs( res.latin1());
00677       resources.remove( res ); // remove this 'res' and all its duplicates
00678    }
00679 
00680    *g_allResourceDirs = *dirs;
00681 
00682    for( QStringList::Iterator it = dirs->begin();
00683         it != dirs->end(); )
00684    {
00685       QFileInfo inf( *it );
00686       if( !inf.exists() || !inf.isReadable() )
00687          it = dirs->remove( it );
00688       else
00689          ++it;
00690    }
00691    return *dirs;
00692 }
00693 
00694 static KCmdLineOptions options[] = {
00695    { "nosignal", I18N_NOOP("Do not signal applications to update"), 0 },
00696    { "noincremental", I18N_NOOP("Disable incremental update, re-read everything"), 0 },
00697    { "checkstamps", I18N_NOOP("Check file timestamps"), 0 },
00698    { "nocheckfiles", I18N_NOOP("Disable checking files (dangerous)"), 0 },
00699    { "global", I18N_NOOP("Create global database"), 0 },
00700    { "menutest", I18N_NOOP("Perform menu generation test run only"), 0 },
00701    { "track <menu-id>", I18N_NOOP("Track menu id for debug purposes"), 0 },
00702 #ifdef KBUILDSYCOCA_GUI
00703    { "silent", I18N_NOOP("Silent - work without windows and stderr"), 0 },
00704    { "showprogress", I18N_NOOP("Show progress information (even if 'silent' mode is on)"), 0 },
00705 #endif
00706    KCmdLineLastOption
00707 };
00708 
00709 static const char appName[] = "kbuildsycoca";
00710 static const char appVersion[] = "1.1";
00711 
00712 class WaitForSignal : public QObject
00713 {
00714 public:
00715    ~WaitForSignal() { kapp->eventLoop()->exitLoop(); }
00716 };
00717 
00718 extern "C" KDE_EXPORT int kdemain(int argc, char **argv)
00719 {
00720    KLocale::setMainCatalogue("kdelibs");
00721    KAboutData d(appName, I18N_NOOP("KBuildSycoca"), appVersion,
00722                 I18N_NOOP("Rebuilds the system configuration cache."),
00723                 KAboutData::License_GPL, "(c) 1999-2002 KDE Developers");
00724    d.addAuthor("David Faure", I18N_NOOP("Author"), "faure@kde.org");
00725    d.addAuthor("Waldo Bastian", I18N_NOOP("Author"), "bastian@kde.org");
00726 
00727    KCmdLineArgs::init(argc, argv, &d);
00728    KCmdLineArgs::addCmdLineOptions(options);
00729    KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
00730    bGlobalDatabase = args->isSet("global");
00731    bMenuTest = args->isSet("menutest");
00732 
00733    if (bGlobalDatabase)
00734    {
00735      setenv("KDEHOME", "-", 1);
00736      setenv("KDEROOTHOME", "-", 1);
00737    }
00738 
00739    KApplication::disableAutoDcopRegistration();
00740 #ifdef KBUILDSYCOCA_GUI
00741    KApplication k;
00742 #else
00743    KApplication k(false, false);
00744 #endif
00745    k.disableSessionManagement();
00746 
00747 #ifdef KBUILDSYCOCA_GUI
00748    silent = args->isSet("silent");
00749    showprogress = args->isSet("showprogress");
00750    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 );
00751    QString capt = i18n("KDE Configuration Manager");
00752    if (!silent) {
00753      if (KMessageBox::No == KMessageBox::questionYesNo(0, i18n("Do you want to reload KDE configuration?"), capt, i18n("Reload"), i18n("Do Not Reload")))
00754        return 0;
00755    }
00756    if (!silent || showprogress) {
00757      progress.setCaption( capt );
00758      progress.show();
00759    }
00760 #endif
00761 
00762    KCrash::setCrashHandler(KCrash::defaultCrashHandler);
00763    KCrash::setEmergencySaveFunction(crashHandler);
00764    KCrash::setApplicationName(QString(appName));
00765 
00766    // this program is in kdelibs so it uses kdelibs as catalog
00767    KLocale::setMainCatalogue("kdelibs");
00768    // force generating of KLocale object. if not, the database will get
00769    // be translated
00770    KGlobal::locale();
00771    KGlobal::dirs()->addResourceType("app-reg", "share/application-registry" );
00772 
00773    DCOPClient *dcopClient = new DCOPClient();
00774 
00775    while(true)
00776    {
00777      QCString registeredName = dcopClient->registerAs(appName, false);
00778      if (registeredName.isEmpty())
00779      {
00780        fprintf(stderr, "Warning: %s is unable to register with DCOP.\n", appName);
00781        break;
00782      }
00783      else if (registeredName == appName)
00784      {
00785        break; // Go
00786      }
00787      fprintf(stderr, "Waiting for already running %s to finish.\n", appName);
00788 
00789      dcopClient->setNotifications( true );
00790      while (dcopClient->isApplicationRegistered(appName))
00791      {
00792        WaitForSignal *obj = new WaitForSignal;
00793        obj->connect(dcopClient, SIGNAL(applicationRemoved(const QCString &)),
00794                SLOT(deleteLater()));
00795        kapp->eventLoop()->enterLoop();
00796      }
00797      dcopClient->setNotifications( false );
00798    }
00799    fprintf(stderr, "%s running...\n", appName);
00800 
00801    bool checkfiles = bGlobalDatabase || args->isSet("checkfiles");
00802 
00803    bool incremental = !bGlobalDatabase && args->isSet("incremental") && checkfiles;
00804    if (incremental || !checkfiles)
00805    {
00806      KSycoca::self()->disableAutoRebuild(); // Prevent deadlock
00807      QString current_language = KGlobal::locale()->language();
00808      QString ksycoca_language = KSycoca::self()->language();
00809      Q_UINT32 current_update_sig = KGlobal::dirs()->calcResourceHash("services", "update_ksycoca", true);
00810      Q_UINT32 ksycoca_update_sig = KSycoca::self()->updateSignature();
00811 
00812      if ((current_update_sig != ksycoca_update_sig) ||
00813          (current_language != ksycoca_language) ||
00814          (KSycoca::self()->timeStamp() == 0))
00815      {
00816         incremental = false;
00817         checkfiles = true;
00818         delete KSycoca::self();
00819      }
00820    }
00821 
00822    g_changeList = new QStringList;
00823 
00824    bool checkstamps = incremental && args->isSet("checkstamps") && checkfiles;
00825    Q_UINT32 filestamp = 0;
00826    QStringList oldresourcedirs;
00827    if( checkstamps && incremental )
00828    {
00829        QString path = sycocaPath()+"stamp";
00830        QCString qPath = QFile::encodeName(path);
00831        cSycocaPath = qPath.data(); // Delete timestamps on crash
00832        QFile ksycocastamp(path);
00833        if( ksycocastamp.open( IO_ReadOnly ))
00834        {
00835            QDataStream str( &ksycocastamp );
00836            if (!str.atEnd())
00837                str >> filestamp;
00838            if (!str.atEnd())
00839            {
00840                str >> oldresourcedirs;
00841                if( oldresourcedirs != KBuildSycoca::existingResourceDirs())
00842                    checkstamps = false;
00843            }
00844            else
00845            {
00846                checkstamps = false;
00847            }
00848            if (!str.atEnd())
00849            {
00850                QStringList extraResourceDirs;
00851                str >> extraResourceDirs;
00852                oldresourcedirs += extraResourceDirs;
00853            }
00854        }
00855        else
00856        {
00857            checkstamps = false;
00858        }
00859        cSycocaPath = 0;
00860    }
00861 
00862    newTimestamp = (Q_UINT32) time(0);
00863 
00864    if( checkfiles && ( !checkstamps || !KBuildSycoca::checkTimestamps( filestamp, oldresourcedirs )))
00865    {
00866       QCString qSycocaPath = QFile::encodeName(sycocaPath());
00867       cSycocaPath = qSycocaPath.data();
00868 
00869       g_allEntries = 0;
00870       g_ctimeDict = 0;
00871       if (incremental)
00872       {
00873          qWarning("Reusing existing ksycoca");
00874          KSycoca *oldSycoca = KSycoca::self();
00875          KSycocaFactoryList *factories = new KSycocaFactoryList;
00876          g_allEntries = new KSycocaEntryListList;
00877          g_ctimeDict = new QDict<Q_UINT32>(523);
00878 
00879          // Must be in same order as in KBuildSycoca::recreate()!
00880          factories->append( new KServiceTypeFactory );
00881          factories->append( new KServiceGroupFactory );
00882          factories->append( new KServiceFactory );
00883          factories->append( new KImageIOFactory );
00884          factories->append( new KProtocolInfoFactory );
00885 
00886          // For each factory
00887          for (KSycocaFactory *factory = factories->first();
00888               factory;
00889               factory = factories->next() )
00890          {
00891              KSycocaEntry::List list;
00892              list = factory->allEntries();
00893              g_allEntries->append( list );
00894          }
00895          delete factories; factories = 0;
00896          KCTimeInfo *ctimeInfo = new KCTimeInfo;
00897          ctimeInfo->fillCTimeDict(*g_ctimeDict);
00898          delete oldSycoca;
00899       }
00900       cSycocaPath = 0;
00901 
00902       KBuildSycoca *sycoca= new KBuildSycoca; // Build data base
00903       if (args->isSet("track"))
00904          sycoca->setTrackId(QString::fromLocal8Bit(args->getOption("track")));
00905       if (!sycoca->recreate()) {
00906 #ifdef KBUILDSYCOCA_GUI
00907         if (!silent || showprogress)
00908           progress.close();
00909 #endif
00910         return -1;
00911       }
00912 
00913       if (bGlobalDatabase)
00914       {
00915         // These directories may have been created with 0700 permission
00916         // better delete them if they are empty
00917         QString applnkDir = KGlobal::dirs()->saveLocation("apps", QString::null, false);
00918         ::rmdir(QFile::encodeName(applnkDir));
00919         QString servicetypesDir = KGlobal::dirs()->saveLocation("servicetypes", QString::null, false);
00920         ::rmdir(QFile::encodeName(servicetypesDir));
00921       }
00922    }
00923 
00924    if (!bGlobalDatabase)
00925    {
00926      // Recreate compatibility symlink
00927      QString oldPath = oldSycocaPath();
00928      if (!oldPath.isEmpty())
00929      {
00930        KTempFile tmp;
00931        if (tmp.status() == 0)
00932        {
00933          QString tmpFile = tmp.name();
00934          tmp.unlink();
00935          symlink(QFile::encodeName(sycocaPath()), QFile::encodeName(tmpFile));
00936          rename(QFile::encodeName(tmpFile), QFile::encodeName(oldPath));
00937        }
00938      }
00939    }
00940 
00941    if (args->isSet("signal"))
00942    {
00943      // Notify ALL applications that have a ksycoca object, using a broadcast
00944      QByteArray data;
00945      QDataStream stream(data, IO_WriteOnly);
00946      stream << *g_changeList;
00947      dcopClient->send( "*", "ksycoca", "notifyDatabaseChanged(QStringList)", data );
00948    }
00949 
00950 #ifdef KBUILDSYCOCA_GUI
00951    if (!silent) {
00952      progress.close();
00953      KMessageBox::information(0, i18n("Configuration information reloaded successfully."), capt);
00954    }
00955 #endif
00956    return 0;
00957 }
00958 
00959 #include "kbuildsycoca.moc"

KDED

Skip menu "KDED"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal