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 <tqfile.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 TQString 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 TQString::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 TQString appName = kapp->instanceName(); 00141 if ( appName.isEmpty() ) 00142 appName = "kmail"; 00143 00144 TQString programName; 00145 const KAboutData *about = kapp->aboutData(); 00146 if ( about ) 00147 programName = about->programName(); 00148 if ( programName.isEmpty() ) 00149 programName = i18n("KMail"); 00150 00151 TQString lockLocation = locateLocal("data", "kmail/lock"); 00152 KSimpleConfig config(lockLocation); 00153 int oldPid = config.readNumEntry("pid", -1); 00154 const TQString oldHostName = config.readEntry("hostname"); 00155 const TQString oldAppName = config.readEntry( "appName", appName ); 00156 const TQString oldProgramName = config.readEntry( "programName", programName ); 00157 const TQString 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 TQ_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 TQString procPath = TQString("/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 TQString path = TQFile::decodeName(path_buffer); 00175 kdDebug() << k_funcinfo << path << endl; 00176 const int pos = path.findRev('/'); 00177 const TQString 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 TQString 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 // TQString::arg( st ) only replaces the first occurrence of %1 00204 // with st while TQString::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, TQString(), 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 TQString lockLocation = locateLocal("data", "kmail/lock"); 00265 KSimpleConfig config(lockLocation); 00266 config.writeEntry("pid", -1); 00267 config.sync(); 00268 } 00269 }