kmail

kmstartup.cpp

Go to the documentation of this file.
00001 /*
00002     This file is part of KMail, the KDE mail client.
00003     Copyright (c) 2000 Don Sanders <sanders@kde.org>
00004 
00005     KMail is free software; you can redistribute it and/or modify it
00006     under the terms of the GNU General Public License, version 2, as
00007     published by the Free Software Foundation.
00008 
00009     KMail is distributed in the hope that it will be useful, but
00010     WITHOUT ANY WARRANTY; without even the implied warranty of
00011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012     General Public License for more details.
00013 
00014     You should have received a copy of the GNU General Public License
00015     along with this program; if not, write to the Free Software
00016     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00017 */
00018 
00019 #include <config.h>
00020 
00021 #include "kmstartup.h"
00022 
00023 #include "kmkernel.h" //control center
00024 #include "kcursorsaver.h"
00025 
00026 #include <klocale.h>
00027 #include <ksimpleconfig.h>
00028 #include <kstandarddirs.h>
00029 #include <kmessagebox.h>
00030 #include <dcopclient.h>
00031 #include <kcrash.h>
00032 #include <kglobal.h>
00033 #include <kapplication.h>
00034 #include <kaboutdata.h>
00035 #include <kiconloader.h>
00036 
00037 #include <errno.h>
00038 #include <sys/types.h>
00039 #include <sys/param.h>
00040 #include <signal.h>
00041 #include <stdio.h>
00042 #include <stdlib.h>
00043 #include <unistd.h>
00044 #include <qfile.h>
00045 
00046 #undef Status // stupid X headers
00047 
00048 extern "C" {
00049 
00050 // Crash recovery signal handler
00051 void kmsignalHandler(int sigId)
00052 {
00053   kmsetSignalHandler(SIG_DFL);
00054   fprintf(stderr, "*** KMail got signal %d (Exiting)\n", sigId);
00055   // try to cleanup all windows
00056   if (kmkernel) kmkernel->dumpDeadLetters();
00057   ::exit(-1); //
00058 }
00059 
00060 // Crash recovery signal handler
00061 void kmcrashHandler(int sigId)
00062 {
00063   kmsetSignalHandler(SIG_DFL);
00064   fprintf(stderr, "*** KMail got signal %d (Crashing)\n", sigId);
00065   // try to cleanup all windows
00066   if (kmkernel) kmkernel->dumpDeadLetters();
00067   // Return to DrKonqi.
00068 }
00069 //-----------------------------------------------------------------------------
00070 
00071 
00072 void kmsetSignalHandler(void (*handler)(int))
00073 {
00074   signal(SIGKILL, handler);
00075   signal(SIGTERM, handler);
00076   signal(SIGHUP,  handler);
00077   KCrash::setEmergencySaveFunction(kmcrashHandler);
00078 }
00079 
00080 }
00081 //-----------------------------------------------------------------------------
00082 
00083 namespace {
00084   QString getMyHostName() {
00085     char hostNameC[256];
00086     // null terminate this C string
00087     hostNameC[255] = 0;
00088     // set the string to 0 length if gethostname fails
00089     if(gethostname(hostNameC, 255))
00090       hostNameC[0] = 0;
00091     return QString::fromLocal8Bit(hostNameC);
00092   }
00093 } // anon namespace
00094 
00095 namespace KMail {
00096 
00097 void checkConfigUpdates() {
00098   static const char * const updates[] = {
00099     "9",
00100     "3.1-update-identities",
00101     "3.1-use-identity-uoids",
00102     "3.1-new-mail-notification",
00103     "3.2-update-loop-on-goto-unread-settings",
00104     "3.1.4-dont-use-UOID-0-for-any-identity",
00105     "3.2-misc",
00106     "3.2-moves",
00107     "3.3-use-ID-for-accounts",
00108     "3.3-update-filter-rules",
00109     "3.3-move-identities-to-own-file",
00110     "3.3-aegypten-kpgprc-to-kmailrc",
00111     "3.3-aegypten-kpgprc-to-libkleopatrarc",
00112     "3.3-aegypten-emailidentities-split-sign-encr-keys",
00113     "3.3-misc",
00114     "3.3b1-misc",
00115     "3.4-misc",
00116     "3.4a",
00117     "3.4b",
00118     "3.4.1",
00119     "3.5.4",
00120     "3.5.7-imap-flag-migration"
00121   };
00122   static const int numUpdates = sizeof updates / sizeof *updates;
00123   // Warning: do not remove entries in the above array, or the update-level check below will break
00124 
00125   KConfig * config = KMKernel::config();
00126   KConfigGroup startup( config, "Startup" );
00127   const int configUpdateLevel = startup.readNumEntry( "update-level", 0 );
00128   if ( configUpdateLevel == numUpdates ) // Optimize for the common case that everything is OK
00129     return;
00130 
00131   for ( int i = configUpdateLevel ; i < numUpdates ; ++i ) {
00132     config->checkUpdate( updates[i], "kmail.upd" );
00133   }
00134   startup.writeEntry( "update-level", numUpdates );
00135 }
00136 
00137 void lockOrDie() {
00138 // Check and create a lock file to prevent concurrent access to kmail files
00139   QString appName = kapp->instanceName();
00140   if ( appName.isEmpty() )
00141     appName = "kmail";
00142 
00143   QString programName;
00144   const KAboutData *about = kapp->aboutData();
00145   if ( about )
00146     programName = about->programName();
00147   if ( programName.isEmpty() )
00148     programName = i18n("KMail");
00149 
00150   QString lockLocation = locateLocal("data", "kmail/lock");
00151   KSimpleConfig config(lockLocation);
00152   int oldPid = config.readNumEntry("pid", -1);
00153   const QString oldHostName = config.readEntry("hostname");
00154   const QString oldAppName = config.readEntry( "appName", appName );
00155   const QString oldProgramName = config.readEntry( "programName", programName );
00156   const QString hostName = getMyHostName();
00157   bool first_instance = false;
00158   if ( oldPid == -1 )
00159       first_instance = true;
00160   else if (hostName == oldHostName && oldPid != getpid()) {
00161       // check if the lock file is stale
00162 #ifdef Q_OS_LINUX
00163       if ( ::access("/proc", X_OK ) == 0 ) {
00164           // On linux with /proc we can even check that it's really kmail and not something else
00165           char path_buffer[MAXPATHLEN + 1];
00166           path_buffer[MAXPATHLEN] = 0;
00167           const QString procPath = QString("/proc/%1/exe").arg(oldPid);
00168           const int length = readlink (procPath.latin1(), path_buffer, MAXPATHLEN);
00169           if ( length == -1 ) // not such pid
00170               first_instance = true;
00171           else {
00172               path_buffer[length] = '\0';
00173               const QString path = QFile::decodeName(path_buffer);
00174               kdDebug() << k_funcinfo << path << endl;
00175               const int pos = path.findRev('/');
00176               const QString fileName = path.mid(pos+1);
00177               kdDebug() << "Found process " << oldPid << " running. It's: " << fileName << endl;
00178               first_instance = fileName != "kmail" && fileName != "kontact";
00179           }
00180       } else
00181 #endif
00182       {
00183           // Otherwise we just check if the other pid is currently running.
00184           // Not 100% correct but better safe than sorry.
00185           if ( kill(oldPid, 0) == -1 )
00186               first_instance = ( errno == ESRCH );
00187       }
00188   }
00189 
00190   if ( !first_instance ) {
00191     QString msg;
00192     if ( oldHostName == hostName ) {
00193       // this can only happen if the user is running this application on
00194       // different displays on the same machine. All other cases will be
00195       // taken care of by KUniqueApplication()
00196       if ( oldAppName == appName )
00197         msg = i18n("%1 already seems to be running on another display on "
00198                    "this machine. Running %2 more than once "
00199                    "can cause the loss of mail. You should not start %1 "
00200                    "unless you are sure that it is not already running.")
00201               .arg( programName, programName );
00202               // QString::arg( st ) only replaces the first occurrence of %1
00203               // with st while QString::arg( s1, s2 ) replacess all occurrences
00204               // of %1 with s1 and all occurrences of %2 with s2. So don't
00205               // even think about changing the above to .arg( programName ).
00206       else
00207         msg = i18n("%1 seems to be running on another display on this "
00208                    "machine. Running %1 and %2 at the same "
00209                    "time can cause the loss of mail. You should not start %2 "
00210                    "unless you are sure that %1 is not running.")
00211               .arg( oldProgramName, programName );
00212     }
00213     else {
00214       if ( oldAppName == appName )
00215         msg = i18n("%1 already seems to be running on %2. Running %1 more "
00216                    "than once can cause the loss of mail. You should not "
00217                    "start %1 on this computer unless you are sure that it is "
00218                    "not already running on %2.")
00219               .arg( programName, oldHostName );
00220       else
00221         msg = i18n("%1 seems to be running on %3. Running %1 and %2 at the "
00222                    "same time can cause the loss of mail. You should not "
00223                    "start %2 on this computer unless you are sure that %1 is "
00224                    "not running on %3.")
00225               .arg( oldProgramName, programName, oldHostName );
00226     }
00227 
00228     KCursorSaver idle( KBusyPtr::idle() );
00229     if ( KMessageBox::No ==
00230          KMessageBox::warningYesNo( 0, msg, QString::null,
00231                                     i18n("Start %1").arg( programName ),
00232                                     i18n("Exit") ) ) {
00233       exit(1);
00234     }
00235   }
00236 
00237   config.writeEntry("pid", getpid());
00238   config.writeEntry("hostname", hostName);
00239   config.writeEntry( "appName", appName );
00240   config.writeEntry( "programName", programName );
00241   config.sync();
00242 }
00243 
00244 void insertLibraryCataloguesAndIcons() {
00245   static const char * const catalogues[] = {
00246     "libkdepim",
00247     "libksieve",
00248     "libkleopatra",
00249     "libkmime"
00250   };
00251 
00252   KLocale * l = KGlobal::locale();
00253   KIconLoader * il = KGlobal::iconLoader();
00254   for ( unsigned int i = 0 ; i < sizeof catalogues / sizeof *catalogues ; ++i ) {
00255     l->insertCatalogue( catalogues[i] );
00256     il->addAppDir( catalogues[i] );
00257   }
00258 
00259 }
00260 
00261 void cleanup()
00262 {
00263   const QString lockLocation = locateLocal("data", "kmail/lock");
00264   KSimpleConfig config(lockLocation);
00265   config.writeEntry("pid", -1);
00266   config.sync();
00267 }
00268 }