• Skip to content
  • Skip to link menu
KDE 4.5 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • Sitemap
  • Contact Us
 

akonadi

selftestdialog.cpp

00001 /*
00002     Copyright (c) 2008 Volker Krause <vkrause@kde.org>
00003 
00004     This library is free software; you can redistribute it and/or modify it
00005     under the terms of the GNU Library General Public License as published by
00006     the Free Software Foundation; either version 2 of the License, or (at your
00007     option) any later version.
00008 
00009     This library is distributed in the hope that it will be useful, but WITHOUT
00010     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00011     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00012     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 the
00016     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017     02110-1301, USA.
00018 */
00019 
00020 #include "selftestdialog_p.h"
00021 #include "agentmanager.h"
00022 #include "session_p.h"
00023 #include "servermanager_p.h"
00024 
00025 #include <akonadi/private/xdgbasedirs_p.h>
00026 
00027 #include <KDebug>
00028 #include <KIcon>
00029 #include <KFileDialog>
00030 #include <KLocale>
00031 #include <KMessageBox>
00032 #include <KRun>
00033 #include <KStandardDirs>
00034 #include <KUser>
00035 
00036 #include <QtCore/QFileInfo>
00037 #include <QtCore/QProcess>
00038 #include <QtCore/QSettings>
00039 #include <QtCore/QTextStream>
00040 #include <QtDBus/QtDBus>
00041 #include <QtGui/QApplication>
00042 #include <QtGui/QClipboard>
00043 #include <QtGui/QStandardItemModel>
00044 #include <QtSql/QSqlDatabase>
00045 #include <QtSql/QSqlError>
00046 
00047 // @cond PRIVATE
00048 
00049 #define AKONADI_CONTROL_SERVICE QLatin1String( "org.freedesktop.Akonadi.Control" )
00050 #define AKONADI_SERVER_SERVICE QLatin1String( "org.freedesktop.Akonadi" )
00051 #define AKONADI_SEARCH_SERVICE QLatin1String( "org.kde.nepomuk.services.nepomukqueryservice" )
00052 
00053 using namespace Akonadi;
00054 
00055 static QString makeLink( const QString &file )
00056 {
00057   return QString::fromLatin1( "<a href=\"%1\">%2</a>" ).arg( file, file );
00058 }
00059 
00060 enum SelfTestRole {
00061   ResultTypeRole = Qt::UserRole,
00062   FileIncludeRole,
00063   ListDirectoryRole,
00064   EnvVarRole,
00065   SummaryRole,
00066   DetailsRole
00067 };
00068 
00069 SelfTestDialog::SelfTestDialog(QWidget * parent) :
00070     KDialog( parent )
00071 {
00072   setCaption( i18n( "Akonadi Server Self-Test" ) );
00073   setButtons( Close | User1 | User2 );
00074   setButtonText( User1, i18n( "Save Report..." ) );
00075   setButtonIcon( User1, KIcon( QString::fromLatin1( "document-save" ) ) );
00076   setButtonText( User2, i18n( "Copy Report to Clipboard" ) );
00077   setButtonIcon( User2, KIcon( QString::fromLatin1( "edit-copy" ) ) );
00078   showButtonSeparator( true );
00079   ui.setupUi( mainWidget() );
00080 
00081   mTestModel = new QStandardItemModel( this );
00082   ui.testView->setModel( mTestModel );
00083   connect( ui.testView->selectionModel(), SIGNAL( currentChanged( const QModelIndex&, const QModelIndex& ) ),
00084            SLOT( selectionChanged( const QModelIndex& ) ) );
00085   connect( ui.detailsLabel, SIGNAL( linkActivated( const QString& ) ), SLOT( linkActivated( const QString& ) ) );
00086 
00087   connect( this, SIGNAL( user1Clicked() ), SLOT( saveReport() ) );
00088   connect( this, SIGNAL( user2Clicked() ), SLOT( copyReport() ) );
00089 
00090   connect( ServerManager::self(), SIGNAL( stateChanged( Akonadi::ServerManager::State ) ), SLOT( runTests() ) );
00091   runTests();
00092 }
00093 
00094 void SelfTestDialog::hideIntroduction()
00095 {
00096   ui.introductionLabel->hide();
00097 }
00098 
00099 QStandardItem* SelfTestDialog::report( ResultType type, const KLocalizedString & summary, const KLocalizedString & details)
00100 {
00101   QStandardItem *item = new QStandardItem( summary.toString() );
00102   switch ( type ) {
00103     case Skip:
00104       item->setIcon( KIcon( QString::fromLatin1( "dialog-ok" ) ) );
00105       break;
00106     case Success:
00107       item->setIcon( KIcon( QString::fromLatin1( "dialog-ok-apply" ) ) );
00108       break;
00109     case Warning:
00110       item->setIcon( KIcon( QString::fromLatin1( "dialog-warning" ) ) );
00111       break;
00112     case Error:
00113     default:
00114       item->setIcon( KIcon( QString::fromLatin1( "dialog-error" ) ) );
00115   }
00116   item->setEditable( false );
00117   item->setWhatsThis( details.toString() );
00118   item->setData( type, ResultTypeRole );
00119   item->setData( summary.toString( 0 ), SummaryRole );
00120   item->setData( details.toString( 0 ), DetailsRole );
00121   mTestModel->appendRow( item );
00122   return item;
00123 }
00124 
00125 void SelfTestDialog::selectionChanged(const QModelIndex &index )
00126 {
00127   if ( index.isValid() ) {
00128     ui.detailsLabel->setText( index.data( Qt::WhatsThisRole ).toString() );
00129     ui.detailsGroup->setEnabled( true );
00130   } else {
00131     ui.detailsLabel->setText( QString() );
00132     ui.detailsGroup->setEnabled( false );
00133   }
00134 }
00135 
00136 void SelfTestDialog::runTests()
00137 {
00138   mTestModel->clear();
00139 
00140   const QString driver = serverSetting( QLatin1String( "General" ), "Driver", QLatin1String( "QMYSQL" ) ).toString();
00141   testSQLDriver();
00142   if (driver == QLatin1String( "QPSQL" )) {
00143     testPSQLServer();
00144   }
00145   else {
00146     testRootUser();
00147     testMySQLServer();
00148     testMySQLServerLog();
00149     testMySQLServerConfig();
00150   }
00151   testAkonadiCtl();
00152   testServerStatus();
00153   testSearchStatus();
00154   testProtocolVersion();
00155   testResources();
00156   testServerLog();
00157   testControlLog();
00158 }
00159 
00160 QVariant SelfTestDialog::serverSetting(const QString & group, const char *key, const QVariant &def ) const
00161 {
00162   const QString serverConfigFile = XdgBaseDirs::akonadiServerConfigFile( XdgBaseDirs::ReadWrite );
00163   QSettings settings( serverConfigFile, QSettings::IniFormat );
00164   settings.beginGroup( group );
00165   return settings.value( QString::fromLatin1(key), def );
00166 }
00167 
00168 bool SelfTestDialog::useStandaloneMysqlServer() const
00169 {
00170   const QString driver = serverSetting( QLatin1String( "General" ), "Driver", QLatin1String( "QMYSQL" ) ).toString();
00171   if ( driver != QLatin1String( "QMYSQL" ) )
00172     return false;
00173   const bool startServer = serverSetting( driver, "StartServer", true ).toBool();
00174   if ( !startServer )
00175     return false;
00176   return true;
00177 }
00178 
00179 bool SelfTestDialog::runProcess(const QString & app, const QStringList & args, QString & result) const
00180 {
00181   QProcess proc;
00182   proc.start( app, args );
00183   const bool rv = proc.waitForFinished();
00184   result.clear();
00185   result += QString::fromLocal8Bit( proc.readAllStandardError() );
00186   result += QString::fromLocal8Bit( proc.readAllStandardOutput() );
00187   return rv;
00188 }
00189 
00190 void SelfTestDialog::testSQLDriver()
00191 {
00192   const QString driver = serverSetting( QLatin1String( "General" ), "Driver", QLatin1String( "QMYSQL" ) ).toString();
00193   const QStringList availableDrivers = QSqlDatabase::drivers();
00194   const KLocalizedString detailsOk = ki18n( "The QtSQL driver '%1' is required by your current Akonadi server configuration and was found on your system." )
00195       .subs( driver );
00196   const KLocalizedString detailsFail = ki18n( "The QtSQL driver '%1' is required by your current Akonadi server configuration.\n"
00197       "The following drivers are installed: %2.\n"
00198       "Make sure the required driver is installed." )
00199       .subs( driver )
00200       .subs( availableDrivers.join( QLatin1String( ", " ) ) );
00201   QStandardItem *item = 0;
00202   if ( availableDrivers.contains( driver ) )
00203     item = report( Success, ki18n( "Database driver found." ), detailsOk );
00204   else
00205     item = report( Error, ki18n( "Database driver not found." ), detailsFail );
00206   item->setData( XdgBaseDirs::akonadiServerConfigFile( XdgBaseDirs::ReadWrite ), FileIncludeRole );
00207 }
00208 
00209 void SelfTestDialog::testMySQLServer()
00210 {
00211   if ( !useStandaloneMysqlServer() ) {
00212     report( Skip, ki18n( "MySQL server executable not tested." ),
00213             ki18n( "The current configuration does not require an internal MySQL server." ) );
00214     return;
00215   }
00216 
00217   const QString driver = serverSetting( QLatin1String( "General" ), "Driver", QLatin1String( "QMYSQL" ) ).toString();
00218   const QString serverPath = serverSetting( driver,  "ServerPath", QLatin1String( "" ) ).toString(); // ### default?
00219 
00220   const KLocalizedString details = ki18n( "You have currently configured Akonadi to use the MySQL server '%1'.\n"
00221       "Make sure you have the MySQL server installed, set the correct path and ensure you have the "
00222       "necessary read and execution rights on the server executable. The server executable is typically "
00223       "called 'mysqld'; its location varies depending on the distribution." ).subs( serverPath );
00224 
00225   QFileInfo info( serverPath );
00226   if ( !info.exists() )
00227     report( Error, ki18n( "MySQL server not found." ), details );
00228   else if ( !info.isReadable() )
00229     report( Error, ki18n( "MySQL server not readable." ), details );
00230   else if ( !info.isExecutable() )
00231     report( Error, ki18n( "MySQL server not executable." ), details );
00232   else if ( !serverPath.contains( QLatin1String( "mysqld" ) ) )
00233     report( Warning, ki18n( "MySQL found with unexpected name." ), details );
00234   else
00235     report( Success, ki18n( "MySQL server found." ), details );
00236 
00237   // be extra sure and get the server version while we are at it
00238   QString result;
00239   if ( runProcess( serverPath, QStringList() << QLatin1String( "--version" ), result ) ) {
00240     const KLocalizedString details = ki18n( "MySQL server found: %1" ).subs( result );
00241     report( Success, ki18n( "MySQL server is executable." ), details );
00242   } else {
00243     const KLocalizedString details = ki18n( "Executing the MySQL server '%1' failed with the following error message: '%2'" )
00244         .subs( serverPath ).subs( result );
00245     report( Error, ki18n( "Executing the MySQL server failed." ), details );
00246   }
00247 }
00248 
00249 void SelfTestDialog::testMySQLServerLog()
00250 {
00251   if ( !useStandaloneMysqlServer() ) {
00252     report( Skip, ki18n( "MySQL server error log not tested." ),
00253             ki18n( "The current configuration does not require an internal MySQL server." ) );
00254     return;
00255   }
00256 
00257   const QString logFileName = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi/db_data" ) )
00258       + QDir::separator() + QString::fromLatin1( "mysql.err" );
00259   const QFileInfo logFileInfo( logFileName );
00260   if ( !logFileInfo.exists() || logFileInfo.size() == 0 ) {
00261     report( Success, ki18n( "No current MySQL error log found." ),
00262       ki18n( "The MySQL server did not report any errors during this startup. The log can be found in '%1'." ).subs( logFileName ) );
00263     return;
00264   }
00265   QFile logFile( logFileName );
00266   if ( !logFile.open( QFile::ReadOnly | QFile::Text  ) ) {
00267     report( Error, ki18n( "MySQL error log not readable." ),
00268       ki18n( "A MySQL server error log file was found but is not readable: %1" ).subs( makeLink( logFileName ) ) );
00269     return;
00270   }
00271   bool warningsFound = false;
00272   QStandardItem *item = 0;
00273   while ( !logFile.atEnd() ) {
00274     const QString line = QString::fromUtf8( logFile.readLine() );
00275     if ( line.contains( QLatin1String( "error" ), Qt::CaseInsensitive ) ) {
00276       item = report( Error, ki18n( "MySQL server log contains errors." ),
00277         ki18n( "The MySQL server error log file '%1' contains errors." ).subs( makeLink( logFileName ) ) );
00278       item->setData( logFileName, FileIncludeRole );
00279       return;
00280     }
00281     if ( !warningsFound && line.contains( QLatin1String( "warn" ), Qt::CaseInsensitive ) ) {
00282       warningsFound = true;
00283     }
00284   }
00285   if ( warningsFound ) {
00286     item = report( Warning, ki18n( "MySQL server log contains warnings." ),
00287                    ki18n( "The MySQL server log file '%1' contains warnings." ).subs( makeLink( logFileName ) ) );
00288   } else {
00289     item = report( Success, ki18n( "MySQL server log contains no errors." ),
00290                    ki18n( "The MySQL server log file '%1' does not contain any errors or warnings." )
00291                          .subs( makeLink( logFileName ) ) );
00292   }
00293   item->setData( logFileName, FileIncludeRole );
00294 
00295   logFile.close();
00296 }
00297 
00298 void SelfTestDialog::testMySQLServerConfig()
00299 {
00300   if ( !useStandaloneMysqlServer() ) {
00301     report( Skip, ki18n( "MySQL server configuration not tested." ),
00302             ki18n( "The current configuration does not require an internal MySQL server." ) );
00303     return;
00304   }
00305 
00306   QStandardItem *item = 0;
00307   const QString globalConfig = XdgBaseDirs::findResourceFile( "config", QLatin1String( "akonadi/mysql-global.conf" ) );
00308   const QFileInfo globalConfigInfo( globalConfig );
00309   if ( !globalConfig.isEmpty() && globalConfigInfo.exists() && globalConfigInfo.isReadable() ) {
00310     item = report( Success, ki18n( "MySQL server default configuration found." ),
00311                    ki18n( "The default configuration for the MySQL server was found and is readable at %1." )
00312                    .subs( makeLink( globalConfig ) ) );
00313     item->setData( globalConfig, FileIncludeRole );
00314   } else {
00315     report( Error, ki18n( "MySQL server default configuration not found." ),
00316             ki18n( "The default configuration for the MySQL server was not found or was not readable. "
00317                   "Check your Akonadi installation is complete and you have all required access rights." ) );
00318   }
00319 
00320   const QString localConfig  = XdgBaseDirs::findResourceFile( "config", QLatin1String( "akonadi/mysql-local.conf" ) );
00321   const QFileInfo localConfigInfo( localConfig );
00322   if ( localConfig.isEmpty() || !localConfigInfo.exists() ) {
00323     report( Skip, ki18n( "MySQL server custom configuration not available." ),
00324             ki18n( "The custom configuration for the MySQL server was not found but is optional." ) );
00325   } else if ( localConfigInfo.exists() && localConfigInfo.isReadable() ) {
00326     item = report( Success, ki18n( "MySQL server custom configuration found." ),
00327                    ki18n( "The custom configuration for the MySQL server was found and is readable at %1" )
00328                    .subs( makeLink( localConfig ) ) );
00329     item->setData( localConfig, FileIncludeRole );
00330   } else {
00331     report( Error, ki18n( "MySQL server custom configuration not readable." ),
00332             ki18n( "The custom configuration for the MySQL server was found at %1 but is not readable. "
00333                   "Check your access rights." ).subs( makeLink( localConfig ) ) );
00334   }
00335 
00336   const QString actualConfig = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi" ) ) + QLatin1String( "/mysql.conf" );
00337   const QFileInfo actualConfigInfo( actualConfig );
00338   if ( actualConfig.isEmpty() || !actualConfigInfo.exists() || !actualConfigInfo.isReadable() ) {
00339     report( Error, ki18n( "MySQL server configuration not found or not readable." ),
00340             ki18n( "The MySQL server configuration was not found or is not readable." ) );
00341   } else {
00342     item = report( Success, ki18n( "MySQL server configuration is usable." ),
00343                    ki18n( "The MySQL server configuration was found at %1 and is readable." ).subs( makeLink( actualConfig ) ) );
00344     item->setData( actualConfig, FileIncludeRole );
00345   }
00346 }
00347 
00348 void SelfTestDialog::testPSQLServer()
00349 {
00350   const QString dbname = serverSetting( QLatin1String( "QPSQL" ), "Name", QLatin1String( "akonadi" )).toString();
00351   const QString hostname = serverSetting( QLatin1String( "QPSQL" ), "Host", QLatin1String( "localhost" )).toString();
00352   const QString username = serverSetting( QLatin1String( "QPSQL" ), "User", QString() ).toString();
00353   const QString password = serverSetting( QLatin1String( "QPSQL" ), "Password", QString() ).toString();
00354   const int port = serverSetting( QLatin1String( "QPSQL" ), "Port", 5432).toInt();
00355 
00356   QSqlDatabase db = QSqlDatabase::addDatabase( QLatin1String( "QPSQL" ) );
00357   db.setHostName( hostname );
00358   db.setDatabaseName( dbname );
00359 
00360   if ( !username.isEmpty() )
00361     db.setUserName( username );
00362 
00363   if ( !password.isEmpty() )
00364     db.setPassword( password );
00365 
00366   db.setPort( port );
00367 
00368   if ( !db.open() ) {
00369     const KLocalizedString details = ki18n( db.lastError().text().toLatin1() );
00370     report( Error, ki18n( "Cannot connect to PostgreSQL server." ),  details);
00371   }
00372   else {
00373     report( Success, ki18n( "PostgreSQL server found." ),
00374                    ki18n( "The PostgreSQL server was found and connection is working." ));
00375   }
00376   db.close();
00377 }
00378 
00379 void SelfTestDialog::testAkonadiCtl()
00380 {
00381   const QString path = KStandardDirs::findExe( QLatin1String( "akonadictl" ) );
00382   if ( path.isEmpty() ) {
00383     report( Error, ki18n( "akonadictl not found" ),
00384                  ki18n( "The program 'akonadictl' needs to be accessible in $PATH. "
00385                        "Make sure you have the Akonadi server installed." ) );
00386     return;
00387   }
00388   QString result;
00389   if ( runProcess( path, QStringList() << QLatin1String( "--version" ), result ) ) {
00390     report( Success, ki18n( "akonadictl found and usable" ),
00391                    ki18n( "The program '%1' to control the Akonadi server was found "
00392                          "and could be executed successfully.\nResult:\n%2" ).subs( path ).subs( result ) );
00393   } else {
00394     report( Error, ki18n( "akonadictl found but not usable" ),
00395                  ki18n( "The program '%1' to control the Akonadi server was found "
00396                        "but could not be executed successfully.\nResult:\n%2\n"
00397                        "Make sure the Akonadi server is installed correctly." ).subs( path ).subs( result ) );
00398   }
00399 }
00400 
00401 void SelfTestDialog::testServerStatus()
00402 {
00403   if ( QDBusConnection::sessionBus().interface()->isServiceRegistered( AKONADI_CONTROL_SERVICE ) ) {
00404     report( Success, ki18n( "Akonadi control process registered at D-Bus." ),
00405                    ki18n( "The Akonadi control process is registered at D-Bus which typically indicates it is operational." ) );
00406   } else {
00407     report( Error, ki18n( "Akonadi control process not registered at D-Bus." ),
00408                  ki18n( "The Akonadi control process is not registered at D-Bus which typically means it was not started "
00409                        "or encountered a fatal error during startup."  ) );
00410   }
00411 
00412   if ( QDBusConnection::sessionBus().interface()->isServiceRegistered( AKONADI_SERVER_SERVICE ) ) {
00413     report( Success, ki18n( "Akonadi server process registered at D-Bus." ),
00414                    ki18n( "The Akonadi server process is registered at D-Bus which typically indicates it is operational." ) );
00415   } else {
00416     report( Error, ki18n( "Akonadi server process not registered at D-Bus." ),
00417                  ki18n( "The Akonadi server process is not registered at D-Bus which typically means it was not started "
00418                        "or encountered a fatal error during startup."  ) );
00419   }
00420 }
00421 
00422 void SelfTestDialog::testSearchStatus()
00423 {
00424   bool searchAvailable = false;
00425   if ( QDBusConnection::sessionBus().interface()->isServiceRegistered( AKONADI_SEARCH_SERVICE ) ) {
00426     searchAvailable = true;
00427     report( Success, ki18n( "Nepomuk search service registered at D-Bus." ),
00428                    ki18n( "The Nepomuk search service is registered at D-Bus which typically indicates it is operational." ) );
00429   } else {
00430     report( Error, ki18n( "Nepomuk search service not registered at D-Bus." ),
00431                    ki18n( "The Nepomuk search service is not registered at D-Bus which typically means it was not started "
00432                           "or encountered a fatal error during startup."  ) );
00433   }
00434 
00435   if ( searchAvailable ) {
00436     // check which backend is used
00437     QDBusInterface interface( QLatin1String( "org.kde.NepomukStorage" ), QLatin1String( "/nepomukstorage" ) );
00438     const QDBusReply<QString> reply = interface.call( QLatin1String( "usedSopranoBackend" ) );
00439     if ( reply.isValid() ) {
00440       const QString name = reply.value();
00441 
00442       // put blacklisted backends here
00443       if ( name.contains( QLatin1String( "redland" ) ) ) {
00444         report( Error, ki18n( "Nepomuk search service uses inappropriate backend." ),
00445                        ki18n( "The Nepomuk search service uses the '%1' backend, which is not "
00446                               "recommended for use with Akonadi." ).subs( name ) );
00447       } else {
00448         report( Success, ki18n( "Nepomuk search service uses an appropriate backend. " ),
00449                          ki18n( "The Nepomuk search service uses one of the recommended backends." ) );
00450       }
00451     }
00452   }
00453 }
00454 
00455 void SelfTestDialog::testProtocolVersion()
00456 {
00457   if ( Internal::serverProtocolVersion() < 0 ) {
00458     report( Skip, ki18n( "Protocol version check not possible." ),
00459             ki18n( "Without a connection to the server it is not possible to check if the protocol version meets the requirements." ) );
00460     return;
00461   }
00462   if ( Internal::serverProtocolVersion() < SessionPrivate::minimumProtocolVersion() ) {
00463     report( Error, ki18n( "Server protocol version is too old." ),
00464             ki18n( "The server protocol version is %1, but at least version %2 is required. "
00465                   "Install a newer version of the Akonadi server." )
00466                   .subs( Internal::serverProtocolVersion() )
00467                   .subs( SessionPrivate::minimumProtocolVersion() ) );
00468   } else {
00469     report( Success, ki18n( "Server protocol version is recent enough." ),
00470             ki18n( "The server Protocol version is %1, which equal or newer than the required version %2." )
00471                 .subs( Internal::serverProtocolVersion() )
00472                 .subs( SessionPrivate::minimumProtocolVersion() ) );
00473   }
00474 }
00475 
00476 void SelfTestDialog::testResources()
00477 {
00478   AgentType::List agentTypes = AgentManager::self()->types();
00479   bool resourceFound = false;
00480   foreach ( const AgentType &type, agentTypes ) {
00481     if ( type.capabilities().contains( QLatin1String( "Resource" ) ) ) {
00482       resourceFound = true;
00483       break;
00484     }
00485   }
00486 
00487   const QStringList pathList = XdgBaseDirs::findAllResourceDirs( "data", QLatin1String( "akonadi/agents" ) );
00488   QStandardItem *item = 0;
00489   if ( resourceFound ) {
00490     item = report( Success, ki18n( "Resource agents found." ), ki18n( "At least one resource agent has been found." ) );
00491   } else {
00492     item = report( Error, ki18n( "No resource agents found." ),
00493       ki18n( "No resource agents have been found, Akonadi is not usable without at least one. "
00494             "This usually means that no resource agents are installed or that there is a setup problem. "
00495             "The following paths have been searched: '%1'. "
00496             "The XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes all paths "
00497             "where Akonadi agents are installed." )
00498           .subs( pathList.join( QLatin1String( " " ) ) )
00499           .subs( QString::fromLocal8Bit( qgetenv( "XDG_DATA_DIRS" ) ) ) );
00500   }
00501   item->setData( pathList, ListDirectoryRole );
00502   item->setData( QByteArray( "XDG_DATA_DIRS" ), EnvVarRole );
00503 }
00504 
00505 void Akonadi::SelfTestDialog::testServerLog()
00506 {
00507   QString serverLog = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi" ) )
00508       + QDir::separator() + QString::fromLatin1( "akonadiserver.error" );
00509   QFileInfo info( serverLog );
00510   if ( !info.exists() || info.size() <= 0 ) {
00511     report( Success, ki18n( "No current Akonadi server error log found." ),
00512                    ki18n( "The Akonadi server did not report any errors during its current startup." ) );
00513   } else {
00514     QStandardItem *item = report( Error, ki18n( "Current Akonadi server error log found." ),
00515       ki18n( "The Akonadi server reported errors during its current startup. The log can be found in %1." ).subs( makeLink( serverLog ) ) );
00516     item->setData( serverLog, FileIncludeRole );
00517   }
00518 
00519   serverLog += QLatin1String( ".old" );
00520   info.setFile( serverLog );
00521   if ( !info.exists() || info.size() <= 0 ) {
00522     report( Success, ki18n( "No previous Akonadi server error log found." ),
00523                    ki18n( "The Akonadi server did not report any errors during its previous startup." ) );
00524   } else {
00525     QStandardItem *item = report( Error, ki18n( "Previous Akonadi server error log found." ),
00526       ki18n( "The Akonadi server reported errors during its previous startup. The log can be found in %1." ).subs( makeLink( serverLog ) ) );
00527     item->setData( serverLog, FileIncludeRole );
00528   }
00529 }
00530 
00531 void SelfTestDialog::testControlLog()
00532 {
00533   QString controlLog = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi" ) )
00534       + QDir::separator() + QString::fromLatin1( "akonadi_control.error" );
00535   QFileInfo info( controlLog );
00536   if ( !info.exists() || info.size() <= 0 ) {
00537     report( Success, ki18n( "No current Akonadi control error log found." ),
00538                    ki18n( "The Akonadi control process did not report any errors during its current startup." ) );
00539   } else {
00540     QStandardItem *item = report( Error, ki18n( "Current Akonadi control error log found." ),
00541       ki18n( "The Akonadi control process reported errors during its current startup. The log can be found in %1." ).subs( makeLink( controlLog ) ) );
00542     item->setData( controlLog, FileIncludeRole );
00543   }
00544 
00545   controlLog += QLatin1String( ".old" );
00546   info.setFile( controlLog );
00547   if ( !info.exists() || info.size() <= 0 ) {
00548     report( Success, ki18n( "No previous Akonadi control error log found." ),
00549                    ki18n( "The Akonadi control process did not report any errors during its previous startup." ) );
00550   } else {
00551     QStandardItem *item = report( Error, ki18n( "Previous Akonadi control error log found." ),
00552       ki18n( "The Akonadi control process reported errors during its previous startup. The log can be found in %1." ).subs( makeLink( controlLog ) ) );
00553     item->setData( controlLog, FileIncludeRole );
00554   }
00555 }
00556 
00557 
00558 void SelfTestDialog::testRootUser()
00559 {
00560   KUser user;
00561   if ( user.isSuperUser() ) {
00562     report( Error, ki18n( "Akonadi was started as root" ), ki18n( "Running Internet-facing applications as root/administrator exposes you to many security risks. MySQL, used by this Akonadi installation, will not allow itself to run as root, to protect you from these risks." ) );
00563   } else {
00564     report( Success, ki18n( "Akonadi is not running as root" ), ki18n( "Akonadi is not running as a root/administrator user, which is the recommended setup for a secure system." ) );
00565   }
00566 }
00567 
00568 QString SelfTestDialog::createReport()
00569 {
00570   QString result;
00571   QTextStream s( &result );
00572   s << "Akonadi Server Self-Test Report" << endl;
00573   s << "===============================" << endl;
00574 
00575   for ( int i = 0; i < mTestModel->rowCount(); ++i ) {
00576     QStandardItem *item = mTestModel->item( i );
00577     s << endl;
00578     s << "Test " << (i + 1) << ":  ";
00579     switch ( item->data( ResultTypeRole ).toInt() ) {
00580       case Skip:
00581         s << "SKIP"; break;
00582       case Success:
00583         s << "SUCCESS"; break;
00584       case Warning:
00585         s << "WARNING"; break;
00586       case Error:
00587       default:
00588         s << "ERROR"; break;
00589     }
00590     s << endl << "--------" << endl;
00591     s << endl;
00592     s << item->data( SummaryRole ).toString() << endl;
00593     s << "Details: " << item->data( DetailsRole ).toString() << endl;
00594     if ( item->data( FileIncludeRole ).isValid() ) {
00595       s << endl;
00596       const QString fileName = item->data( FileIncludeRole ).toString();
00597       QFile f( fileName );
00598       if ( f.open( QFile::ReadOnly ) ) {
00599         s << "File content of '" << fileName << "':" << endl;
00600         s << f.readAll() << endl;
00601       } else {
00602         s << "File '" << fileName << "' could not be opened" << endl;
00603       }
00604     }
00605     if ( item->data( ListDirectoryRole ).isValid() ) {
00606       s << endl;
00607       const QStringList pathList = item->data( ListDirectoryRole ).toStringList();
00608       if ( pathList.isEmpty() )
00609         s << "Directory list is empty." << endl;
00610       foreach ( const QString &path, pathList ) {
00611         s << "Directory listing of '" << path << "':" << endl;
00612         QDir dir( path );
00613         dir.setFilter( QDir::AllEntries | QDir::NoDotAndDotDot );
00614         foreach ( const QString &entry, dir.entryList() )
00615           s << entry << endl;
00616       }
00617     }
00618     if ( item->data( EnvVarRole ).isValid() ) {
00619       s << endl;
00620       const QByteArray envVarName = item->data( EnvVarRole ).toByteArray();
00621       const QByteArray envVarValue = qgetenv( envVarName );
00622       s << "Environment variable " << envVarName << " is set to '" << envVarValue << "'" << endl;
00623     }
00624   }
00625 
00626   s << endl;
00627   s.flush();
00628   return result;
00629 }
00630 
00631 void SelfTestDialog::saveReport()
00632 {
00633   const QString defaultFileName = QLatin1String( "akonadi-selftest-report-" )
00634                    + QDate::currentDate().toString( QLatin1String( "yyyyMMdd" ) )
00635                    + QLatin1String( ".txt" );
00636   const QString fileName =  KFileDialog::getSaveFileName( defaultFileName, QString(), this,
00637                                                           i18n( "Save Test Report" ) );
00638   if ( fileName.isEmpty() )
00639     return;
00640 
00641   QFile file( fileName );
00642   if ( !file.open( QFile::ReadWrite ) ) {
00643     KMessageBox::error( this, i18n( "Could not open file '%1'", fileName ) );
00644     return;
00645   }
00646 
00647   file.write( createReport().toUtf8() );
00648   file.close();
00649 }
00650 
00651 void SelfTestDialog::copyReport()
00652 {
00653   QApplication::clipboard()->setText( createReport() );
00654 }
00655 
00656 void SelfTestDialog::linkActivated(const QString & link)
00657 {
00658   KRun::runUrl( KUrl::fromPath( link ), QLatin1String( "text/plain" ), this );
00659 }
00660 
00661 // @endcond
00662 
00663 #include "selftestdialog_p.moc"

akonadi

Skip menu "akonadi"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kblog
  • kcal
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.7.1
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