kmail

kmstartup.cpp

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-filter-icons",
00120     "3.5.4",
00121     "3.5.7-imap-flag-migration"
00122   };
00123   static const int numUpdates = sizeof updates / sizeof *updates;
00124   // Warning: do not remove entries in the above array, or the update-level check below will break
00125 
00126   KConfig * config = KMKernel::config();
00127   KConfigGroup startup( config, "Startup" );
00128   const int configUpdateLevel = startup.readNumEntry( "update-level", 0 );
00129   if ( configUpdateLevel == numUpdates ) // Optimize for the common case that everything is OK
00130     return;
00131 
00132   for ( int i = configUpdateLevel ; i < numUpdates ; ++i ) {
00133     config->checkUpdate( updates[i], "kmail.upd" );
00134   }
00135   startup.writeEntry( "update-level", numUpdates );
00136 }
00137 
00138 void lockOrDie() {
00139 // Check and create a lock file to prevent concurrent access to kmail files
00140   QString appName = kapp->instanceName();
00141   if ( appName.isEmpty() )
00142     appName = "kmail";
00143 
00144   QString programName;
00145   const KAboutData *about = kapp->aboutData();
00146   if ( about )
00147     programName = about->programName();
00148   if ( programName.isEmpty() )
00149     programName = i18n("KMail");
00150 
00151   QString lockLocation = locateLocal("data", "kmail/lock");
00152   KSimpleConfig config(lockLocation);
00153   int oldPid = config.readNumEntry("pid", -1);
00154   const QString oldHostName = config.readEntry("hostname");
00155   const QString oldAppName = config.readEntry( "appName", appName );
00156   const QString oldProgramName = config.readEntry( "programName", programName );
00157   const QString hostName = getMyHostName();
00158   bool first_instance = false;
00159   if ( oldPid == -1 )
00160       first_instance = true;
00161   else if (hostName == oldHostName && oldPid != getpid()) {
00162       // check if the lock file is stale
00163 #ifdef Q_OS_LINUX
00164       if ( ::access("/proc", X_OK ) == 0 ) {
00165           // On linux with /proc we can even check that it's really kmail and not something else
00166           char path_buffer[MAXPATHLEN + 1];
00167           path_buffer[MAXPATHLEN] = 0;
00168           const QString procPath = QString("/proc/%1/exe").arg(oldPid);
00169           const int length = readlink (procPath.latin1(), path_buffer, MAXPATHLEN);
00170           if ( length == -1 ) // not such pid
00171               first_instance = true;
00172           else {
00173               path_buffer[length] = '\0';
00174               const QString path = QFile::decodeName(path_buffer);
00175               kdDebug() << k_funcinfo << path << endl;
00176               const int pos = path.findRev('/');
00177               const QString fileName = path.mid(pos+1);
00178               kdDebug() << "Found process " << oldPid << " running. It's: " << fileName << endl;
00179               first_instance = fileName != "kmail" && fileName != "kontact";
00180           }
00181       } else
00182 #endif
00183       {
00184           // Otherwise we just check if the other pid is currently running.
00185           // Not 100% correct but better safe than sorry.
00186           if ( kill(oldPid, 0) == -1 )
00187               first_instance = ( errno == ESRCH );
00188       }
00189   }
00190 
00191   if ( !first_instance ) {
00192     QString msg;
00193     if ( oldHostName == hostName ) {
00194       // this can only happen if the user is running this application on
00195       // different displays on the same machine. All other cases will be
00196       // taken care of by KUniqueApplication()
00197       if ( oldAppName == appName )
00198         msg = i18n("%1 already seems to be running on another display on "
00199                    "this machine. Running %2 more than once "
00200                    "can cause the loss of mail. You should not start %1 "
00201                    "unless you are sure that it is not already running.")
00202               .arg( programName, programName );
00203               // QString::arg( st ) only replaces the first occurrence of %1
00204               // with st while QString::arg( s1, s2 ) replacess all occurrences
00205               // of %1 with s1 and all occurrences of %2 with s2. So don't
00206               // even think about changing the above to .arg( programName ).
00207       else
00208         msg = i18n("%1 seems to be running on another display on this "
00209                    "machine. Running %1 and %2 at the same "
00210                    "time can cause the loss of mail. You should not start %2 "
00211                    "unless you are sure that %1 is not running.")
00212               .arg( oldProgramName, programName );
00213     }
00214     else {
00215       if ( oldAppName == appName )
00216         msg = i18n("%1 already seems to be running on %2. Running %1 more "
00217                    "than once can cause the loss of mail. You should not "
00218                    "start %1 on this computer unless you are sure that it is "
00219                    "not already running on %2.")
00220               .arg( programName, oldHostName );
00221       else
00222         msg = i18n("%1 seems to be running on %3. Running %1 and %2 at the "
00223                    "same time can cause the loss of mail. You should not "
00224                    "start %2 on this computer unless you are sure that %1 is "
00225                    "not running on %3.")
00226               .arg( oldProgramName, programName, oldHostName );
00227     }
00228 
00229     KCursorSaver idle( KBusyPtr::idle() );
00230     if ( KMessageBox::No ==
00231          KMessageBox::warningYesNo( 0, msg, QString::null,
00232                                     i18n("Start %1").arg( programName ),
00233                                     i18n("Exit") ) ) {
00234       exit(1);
00235     }
00236   }
00237 
00238   config.writeEntry("pid", getpid());
00239   config.writeEntry("hostname", hostName);
00240   config.writeEntry( "appName", appName );
00241   config.writeEntry( "programName", programName );
00242   config.sync();
00243 }
00244 
00245 void insertLibraryCataloguesAndIcons() {
00246   static const char * const catalogues[] = {
00247     "libkdepim",
00248     "libksieve",
00249     "libkleopatra",
00250     "libkmime"
00251   };
00252 
00253   KLocale * l = KGlobal::locale();
00254   KIconLoader * il = KGlobal::iconLoader();
00255   for ( unsigned int i = 0 ; i < sizeof catalogues / sizeof *catalogues ; ++i ) {
00256     l->insertCatalogue( catalogues[i] );
00257     il->addAppDir( catalogues[i] );
00258   }
00259 
00260 }
00261 
00262 void cleanup()
00263 {
00264   const QString lockLocation = locateLocal("data", "kmail/lock");
00265   KSimpleConfig config(lockLocation);
00266   config.writeEntry("pid", -1);
00267   config.sync();
00268 }
00269 }
KDE Home | KDE Accessibility Home | Description of Access Keys