• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.9.4 API Reference
  • KDE Home
  • Contact Us
 

akonadi

  • akonadi
selftestdialog.cpp
1 /*
2  Copyright (c) 2008 Volker Krause <vkrause@kde.org>
3 
4  This library is free software; you can redistribute it and/or modify it
5  under the terms of the GNU Library General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or (at your
7  option) any later version.
8 
9  This library is distributed in the hope that it will be useful, but WITHOUT
10  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12  License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to the
16  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  02110-1301, USA.
18 */
19 
20 #include "selftestdialog_p.h"
21 #include "agentmanager.h"
22 #include "dbusconnectionpool.h"
23 #include "session_p.h"
24 #include "servermanager_p.h"
25 
26 #include <akonadi/private/xdgbasedirs_p.h>
27 
28 #include <KDebug>
29 #include <KIcon>
30 #include <KFileDialog>
31 #include <KLocale>
32 #include <KMessageBox>
33 #include <KRun>
34 #include <KStandardDirs>
35 #include <KUser>
36 
37 #include <QtCore/QFileInfo>
38 #include <QtCore/QProcess>
39 #include <QtCore/QSettings>
40 #include <QtCore/QTextStream>
41 #include <QtDBus/QtDBus>
42 #include <QtGui/QApplication>
43 #include <QtGui/QClipboard>
44 #include <QtGui/QStandardItemModel>
45 #include <QtSql/QSqlDatabase>
46 #include <QtSql/QSqlError>
47 
48 // @cond PRIVATE
49 
50 #define AKONADI_CONTROL_SERVICE QLatin1String( "org.freedesktop.Akonadi.Control" )
51 #define AKONADI_SERVER_SERVICE QLatin1String( "org.freedesktop.Akonadi" )
52 #define AKONADI_SEARCH_SERVICE QLatin1String( "org.kde.nepomuk.services.nepomukqueryservice" )
53 
54 using namespace Akonadi;
55 
56 static QString makeLink( const QString &file )
57 {
58  return QString::fromLatin1( "<a href=\"%1\">%2</a>" ).arg( file, file );
59 }
60 
61 enum SelfTestRole {
62  ResultTypeRole = Qt::UserRole,
63  FileIncludeRole,
64  ListDirectoryRole,
65  EnvVarRole,
66  SummaryRole,
67  DetailsRole
68 };
69 
70 SelfTestDialog::SelfTestDialog(QWidget * parent) :
71  KDialog( parent )
72 {
73  setCaption( i18n( "Akonadi Server Self-Test" ) );
74  setButtons( Close | User1 | User2 );
75  setButtonText( User1, i18n( "Save Report..." ) );
76  setButtonIcon( User1, KIcon( QString::fromLatin1( "document-save" ) ) );
77  setButtonText( User2, i18n( "Copy Report to Clipboard" ) );
78  setButtonIcon( User2, KIcon( QString::fromLatin1( "edit-copy" ) ) );
79  showButtonSeparator( true );
80  ui.setupUi( mainWidget() );
81 
82  mTestModel = new QStandardItemModel( this );
83  ui.testView->setModel( mTestModel );
84  connect( ui.testView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
85  SLOT(selectionChanged(QModelIndex)) );
86  connect( ui.detailsLabel, SIGNAL(linkActivated(QString)), SLOT(linkActivated(QString)) );
87 
88  connect( this, SIGNAL(user1Clicked()), SLOT(saveReport()) );
89  connect( this, SIGNAL(user2Clicked()), SLOT(copyReport()) );
90 
91  connect( ServerManager::self(), SIGNAL(stateChanged(Akonadi::ServerManager::State)), SLOT(runTests()) );
92  runTests();
93 }
94 
95 void SelfTestDialog::hideIntroduction()
96 {
97  ui.introductionLabel->hide();
98 }
99 
100 QStandardItem* SelfTestDialog::report( ResultType type, const KLocalizedString & summary, const KLocalizedString & details)
101 {
102  QStandardItem *item = new QStandardItem( summary.toString() );
103  switch ( type ) {
104  case Skip:
105  item->setIcon( KIcon( QString::fromLatin1( "dialog-ok" ) ) );
106  break;
107  case Success:
108  item->setIcon( KIcon( QString::fromLatin1( "dialog-ok-apply" ) ) );
109  break;
110  case Warning:
111  item->setIcon( KIcon( QString::fromLatin1( "dialog-warning" ) ) );
112  break;
113  case Error:
114  default:
115  item->setIcon( KIcon( QString::fromLatin1( "dialog-error" ) ) );
116  }
117  item->setEditable( false );
118  item->setWhatsThis( details.toString() );
119  item->setData( type, ResultTypeRole );
120  item->setData( summary.toString( 0 ), SummaryRole );
121  item->setData( details.toString( 0 ), DetailsRole );
122  mTestModel->appendRow( item );
123  return item;
124 }
125 
126 void SelfTestDialog::selectionChanged(const QModelIndex &index )
127 {
128  if ( index.isValid() ) {
129  ui.detailsLabel->setText( index.data( Qt::WhatsThisRole ).toString() );
130  ui.detailsGroup->setEnabled( true );
131  } else {
132  ui.detailsLabel->setText( QString() );
133  ui.detailsGroup->setEnabled( false );
134  }
135 }
136 
137 void SelfTestDialog::runTests()
138 {
139  mTestModel->clear();
140 
141  const QString driver = serverSetting( QLatin1String( "General" ), "Driver", QLatin1String( "QMYSQL" ) ).toString();
142  testSQLDriver();
143  if (driver == QLatin1String( "QPSQL" )) {
144  testPSQLServer();
145  }
146  else {
147 #ifndef Q_OS_WIN
148  testRootUser();
149 #endif
150  testMySQLServer();
151  testMySQLServerLog();
152  testMySQLServerConfig();
153  }
154  testAkonadiCtl();
155  testServerStatus();
156  testSearchStatus();
157  testProtocolVersion();
158  testResources();
159  testServerLog();
160  testControlLog();
161 }
162 
163 QVariant SelfTestDialog::serverSetting(const QString & group, const char *key, const QVariant &def ) const
164 {
165  const QString serverConfigFile = XdgBaseDirs::akonadiServerConfigFile( XdgBaseDirs::ReadWrite );
166  QSettings settings( serverConfigFile, QSettings::IniFormat );
167  settings.beginGroup( group );
168  return settings.value( QString::fromLatin1(key), def );
169 }
170 
171 bool SelfTestDialog::useStandaloneMysqlServer() const
172 {
173  const QString driver = serverSetting( QLatin1String( "General" ), "Driver", QLatin1String( "QMYSQL" ) ).toString();
174  if ( driver != QLatin1String( "QMYSQL" ) )
175  return false;
176  const bool startServer = serverSetting( driver, "StartServer", true ).toBool();
177  if ( !startServer )
178  return false;
179  return true;
180 }
181 
182 bool SelfTestDialog::runProcess(const QString & app, const QStringList & args, QString & result) const
183 {
184  QProcess proc;
185  proc.start( app, args );
186  const bool rv = proc.waitForFinished();
187  result.clear();
188  result += QString::fromLocal8Bit( proc.readAllStandardError() );
189  result += QString::fromLocal8Bit( proc.readAllStandardOutput() );
190  return rv;
191 }
192 
193 void SelfTestDialog::testSQLDriver()
194 {
195  const QString driver = serverSetting( QLatin1String( "General" ), "Driver", QLatin1String( "QMYSQL" ) ).toString();
196  const QStringList availableDrivers = QSqlDatabase::drivers();
197  const KLocalizedString detailsOk = ki18n( "The QtSQL driver '%1' is required by your current Akonadi server configuration and was found on your system." )
198  .subs( driver );
199  const KLocalizedString detailsFail = ki18n( "The QtSQL driver '%1' is required by your current Akonadi server configuration.\n"
200  "The following drivers are installed: %2.\n"
201  "Make sure the required driver is installed." )
202  .subs( driver )
203  .subs( availableDrivers.join( QLatin1String( ", " ) ) );
204  QStandardItem *item = 0;
205  if ( availableDrivers.contains( driver ) )
206  item = report( Success, ki18n( "Database driver found." ), detailsOk );
207  else
208  item = report( Error, ki18n( "Database driver not found." ), detailsFail );
209  item->setData( XdgBaseDirs::akonadiServerConfigFile( XdgBaseDirs::ReadWrite ), FileIncludeRole );
210 }
211 
212 void SelfTestDialog::testMySQLServer()
213 {
214  if ( !useStandaloneMysqlServer() ) {
215  report( Skip, ki18n( "MySQL server executable not tested." ),
216  ki18n( "The current configuration does not require an internal MySQL server." ) );
217  return;
218  }
219 
220  const QString driver = serverSetting( QLatin1String( "General" ), "Driver", QLatin1String( "QMYSQL" ) ).toString();
221  const QString serverPath = serverSetting( driver, "ServerPath", QLatin1String( "" ) ).toString(); // ### default?
222 
223  const KLocalizedString details = ki18n( "You have currently configured Akonadi to use the MySQL server '%1'.\n"
224  "Make sure you have the MySQL server installed, set the correct path and ensure you have the "
225  "necessary read and execution rights on the server executable. The server executable is typically "
226  "called 'mysqld'; its location varies depending on the distribution." ).subs( serverPath );
227 
228  QFileInfo info( serverPath );
229  if ( !info.exists() )
230  report( Error, ki18n( "MySQL server not found." ), details );
231  else if ( !info.isReadable() )
232  report( Error, ki18n( "MySQL server not readable." ), details );
233  else if ( !info.isExecutable() )
234  report( Error, ki18n( "MySQL server not executable." ), details );
235  else if ( !serverPath.contains( QLatin1String( "mysqld" ) ) )
236  report( Warning, ki18n( "MySQL found with unexpected name." ), details );
237  else
238  report( Success, ki18n( "MySQL server found." ), details );
239 
240  // be extra sure and get the server version while we are at it
241  QString result;
242  if ( runProcess( serverPath, QStringList() << QLatin1String( "--version" ), result ) ) {
243  const KLocalizedString details = ki18n( "MySQL server found: %1" ).subs( result );
244  report( Success, ki18n( "MySQL server is executable." ), details );
245  } else {
246  const KLocalizedString details = ki18n( "Executing the MySQL server '%1' failed with the following error message: '%2'" )
247  .subs( serverPath ).subs( result );
248  report( Error, ki18n( "Executing the MySQL server failed." ), details );
249  }
250 }
251 
252 void SelfTestDialog::testMySQLServerLog()
253 {
254  if ( !useStandaloneMysqlServer() ) {
255  report( Skip, ki18n( "MySQL server error log not tested." ),
256  ki18n( "The current configuration does not require an internal MySQL server." ) );
257  return;
258  }
259 
260  const QString logFileName = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi/db_data" ) )
261  + QDir::separator() + QString::fromLatin1( "mysql.err" );
262  const QFileInfo logFileInfo( logFileName );
263  if ( !logFileInfo.exists() || logFileInfo.size() == 0 ) {
264  report( Success, ki18n( "No current MySQL error log found." ),
265  ki18n( "The MySQL server did not report any errors during this startup. The log can be found in '%1'." ).subs( logFileName ) );
266  return;
267  }
268  QFile logFile( logFileName );
269  if ( !logFile.open( QFile::ReadOnly | QFile::Text ) ) {
270  report( Error, ki18n( "MySQL error log not readable." ),
271  ki18n( "A MySQL server error log file was found but is not readable: %1" ).subs( makeLink( logFileName ) ) );
272  return;
273  }
274  bool warningsFound = false;
275  QStandardItem *item = 0;
276  while ( !logFile.atEnd() ) {
277  const QString line = QString::fromUtf8( logFile.readLine() );
278  if ( line.contains( QLatin1String( "error" ), Qt::CaseInsensitive ) ) {
279  item = report( Error, ki18n( "MySQL server log contains errors." ),
280  ki18n( "The MySQL server error log file '%1' contains errors." ).subs( makeLink( logFileName ) ) );
281  item->setData( logFileName, FileIncludeRole );
282  return;
283  }
284  if ( !warningsFound && line.contains( QLatin1String( "warn" ), Qt::CaseInsensitive ) ) {
285  warningsFound = true;
286  }
287  }
288  if ( warningsFound ) {
289  item = report( Warning, ki18n( "MySQL server log contains warnings." ),
290  ki18n( "The MySQL server log file '%1' contains warnings." ).subs( makeLink( logFileName ) ) );
291  } else {
292  item = report( Success, ki18n( "MySQL server log contains no errors." ),
293  ki18n( "The MySQL server log file '%1' does not contain any errors or warnings." )
294  .subs( makeLink( logFileName ) ) );
295  }
296  item->setData( logFileName, FileIncludeRole );
297 
298  logFile.close();
299 }
300 
301 void SelfTestDialog::testMySQLServerConfig()
302 {
303  if ( !useStandaloneMysqlServer() ) {
304  report( Skip, ki18n( "MySQL server configuration not tested." ),
305  ki18n( "The current configuration does not require an internal MySQL server." ) );
306  return;
307  }
308 
309  QStandardItem *item = 0;
310  const QString globalConfig = XdgBaseDirs::findResourceFile( "config", QLatin1String( "akonadi/mysql-global.conf" ) );
311  const QFileInfo globalConfigInfo( globalConfig );
312  if ( !globalConfig.isEmpty() && globalConfigInfo.exists() && globalConfigInfo.isReadable() ) {
313  item = report( Success, ki18n( "MySQL server default configuration found." ),
314  ki18n( "The default configuration for the MySQL server was found and is readable at %1." )
315  .subs( makeLink( globalConfig ) ) );
316  item->setData( globalConfig, FileIncludeRole );
317  } else {
318  report( Error, ki18n( "MySQL server default configuration not found." ),
319  ki18n( "The default configuration for the MySQL server was not found or was not readable. "
320  "Check your Akonadi installation is complete and you have all required access rights." ) );
321  }
322 
323  const QString localConfig = XdgBaseDirs::findResourceFile( "config", QLatin1String( "akonadi/mysql-local.conf" ) );
324  const QFileInfo localConfigInfo( localConfig );
325  if ( localConfig.isEmpty() || !localConfigInfo.exists() ) {
326  report( Skip, ki18n( "MySQL server custom configuration not available." ),
327  ki18n( "The custom configuration for the MySQL server was not found but is optional." ) );
328  } else if ( localConfigInfo.exists() && localConfigInfo.isReadable() ) {
329  item = report( Success, ki18n( "MySQL server custom configuration found." ),
330  ki18n( "The custom configuration for the MySQL server was found and is readable at %1" )
331  .subs( makeLink( localConfig ) ) );
332  item->setData( localConfig, FileIncludeRole );
333  } else {
334  report( Error, ki18n( "MySQL server custom configuration not readable." ),
335  ki18n( "The custom configuration for the MySQL server was found at %1 but is not readable. "
336  "Check your access rights." ).subs( makeLink( localConfig ) ) );
337  }
338 
339  const QString actualConfig = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi" ) ) + QLatin1String( "/mysql.conf" );
340  const QFileInfo actualConfigInfo( actualConfig );
341  if ( actualConfig.isEmpty() || !actualConfigInfo.exists() || !actualConfigInfo.isReadable() ) {
342  report( Error, ki18n( "MySQL server configuration not found or not readable." ),
343  ki18n( "The MySQL server configuration was not found or is not readable." ) );
344  } else {
345  item = report( Success, ki18n( "MySQL server configuration is usable." ),
346  ki18n( "The MySQL server configuration was found at %1 and is readable." ).subs( makeLink( actualConfig ) ) );
347  item->setData( actualConfig, FileIncludeRole );
348  }
349 }
350 
351 void SelfTestDialog::testPSQLServer()
352 {
353  const QString dbname = serverSetting( QLatin1String( "QPSQL" ), "Name", QLatin1String( "akonadi" )).toString();
354  const QString hostname = serverSetting( QLatin1String( "QPSQL" ), "Host", QLatin1String( "localhost" )).toString();
355  const QString username = serverSetting( QLatin1String( "QPSQL" ), "User", QString() ).toString();
356  const QString password = serverSetting( QLatin1String( "QPSQL" ), "Password", QString() ).toString();
357  const int port = serverSetting( QLatin1String( "QPSQL" ), "Port", 5432).toInt();
358 
359  QSqlDatabase db = QSqlDatabase::addDatabase( QLatin1String( "QPSQL" ) );
360  db.setHostName( hostname );
361  db.setDatabaseName( dbname );
362 
363  if ( !username.isEmpty() )
364  db.setUserName( username );
365 
366  if ( !password.isEmpty() )
367  db.setPassword( password );
368 
369  db.setPort( port );
370 
371  if ( !db.open() ) {
372  const KLocalizedString details = ki18n( db.lastError().text().toLatin1() );
373  report( Error, ki18n( "Cannot connect to PostgreSQL server." ), details);
374  }
375  else {
376  report( Success, ki18n( "PostgreSQL server found." ),
377  ki18n( "The PostgreSQL server was found and connection is working." ));
378  }
379  db.close();
380 }
381 
382 void SelfTestDialog::testAkonadiCtl()
383 {
384  const QString path = KStandardDirs::findExe( QLatin1String( "akonadictl" ) );
385  if ( path.isEmpty() ) {
386  report( Error, ki18n( "akonadictl not found" ),
387  ki18n( "The program 'akonadictl' needs to be accessible in $PATH. "
388  "Make sure you have the Akonadi server installed." ) );
389  return;
390  }
391  QString result;
392  if ( runProcess( path, QStringList() << QLatin1String( "--version" ), result ) ) {
393  report( Success, ki18n( "akonadictl found and usable" ),
394  ki18n( "The program '%1' to control the Akonadi server was found "
395  "and could be executed successfully.\nResult:\n%2" ).subs( path ).subs( result ) );
396  } else {
397  report( Error, ki18n( "akonadictl found but not usable" ),
398  ki18n( "The program '%1' to control the Akonadi server was found "
399  "but could not be executed successfully.\nResult:\n%2\n"
400  "Make sure the Akonadi server is installed correctly." ).subs( path ).subs( result ) );
401  }
402 }
403 
404 void SelfTestDialog::testServerStatus()
405 {
406  if ( DBusConnectionPool::threadConnection().interface()->isServiceRegistered( AKONADI_CONTROL_SERVICE ) ) {
407  report( Success, ki18n( "Akonadi control process registered at D-Bus." ),
408  ki18n( "The Akonadi control process is registered at D-Bus which typically indicates it is operational." ) );
409  } else {
410  report( Error, ki18n( "Akonadi control process not registered at D-Bus." ),
411  ki18n( "The Akonadi control process is not registered at D-Bus which typically means it was not started "
412  "or encountered a fatal error during startup." ) );
413  }
414 
415  if ( DBusConnectionPool::threadConnection().interface()->isServiceRegistered( AKONADI_SERVER_SERVICE ) ) {
416  report( Success, ki18n( "Akonadi server process registered at D-Bus." ),
417  ki18n( "The Akonadi server process is registered at D-Bus which typically indicates it is operational." ) );
418  } else {
419  report( Error, ki18n( "Akonadi server process not registered at D-Bus." ),
420  ki18n( "The Akonadi server process is not registered at D-Bus which typically means it was not started "
421  "or encountered a fatal error during startup." ) );
422  }
423 }
424 
425 void SelfTestDialog::testSearchStatus()
426 {
427  bool searchAvailable = false;
428  if ( DBusConnectionPool::threadConnection().interface()->isServiceRegistered( AKONADI_SEARCH_SERVICE ) ) {
429  searchAvailable = true;
430  report( Success, ki18n( "Nepomuk search service registered at D-Bus." ),
431  ki18n( "The Nepomuk search service is registered at D-Bus which typically indicates it is operational." ) );
432  } else {
433  report( Error, ki18n( "Nepomuk search service not registered at D-Bus." ),
434  ki18n( "The Nepomuk search service is not registered at D-Bus which typically means it was not started "
435  "or encountered a fatal error during startup." ) );
436  }
437 
438  if ( searchAvailable ) {
439  // check which backend is used
440  QDBusInterface interface( QLatin1String( "org.kde.NepomukStorage" ), QLatin1String( "/nepomukstorage" ) );
441  const QDBusReply<QString> reply = interface.call( QLatin1String( "usedSopranoBackend" ) );
442  if ( reply.isValid() ) {
443  const QString name = reply.value();
444 
445  // put blacklisted backends here
446  if ( name.contains( QLatin1String( "redland" ) ) ) {
447  report( Error, ki18n( "Nepomuk search service uses inappropriate backend." ),
448  ki18n( "The Nepomuk search service uses the '%1' backend, which is not "
449  "recommended for use with Akonadi." ).subs( name ) );
450  } else {
451  report( Success, ki18n( "Nepomuk search service uses an appropriate backend. " ),
452  ki18n( "The Nepomuk search service uses one of the recommended backends." ) );
453  }
454  }
455  }
456 }
457 
458 void SelfTestDialog::testProtocolVersion()
459 {
460  if ( Internal::serverProtocolVersion() < 0 ) {
461  report( Skip, ki18n( "Protocol version check not possible." ),
462  ki18n( "Without a connection to the server it is not possible to check if the protocol version meets the requirements." ) );
463  return;
464  }
465  if ( Internal::serverProtocolVersion() < SessionPrivate::minimumProtocolVersion() ) {
466  report( Error, ki18n( "Server protocol version is too old." ),
467  ki18n( "The server protocol version is %1, but at least version %2 is required. "
468  "Install a newer version of the Akonadi server." )
469  .subs( Internal::serverProtocolVersion() )
470  .subs( SessionPrivate::minimumProtocolVersion() ) );
471  } else {
472  report( Success, ki18n( "Server protocol version is recent enough." ),
473  ki18n( "The server Protocol version is %1, which equal or newer than the required version %2." )
474  .subs( Internal::serverProtocolVersion() )
475  .subs( SessionPrivate::minimumProtocolVersion() ) );
476  }
477 }
478 
479 void SelfTestDialog::testResources()
480 {
481  AgentType::List agentTypes = AgentManager::self()->types();
482  bool resourceFound = false;
483  foreach ( const AgentType &type, agentTypes ) {
484  if ( type.capabilities().contains( QLatin1String( "Resource" ) ) ) {
485  resourceFound = true;
486  break;
487  }
488  }
489 
490  const QStringList pathList = XdgBaseDirs::findAllResourceDirs( "data", QLatin1String( "akonadi/agents" ) );
491  QStandardItem *item = 0;
492  if ( resourceFound ) {
493  item = report( Success, ki18n( "Resource agents found." ), ki18n( "At least one resource agent has been found." ) );
494  } else {
495  item = report( Error, ki18n( "No resource agents found." ),
496  ki18n( "No resource agents have been found, Akonadi is not usable without at least one. "
497  "This usually means that no resource agents are installed or that there is a setup problem. "
498  "The following paths have been searched: '%1'. "
499  "The XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes all paths "
500  "where Akonadi agents are installed." )
501  .subs( pathList.join( QLatin1String( " " ) ) )
502  .subs( QString::fromLocal8Bit( qgetenv( "XDG_DATA_DIRS" ) ) ) );
503  }
504  item->setData( pathList, ListDirectoryRole );
505  item->setData( QByteArray( "XDG_DATA_DIRS" ), EnvVarRole );
506 }
507 
508 void Akonadi::SelfTestDialog::testServerLog()
509 {
510  QString serverLog = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi" ) )
511  + QDir::separator() + QString::fromLatin1( "akonadiserver.error" );
512  QFileInfo info( serverLog );
513  if ( !info.exists() || info.size() <= 0 ) {
514  report( Success, ki18n( "No current Akonadi server error log found." ),
515  ki18n( "The Akonadi server did not report any errors during its current startup." ) );
516  } else {
517  QStandardItem *item = report( Error, ki18n( "Current Akonadi server error log found." ),
518  ki18n( "The Akonadi server reported errors during its current startup. The log can be found in %1." ).subs( makeLink( serverLog ) ) );
519  item->setData( serverLog, FileIncludeRole );
520  }
521 
522  serverLog += QLatin1String( ".old" );
523  info.setFile( serverLog );
524  if ( !info.exists() || info.size() <= 0 ) {
525  report( Success, ki18n( "No previous Akonadi server error log found." ),
526  ki18n( "The Akonadi server did not report any errors during its previous startup." ) );
527  } else {
528  QStandardItem *item = report( Error, ki18n( "Previous Akonadi server error log found." ),
529  ki18n( "The Akonadi server reported errors during its previous startup. The log can be found in %1." ).subs( makeLink( serverLog ) ) );
530  item->setData( serverLog, FileIncludeRole );
531  }
532 }
533 
534 void SelfTestDialog::testControlLog()
535 {
536  QString controlLog = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi" ) )
537  + QDir::separator() + QString::fromLatin1( "akonadi_control.error" );
538  QFileInfo info( controlLog );
539  if ( !info.exists() || info.size() <= 0 ) {
540  report( Success, ki18n( "No current Akonadi control error log found." ),
541  ki18n( "The Akonadi control process did not report any errors during its current startup." ) );
542  } else {
543  QStandardItem *item = report( Error, ki18n( "Current Akonadi control error log found." ),
544  ki18n( "The Akonadi control process reported errors during its current startup. The log can be found in %1." ).subs( makeLink( controlLog ) ) );
545  item->setData( controlLog, FileIncludeRole );
546  }
547 
548  controlLog += QLatin1String( ".old" );
549  info.setFile( controlLog );
550  if ( !info.exists() || info.size() <= 0 ) {
551  report( Success, ki18n( "No previous Akonadi control error log found." ),
552  ki18n( "The Akonadi control process did not report any errors during its previous startup." ) );
553  } else {
554  QStandardItem *item = report( Error, ki18n( "Previous Akonadi control error log found." ),
555  ki18n( "The Akonadi control process reported errors during its previous startup. The log can be found in %1." ).subs( makeLink( controlLog ) ) );
556  item->setData( controlLog, FileIncludeRole );
557  }
558 }
559 
560 
561 void SelfTestDialog::testRootUser()
562 {
563  KUser user;
564  if ( user.isSuperUser() ) {
565  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." ) );
566  } else {
567  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." ) );
568  }
569 }
570 
571 QString SelfTestDialog::createReport()
572 {
573  QString result;
574  QTextStream s( &result );
575  s << "Akonadi Server Self-Test Report" << endl;
576  s << "===============================" << endl;
577 
578  for ( int i = 0; i < mTestModel->rowCount(); ++i ) {
579  QStandardItem *item = mTestModel->item( i );
580  s << endl;
581  s << "Test " << (i + 1) << ": ";
582  switch ( item->data( ResultTypeRole ).toInt() ) {
583  case Skip:
584  s << "SKIP"; break;
585  case Success:
586  s << "SUCCESS"; break;
587  case Warning:
588  s << "WARNING"; break;
589  case Error:
590  default:
591  s << "ERROR"; break;
592  }
593  s << endl << "--------" << endl;
594  s << endl;
595  s << item->data( SummaryRole ).toString() << endl;
596  s << "Details: " << item->data( DetailsRole ).toString() << endl;
597  if ( item->data( FileIncludeRole ).isValid() ) {
598  s << endl;
599  const QString fileName = item->data( FileIncludeRole ).toString();
600  QFile f( fileName );
601  if ( f.open( QFile::ReadOnly ) ) {
602  s << "File content of '" << fileName << "':" << endl;
603  s << f.readAll() << endl;
604  } else {
605  s << "File '" << fileName << "' could not be opened" << endl;
606  }
607  }
608  if ( item->data( ListDirectoryRole ).isValid() ) {
609  s << endl;
610  const QStringList pathList = item->data( ListDirectoryRole ).toStringList();
611  if ( pathList.isEmpty() )
612  s << "Directory list is empty." << endl;
613  foreach ( const QString &path, pathList ) {
614  s << "Directory listing of '" << path << "':" << endl;
615  QDir dir( path );
616  dir.setFilter( QDir::AllEntries | QDir::NoDotAndDotDot );
617  foreach ( const QString &entry, dir.entryList() )
618  s << entry << endl;
619  }
620  }
621  if ( item->data( EnvVarRole ).isValid() ) {
622  s << endl;
623  const QByteArray envVarName = item->data( EnvVarRole ).toByteArray();
624  const QByteArray envVarValue = qgetenv( envVarName );
625  s << "Environment variable " << envVarName << " is set to '" << envVarValue << "'" << endl;
626  }
627  }
628 
629  s << endl;
630  s.flush();
631  return result;
632 }
633 
634 void SelfTestDialog::saveReport()
635 {
636  const QString defaultFileName = QLatin1String( "akonadi-selftest-report-" )
637  + QDate::currentDate().toString( QLatin1String( "yyyyMMdd" ) )
638  + QLatin1String( ".txt" );
639  const QString fileName = KFileDialog::getSaveFileName( defaultFileName, QString(), this,
640  i18n( "Save Test Report" ) );
641  if ( fileName.isEmpty() )
642  return;
643 
644  QFile file( fileName );
645  if ( !file.open( QFile::ReadWrite ) ) {
646  KMessageBox::error( this, i18n( "Could not open file '%1'", fileName ) );
647  return;
648  }
649 
650  file.write( createReport().toUtf8() );
651  file.close();
652 }
653 
654 void SelfTestDialog::copyReport()
655 {
656 #ifndef QT_NO_CLIPBOARD
657  QApplication::clipboard()->setText( createReport() );
658 #endif
659 }
660 
661 void SelfTestDialog::linkActivated(const QString & link)
662 {
663  KRun::runUrl( KUrl::fromPath( link ), QLatin1String( "text/plain" ), this );
664 }
665 
666 // @endcond
667 
668 #include "selftestdialog_p.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon Dec 10 2012 13:48:10 by doxygen 1.8.1.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

akonadi

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

kdepimlibs-4.9.4 API Reference

Skip menu "kdepimlibs-4.9.4 API Reference"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal