Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

oipkg.cpp

Go to the documentation of this file.
00001 /*
00002                              This file is part of the Opie Project
00003 
00004                              Copyright (C)2004, 2005 Dan Williams <drw@handhelds.org>
00005               =.
00006             .=l.
00007            .>+-=
00008  _;:,     .>    :=|.         This program is free software; you can
00009 .> <`_,   >  .   <=          redistribute it and/or  modify it under
00010 :`=1 )Y*s>-.--   :           the terms of the GNU Library General Public
00011 .="- .-=="i,     .._         License as published by the Free Software
00012  - .   .-<_>     .<>         Foundation; either version 2 of the License,
00013      ._= =}       :          or (at your option) any later version.
00014     .%`+i>       _;_.
00015     .i_,=:_.      -<s.       This program is distributed in the hope that
00016      +  .  -:.       =       it will be useful,  but WITHOUT ANY WARRANTY;
00017     : ..    .:,     . . .    without even the implied warranty of
00018     =_        +     =;=|`    MERCHANTABILITY or FITNESS FOR A
00019   _.=:.       :    :=>`:     PARTICULAR PURPOSE. See the GNU
00020 ..}^=.=       =       ;      Library General Public License for more
00021 ++=   -.     .`     .:       details.
00022 :     =  ...= . :.=-
00023  -.   .:....=;==+<;          You should have received a copy of the GNU
00024   -_. . .   )=.  =           Library General Public License along with
00025     --        :-=`           this library; see the file COPYING.LIB.
00026                              If not, write to the Free Software Foundation,
00027                              Inc., 59 Temple Place - Suite 330,
00028                              Boston, MA 02111-1307, USA.
00029 */
00030 
00031 #include "oipkg.h"
00032 
00033 #include <qdir.h>
00034 #include <qfile.h>
00035 #include <qtextstream.h>
00036 
00037 #include <stdlib.h>
00038 #include <unistd.h>
00039 
00040 extern "C" {
00041 #include <libipkg.h>
00042 };
00043 args_t m_ipkgArgs; // libipkg configuration arguments
00044 
00045 const QString IPKG_CONF        = "/etc/ipkg.conf";      // Fully-qualified name of Ipkg primary configuration file
00046 const QString IPKG_CONF_DIR    = "/etc/ipkg";           // Directory of secondary Ipkg configuration files
00047 const QString IPKG_PKG_PATH    = "/usr/lib/ipkg/lists"; // Directory containing server package lists
00048 const QString IPKG_STATUS_PATH = "usr/lib/ipkg/status"; // Destination status file location
00049 const QString IPKG_INFO_PATH   = "usr/lib/ipkg/info";   // Package file lists location
00050 
00051 OIpkg *oipkg;
00052 
00053 // Ipkg callback functions
00054 
00055 int fsignalIpkgMessage( ipkg_conf_t *conf, message_level_t level, char *msg )
00056 {
00057     // Display message only if it is below the message level threshold
00058     if ( conf && ( conf->verbosity < level ) )
00059         return 0;
00060     else
00061         oipkg->ipkgMessage( msg );
00062 
00063     return 0;
00064 }
00065 
00066 char *fIpkgResponse( char */*question*/ )
00067 {
00068     return 0l;
00069 }
00070 
00071 int fIpkgStatus( char */*name*/, int /*status*/, char *desc, void */*userdata*/ )
00072 {
00073     oipkg->ipkgStatus( desc );
00074     return 0;
00075 }
00076 
00077 int fIpkgFiles( char */*name*/, char *desc, char */*version*/, pkg_state_status_t /*status*/,
00078                 void */*userdata*/ )
00079 {
00080     oipkg->ipkgList( desc );
00081     return 0;
00082 }
00083 
00084 OIpkg::OIpkg( Config *config, QObject *parent, const char *name )
00085     : QObject( parent, name )
00086     , m_config( config )
00087     , m_confInfo( NULL )
00088     , m_ipkgExecOptions( 0 )
00089     , m_ipkgExecVerbosity( 1 )
00090 {
00091     // Keep pointer to self for the Ipkg callback functions
00092     oipkg = this;
00093 
00094     // Initialize libipkg
00095     ipkg_init( &fsignalIpkgMessage, &fIpkgResponse, &m_ipkgArgs );
00096 
00097     // Default ipkg run-time arguments
00098     m_ipkgArgs.noaction = false;
00099     m_ipkgArgs.force_defaults = true;
00100 }
00101 
00102 OIpkg::~OIpkg()
00103 {
00104     // Upon destruction, ensure that items in config list are deleted with list
00105     if ( m_confInfo )
00106         m_confInfo->setAutoDelete( true );
00107 
00108     // Free up libipkg resources
00109     ipkg_deinit( &m_ipkgArgs );
00110 }
00111 
00112 OConfItemList *OIpkg::configItems()
00113 {
00114     // Retrieve all configuration items
00115     return filterConfItems();
00116 }
00117 
00118 OConfItemList *OIpkg::servers()
00119 {
00120     // Retrieve only servers
00121     return filterConfItems( OConfItem::Source );
00122 }
00123 
00124 OConfItemList *OIpkg::destinations()
00125 {
00126     // Retrieve only destinations
00127     return filterConfItems( OConfItem::Destination );
00128 }
00129 
00130 OConfItemList *OIpkg::options()
00131 {
00132     // Retrieve only destinations
00133     return filterConfItems( OConfItem::Option );
00134 }
00135 
00136 void OIpkg::setConfigItems( OConfItemList *configList )
00137 {
00138     if ( m_confInfo )
00139         delete m_confInfo;
00140 
00141     m_confInfo = configList;
00142 
00143     // Write out new /etc/ipkg.conf
00144     QFile confFile( IPKG_CONF );
00145     if ( confFile.open( IO_WriteOnly ) )
00146     {
00147         QTextStream confStream( &confFile );
00148         confStream << "# Generated by Opie Package Manager\n\n";
00149 
00150         OConfItemListIterator it( *m_confInfo );
00151         for ( ; it.current(); ++it )
00152         {
00153             OConfItem *item = it.current();
00154 
00155             // Only write out valid conf items
00156             if ( item->type() != OConfItem::NotDefined )
00157             {
00158                 QString confLine;
00159                 QString name = item->name();
00160                 if ( !item->active() )
00161                     confLine = "#";
00162 
00163                 switch ( item->type() )
00164                 {
00165                     case OConfItem::Source :
00166                     {
00167                         if ( item->features().contains( "Compressed" ) )
00168                             confLine.append( "src/gz" );
00169                         else
00170                             confLine.append( "src" );
00171                     }
00172                     break;
00173                     case OConfItem::Destination : confLine.append( "dest" ); break;
00174                     case OConfItem::Option : confLine.append( "option" ); break;
00175                     case OConfItem::Arch : confLine.append( "arch" ); break;
00176                     case OConfItem::Other :
00177                     {
00178                         // For options w/type = Other, the mapping is as follows:
00179                         //    name = typeStr (e.g. "lists_dir")
00180                         //    value = value
00181                         //    features = name (from configuration file)
00182                         confLine.append( item->name() );
00183                         name = item->features();
00184                     }
00185                     break;
00186                     default : break;
00187                 };
00188 
00189                 confStream << confLine << " " << name << " " << item->value() << "\n";
00190             }
00191         }
00192 
00193         confFile.close();
00194     }
00195     else
00196     {
00197         // Problem writing to /etc/ipkg.conf, exit before removing other conf files
00198         return;
00199     }
00200 
00201     // Delete /etc/ipkg/*.conf files (/etc/ipkg.conf should now have all settings
00202     QStringList confFiles;
00203     QDir confDir( IPKG_CONF_DIR );
00204     if ( confDir.exists() )
00205     {
00206         confDir.setNameFilter( "*.conf" );
00207         confDir.setFilter( QDir::Files );
00208         confFiles = confDir.entryList( "*.conf", QDir::Files );
00209 
00210         QStringList::Iterator lastFile = confFiles.end();
00211         for ( QStringList::Iterator it = confFiles.begin(); it != lastFile; ++it )
00212         {
00213             // Create absolute file path if necessary
00214             QString absFile = (*it);
00215             if ( !absFile.startsWith( "/" ) )
00216                 absFile.prepend( QString( IPKG_CONF_DIR ) + "/" );
00217 
00218             // Delete file
00219             QFile::remove( absFile );
00220         }
00221     }
00222 
00223     // Reinitialize libipkg to pick up new configuration
00224     ipkg_deinit( &m_ipkgArgs );
00225     ipkg_init( &fsignalIpkgMessage, &fIpkgResponse, &m_ipkgArgs );
00226     m_ipkgArgs.noaction = false;
00227     m_ipkgArgs.force_defaults = true;
00228 }
00229 
00230 void OIpkg::saveSettings()
00231 {
00232     // Save Ipkg execution options to application configuration file
00233     if ( m_config )
00234     {
00235         m_config->setGroup( "Ipkg" );
00236         m_config->writeEntry( "ExecOptions", m_ipkgExecOptions );
00237         m_config->writeEntry( "Verbosity", m_ipkgExecVerbosity );
00238     }
00239 }
00240 
00241 OPackageList *OIpkg::availablePackages( const QString &server )
00242 {
00243     // Load Ipkg configuration info if not already cached
00244     if ( !m_confInfo )
00245         loadConfiguration();
00246 
00247     // Build new server list (caller is responsible for deleting)
00248     OPackageList *pl = new OPackageList;
00249 
00250     // Get directory where server lists are located
00251     QString listsDir;
00252     OConfItem *confItem = findConfItem( OConfItem::Other, "lists_dir" );
00253     if ( confItem )
00254         listsDir = confItem->value();
00255     else
00256         listsDir = IPKG_PKG_PATH;
00257 
00258     // Open package list file
00259     QFile f( listsDir + "/" + server );
00260     if ( !f.open( IO_ReadOnly ) )
00261         return NULL;
00262     QTextStream t( &f );
00263 
00264     // Process all information in package list file
00265     OPackage *package = NULL;
00266     QString line = t.readLine();
00267     while ( !t.eof() )
00268     {
00269         // Determine key/value pair
00270         int pos = line.find( ':', 0 );
00271         QString key;
00272         if ( pos > -1 )
00273             key = line.mid( 0, pos );
00274         else
00275             key = QString::null;
00276         QString value = line.mid( pos+2, line.length()-pos );
00277 
00278         // Allocate new package and insert into list
00279         if ( package == NULL  && !key.isEmpty() )
00280         {
00281             package = new OPackage( value );
00282             package->setSource( server );
00283             pl->append( package );
00284         }
00285 
00286         // Update package data
00287         if ( key == "Package" )
00288                 package->setName( value );
00289         else if ( key == "Version" )
00290             package->setVersion( value );
00291         else if ( key == "Section" )
00292             package->setCategory( value );
00293             //DataManager::setAvailableCategories( value );
00294         else if ( key.isEmpty() && value.isEmpty() )
00295             package = NULL;
00296 
00297         // Skip past all description lines
00298         if ( key == "Description" )
00299         {
00300             line = t.readLine();
00301             while ( !line.isEmpty() && line.find( ':', 0 ) == -1 && !t.eof() )
00302                 line = t.readLine();
00303         }
00304         else
00305             line = t.readLine();
00306     }
00307 
00308     f.close();
00309 
00310     return pl;
00311 }
00312 
00313 OPackageList *OIpkg::installedPackages( const QString &destName, const QString &destPath )
00314 {
00315     // Load Ipkg configuration info if not already cached
00316     if ( !m_confInfo )
00317         loadConfiguration();
00318 
00319     // Build new server list (caller is responsible for deleting)
00320     OPackageList *pl = new OPackageList;
00321 
00322     // Open status file
00323     QString path = destPath;
00324     if ( path.right( 1 ) != "/" )
00325         path.append( "/" );
00326     path.append( IPKG_STATUS_PATH );
00327 
00328     QFile f( path );
00329     if ( !f.open( IO_ReadOnly ) )
00330         return NULL;
00331     QTextStream t( &f );
00332 
00333     // Process all information in status file
00334     bool newPackage = false;
00335     QString line = t.readLine();
00336     QString name;
00337     QString version;
00338     QString status;
00339 
00340     while ( !t.eof() )
00341     {
00342         // Determine key/value pair
00343         int pos = line.find( ':', 0 );
00344         QString key;
00345         if ( pos > -1 )
00346             key = line.mid( 0, pos );
00347         else
00348             key = QString::null;
00349         QString value = line.mid( pos+2, line.length()-pos );
00350 
00351         // Allocate new package and insert into list
00352         if ( newPackage  && !key.isEmpty() )
00353         {
00354             // Add to list only if it has a valid name and is installed
00355             if ( !name.isNull() && status.contains( " installed" ) )
00356             {
00357                 pl->append( new OPackage( name, QString::null, version, QString::null, destName ) );
00358                 name = QString::null;
00359                 version = QString::null;
00360                 status = QString::null;
00361 
00362                 newPackage = false;
00363             }
00364         }
00365 
00366         // Update package data
00367         if ( key == "Package" )
00368             name = value;
00369         else if ( key == "Version" )
00370             version = value;
00371         else if ( key == "Status" )
00372             status = value;
00373         else if ( key.isEmpty() && value.isEmpty() )
00374             newPackage = true;
00375 
00376         // Skip past all description lines
00377         if ( key == "Description" )
00378         {
00379             line = t.readLine();
00380             while ( !line.isEmpty() && line.find( ':', 0 ) == -1 && !t.eof() )
00381                 line = t.readLine();
00382         }
00383         else
00384             line = t.readLine();
00385     }
00386 
00387     f.close();
00388 
00389     // Make sure to add to list last entry
00390     if ( !name.isNull() && status.contains( " installed" ) )
00391         pl->append( new OPackage( name, QString::null, version, QString::null, destName ) );
00392 
00393     return pl;
00394 }
00395 
00396 OConfItem *OIpkg::findConfItem( OConfItem::Type type, const QString &name )
00397 {
00398     // Find configuration item in list
00399     OConfItemListIterator configIt( *m_confInfo );
00400     OConfItem *config = 0l;
00401     for ( ; configIt.current(); ++configIt )
00402     {
00403         config = configIt.current();
00404         if ( config->type() == type && config->name() == name )
00405             break;
00406     }
00407 
00408     if ( config && config->type() == type && config->name() == name )
00409         return config;
00410 
00411     return 0l;
00412 }
00413 
00414 bool OIpkg::executeCommand( OPackage::Command command, const QStringList &parameters, const QString &destination,
00415                             const QObject *receiver, const char *slotOutput, bool rawOutput )
00416 {
00417     if ( command == OPackage::NotDefined )
00418         return false;
00419 
00420     // Set ipkg run-time options/arguments
00421     m_ipkgArgs.force_depends = ( m_ipkgExecOptions & FORCE_DEPENDS );
00422     m_ipkgArgs.force_reinstall = ( m_ipkgExecOptions & FORCE_REINSTALL );
00423     // TODO m_ipkgArgs.force_remove = ( m_ipkgExecOptions & FORCE_REMOVE );
00424     m_ipkgArgs.force_overwrite = ( m_ipkgExecOptions & FORCE_OVERWRITE );
00425     m_ipkgArgs.verbosity = m_ipkgExecVerbosity;
00426     if ( m_ipkgArgs.dest )
00427         free( m_ipkgArgs.dest );
00428     if ( !destination.isNull() )
00429     {
00430         int len = destination.length() + 1;
00431         m_ipkgArgs.dest = (char *)malloc( len );
00432         strncpy( m_ipkgArgs.dest, destination, destination.length() );
00433         m_ipkgArgs.dest[ len - 1 ] = '\0';
00434     }
00435     else
00436         m_ipkgArgs.dest = 0l;
00437 
00438     // Connect output signal to widget
00439 
00440     if ( !rawOutput )
00441     {
00442         // TODO - connect to local slot and parse output before emitting signalIpkgMessage
00443     }
00444 
00445     switch( command )
00446     {
00447         case OPackage::Update : {
00448                 connect( this, SIGNAL(signalIpkgMessage(const QString &)), receiver, slotOutput );
00449                 ipkg_lists_update( &m_ipkgArgs );
00450                 disconnect( this, SIGNAL(signalIpkgMessage(const QString &)), 0, 0 );
00451             };
00452             break;
00453         case OPackage::Upgrade : {
00454                 connect( this, SIGNAL(signalIpkgMessage(const QString &)), receiver, slotOutput );
00455                 ipkg_packages_upgrade( &m_ipkgArgs );
00456 
00457                 // Re-link non-root destinations to make sure everything is in sync
00458                 OConfItemList *destList = destinations();
00459                 OConfItemListIterator it( *destList );
00460                 for ( ; it.current(); ++it )
00461                 {
00462                     OConfItem *dest = it.current();
00463                     if ( dest->name() != "root" )
00464                         linkPackageDir( dest->name() );
00465                 }
00466                 delete destList;
00467                 disconnect( this, SIGNAL(signalIpkgMessage(const QString &)), 0, 0 );
00468             };
00469             break;
00470         case OPackage::Install : {
00471                 connect( this, SIGNAL(signalIpkgMessage(const QString &)), receiver, slotOutput );
00472                 for ( QStringList::ConstIterator it = parameters.begin(); it != parameters.end(); ++it )
00473                 {
00474                     ipkg_packages_install( &m_ipkgArgs, (*it) );
00475                 }
00476                 if ( destination != "root" )
00477                     linkPackageDir( destination );
00478                 disconnect( this, SIGNAL(signalIpkgMessage(const QString &)), 0, 0 );
00479             };
00480             break;
00481         case OPackage::Remove : {
00482                 connect( this, SIGNAL(signalIpkgMessage(const QString &)), receiver, slotOutput );
00483 
00484                 // Get list of destinations for unlinking of packages not installed to root
00485                 OConfItemList *destList = destinations();
00486 
00487                 for ( QStringList::ConstIterator it = parameters.begin(); it != parameters.end(); ++it )
00488                 {
00489                     unlinkPackage( (*it), destList );
00490                     ipkg_packages_remove( &m_ipkgArgs, (*it), true );
00491                 }
00492 
00493                 delete destList;
00494                 disconnect( this, SIGNAL(signalIpkgMessage(const QString &)), 0, 0 );
00495             };
00496             break;
00497         case OPackage::Download : {
00498                 connect( this, SIGNAL(signalIpkgMessage(const QString &)), receiver, slotOutput );
00499                 for ( QStringList::ConstIterator it = parameters.begin(); it != parameters.end(); ++it )
00500                 {
00501                     ipkg_packages_download( &m_ipkgArgs, (*it) );
00502                 }
00503                 disconnect( this, SIGNAL(signalIpkgMessage(const QString &)), 0, 0 );
00504             };
00505             break;
00506         case OPackage::Info : {
00507                 connect( this, SIGNAL(signalIpkgStatus(const QString &)), receiver, slotOutput );
00508                 ipkg_packages_info( &m_ipkgArgs, (*parameters.begin()), &fIpkgStatus, 0l );
00509                 disconnect( this, SIGNAL(signalIpkgStatus(const QString &)), 0, 0 );
00510             };
00511             break;
00512         case OPackage::Files : {
00513                 connect( this, SIGNAL(signalIpkgList(const QString &)), receiver, slotOutput );
00514                 ipkg_package_files( &m_ipkgArgs, (*parameters.begin()), &fIpkgFiles, 0l );
00515                 disconnect( this, SIGNAL(signalIpkgList(const QString &)), 0, 0 );
00516             };
00517             break;
00518         default : break;
00519     };
00520 
00521     return true;
00522 }
00523 
00524 void OIpkg::ipkgMessage( char *msg )
00525 {
00526     emit signalIpkgMessage( msg );
00527 }
00528 
00529 void OIpkg::ipkgStatus( char *status )
00530 {
00531     emit signalIpkgStatus( status );
00532 }
00533 
00534 void OIpkg::ipkgList( char *filelist )
00535 {
00536     emit signalIpkgList( filelist );
00537 }
00538 
00539 void OIpkg::loadConfiguration()
00540 {
00541     if ( m_confInfo )
00542         delete m_confInfo;
00543 
00544     // Load configuration item list
00545     m_confInfo = new OConfItemList();
00546 
00547     QStringList confFiles;
00548     QDir confDir( IPKG_CONF_DIR );
00549     if ( confDir.exists() )
00550     {
00551         confDir.setNameFilter( "*.conf" );
00552         confDir.setFilter( QDir::Files );
00553         confFiles = confDir.entryList( "*.conf", QDir::Files );
00554     }
00555     confFiles << IPKG_CONF;
00556 
00557     QStringList::Iterator lastFile = confFiles.end();
00558     for ( QStringList::Iterator it = confFiles.begin(); it != lastFile; ++it )
00559     {
00560         // Create absolute file path if necessary
00561         QString absFile = (*it);
00562         if ( !absFile.startsWith( "/" ) )
00563             absFile.prepend( QString( IPKG_CONF_DIR ) + "/" );
00564 
00565         // Read in file
00566         QFile f( absFile );
00567         if ( f.open( IO_ReadOnly ) )
00568         {
00569             QTextStream s( &f );
00570             while ( !s.eof() )
00571             {
00572 
00573                 QString line = s.readLine().simplifyWhiteSpace();
00574 
00575                 // Parse line and save info to the conf options list
00576                 if ( !line.isEmpty() )
00577                 {
00578                     // Strip leading comment marker if exists
00579                     bool comment = false;
00580                     if ( line.startsWith( "#" ) )
00581                     {
00582                         line.remove( 0, 1 );
00583                         line = line.simplifyWhiteSpace();
00584                         comment = true;
00585                     }
00586 
00587                     bool recognizedOption = true;
00588                     int pos = line.find( ' ', 1 )  + 1;
00589                     int endpos = line.find( ' ', pos );
00590 
00591                     // Name
00592                     QString name = line.mid( pos, endpos - pos );
00593 
00594                     // Value
00595                     QString value = "";
00596                     if ( endpos > -1 )
00597                         value = line.right( line.length() - endpos - 1 );
00598 
00599                     // Active
00600                     bool active = !comment;
00601 
00602                     // Type
00603                     // For options w/type = Other, the mapping is as follows:
00604                     //    name = typeStr (e.g. "lists_dir")
00605                     //    value = value
00606                     //    features = name (from configuration file)
00607 
00608                     QString typeStr = line.left( pos - 1 );
00609                     OConfItem::Type type;
00610                     QString features;
00611                     if ( typeStr == "src" )
00612                         type = OConfItem::Source;
00613                     else if ( typeStr == "src/gz" )
00614                     {
00615                         type = OConfItem::Source;
00616                         features = "Compressed";
00617                     }
00618                     else if ( typeStr == "dest" )
00619                         type = OConfItem::Destination;
00620                     else if ( typeStr == "option" )
00621                         type = OConfItem::Option;
00622                     else if ( typeStr == "arch" )
00623                         type = OConfItem::Arch;
00624                     else if ( typeStr == "lists_dir" )
00625                     {
00626                         type = OConfItem::Other;
00627                         features = name;
00628                         name = typeStr;
00629 
00630                         // Default value when not defined
00631                         if ( value == QString::null || value == "" )
00632                             value = IPKG_PKG_PATH;
00633                     }
00634                     else
00635                         recognizedOption = false;
00636 
00637                     // Add to list
00638                     if ( recognizedOption )
00639                         m_confInfo->append( new OConfItem( type, name, value, features, active ) );
00640                 }
00641             }
00642 
00643             f.close();
00644         }
00645     }
00646 
00647     // Load Ipkg execution options from application configuration file
00648     if ( m_config )
00649     {
00650         m_config->setGroup( "Ipkg" );
00651         m_ipkgExecOptions = m_config->readNumEntry( "ExecOptions", m_ipkgExecOptions );
00652         m_ipkgExecVerbosity = m_config->readNumEntry( "Verbosity", m_ipkgExecVerbosity );
00653     }
00654 }
00655 
00656 OConfItemList *OIpkg::filterConfItems( OConfItem::Type typefilter )
00657 {
00658     // Load Ipkg configuration info if not already cached
00659     if ( !m_confInfo )
00660         loadConfiguration();
00661 
00662     // Build new server list (caller is responsible for deleting)
00663     OConfItemList *sl = new OConfItemList;
00664 
00665     // If typefilter is empty, retrieve all items
00666     bool retrieveAll = ( typefilter == OConfItem::NotDefined );
00667 
00668     // Parse configuration info for servers
00669     OConfItemListIterator it( *m_confInfo );
00670     for ( ; it.current(); ++it )
00671     {
00672         OConfItem *item = it.current();
00673         if ( retrieveAll || item->type() == typefilter )
00674         {
00675             sl->append( item );
00676         }
00677     }
00678 
00679     return sl;
00680 }
00681 
00682 const QString &OIpkg::rootPath()
00683 {
00684     if ( m_rootPath.isEmpty() )
00685     {
00686         OConfItem *rootDest = findConfItem( OConfItem::Destination, "root" );
00687         rootDest ? m_rootPath = rootDest->value()
00688                  : m_rootPath = '/';
00689         if ( m_rootPath.right( 1 ) == '/' )
00690             m_rootPath.truncate( m_rootPath.length() - 1 );
00691     }
00692     return m_rootPath;
00693 }
00694 
00695 void OIpkg::linkPackageDir( const QString &dest )
00696 {
00697     if ( !dest.isNull() )
00698     {
00699         OConfItem *destConfItem = findConfItem( OConfItem::Destination, dest );
00700 
00701         emit signalIpkgMessage( tr( "Linking packages installed in: %1" ).arg( dest ) );
00702 
00703         // Set package destination directory
00704         QString destDir = destConfItem->value();
00705         QString destInfoDir = destDir;
00706         if ( destInfoDir.right( 1 ) != '/' )
00707             destInfoDir.append( '/' );
00708         destInfoDir.append( IPKG_INFO_PATH );
00709 
00710         // Get list of installed packages in destination
00711         QDir packageDir( destInfoDir );
00712         QStringList packageFiles;
00713         if ( packageDir.exists() )
00714         {
00715             packageDir.setNameFilter( "*.list" );
00716             packageDir.setFilter( QDir::Files );
00717             packageFiles = packageDir.entryList( "*.list", QDir::Files );
00718         }
00719 
00720         // Link all files for every package installed in desination
00721         QStringList::Iterator lastFile = packageFiles.end();
00722         for ( QStringList::Iterator it = packageFiles.begin(); it != lastFile; ++it )
00723         {
00724             //emit signalIpkgMessage( QString( "Processing: %1/%2" ).arg( destInfoDir ).arg (*it) );
00725             QString packageFileName = destInfoDir;
00726             packageFileName.append( '/' );
00727             packageFileName.append( (*it) );
00728             QFile packageFile( packageFileName );
00729             if ( packageFile.open( IO_ReadOnly ) )
00730             {
00731                 QTextStream t( &packageFile );
00732                 QString linkFile;
00733                 while ( !t.eof() )
00734                 {
00735                     // Get the name of the file to link and build the sym link filename
00736                     linkFile = t.readLine();
00737                     QString linkDest( linkFile.right( linkFile.length() - destDir.length() ) );
00738                     linkDest.prepend( rootPath() );
00739 
00740                     // If file installed file is actually symbolic link, use actual file for linking
00741                     QFileInfo fileInfo( linkFile );
00742                     if ( fileInfo.isSymLink() && !fileInfo.readLink().isEmpty() )
00743                         linkFile = fileInfo.readLink();
00744 
00745                     // See if directory exists in 'root', if not, create
00746                     fileInfo.setFile( linkDest );
00747                     QString linkDestDirName = fileInfo.dirPath( true );
00748                     QDir linkDestDir( linkDestDirName );
00749                     if ( !linkDestDir.exists() )
00750                     {
00751                         linkDestDir.mkdir( linkDestDirName );
00752                     }
00753                     else
00754                     {
00755                         // Remove any previous link to make sure we will be pointing to the current version
00756                         if ( QFile::exists( linkDest ) )
00757                             QFile::remove( linkDest );
00758                     }
00759 
00760                     // Link the file
00761                     //emit signalIpkgMessage( QString( "Linking '%1' to '%2'" ).arg( linkFile ).arg( linkDest ) );
00762                     if ( symlink( linkFile, linkDest ) == -1 )
00763                         emit signalIpkgMessage( tr( "Error linkling '%1' to '%2'" )
00764                                                 .arg( linkFile )
00765                                                 .arg( linkDest ) );
00766                 }
00767                 packageFile.close();
00768             }
00769         }
00770     }
00771 }
00772 
00773 void OIpkg::unlinkPackage( const QString &package, OConfItemList *destList )
00774 {
00775     if ( !package.isNull() )
00776     {
00777         // Find destination package is installed in
00778         if ( destList )
00779         {
00780             OConfItemListIterator it( *destList );
00781             for ( ; it.current(); ++it )
00782             {
00783                 OConfItem *dest = it.current();
00784                 QString destInfoFileName = QString( "%1/%2/%3.list" ).arg( dest->value() )
00785                                                                      .arg( IPKG_INFO_PATH )
00786                                                                      .arg( package );
00787                 //emit signalIpkgMessage( QString( "Looking for '%1'" ).arg ( destInfoFileName ) );
00788 
00789                 // If found and destination is not 'root', remove symbolic links
00790                 if ( QFile::exists( destInfoFileName ) && dest->name() != "root" )
00791                 {
00792                     QFile destInfoFile( destInfoFileName );
00793                     if ( destInfoFile.open( IO_ReadOnly ) )
00794                     {
00795                         QTextStream t( &destInfoFile );
00796                         QString linkFile;
00797                         while ( !t.eof() )
00798                         {
00799                             // Get the name of the file to link and build the sym link filename
00800                             linkFile = t.readLine();
00801                             QString linkDest( linkFile.right( linkFile.length() -
00802                                                               dest->value().length() ) );
00803                             linkDest.prepend( rootPath() );
00804 
00805                             //emit signalIpkgMessage( QString( "Deleting: '%1'" ).arg( linkDest ) );
00806                             QFile::remove( linkDest );
00807                         }
00808                         destInfoFile.close();
00809                     }
00810 
00811                     emit signalIpkgMessage( tr( "Links removed for: %1" ).arg( package ) );
00812                     return;
00813                 }
00814             }
00815         }
00816     }
00817 }

Generated on Sat Nov 5 16:17:57 2005 for OPIE by  doxygen 1.4.2