kmail

kmstartup.cpp
1 /*
2  This file is part of KMail, the KDE mail client.
3  Copyright (c) 2000 Don Sanders <sanders@kde.org>
4 
5  KMail is free software; you can redistribute it and/or modify it
6  under the terms of the GNU General Public License, version 2, as
7  published by the Free Software Foundation.
8 
9  KMail is distributed in the hope that it will be useful, but
10  WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18 
19 #include <config.h>
20 
21 #include "kmstartup.h"
22 
23 #include "kmkernel.h" //control center
24 #include "kcursorsaver.h"
25 
26 #include <tdelocale.h>
27 #include <ksimpleconfig.h>
28 #include <kstandarddirs.h>
29 #include <tdemessagebox.h>
30 #include <dcopclient.h>
31 #include <kcrash.h>
32 #include <tdeglobal.h>
33 #include <tdeapplication.h>
34 #include <tdeaboutdata.h>
35 #include <kiconloader.h>
36 
37 #include <errno.h>
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <signal.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <unistd.h>
44 #include <tqfile.h>
45 
46 #undef Status // stupid X headers
47 
48 extern "C" {
49 
50 // Crash recovery signal handler
51 void kmsignalHandler(int sigId)
52 {
53  kmsetSignalHandler(SIG_DFL);
54  fprintf(stderr, "*** KMail got signal %d (Exiting)\n", sigId);
55  // try to cleanup all windows
56  if (kmkernel) kmkernel->dumpDeadLetters();
57  ::exit(-1); //
58 }
59 
60 // Crash recovery signal handler
61 void kmcrashHandler(int sigId)
62 {
63  kmsetSignalHandler(SIG_DFL);
64  fprintf(stderr, "*** KMail got signal %d (Crashing)\n", sigId);
65  // try to cleanup all windows
66  if (kmkernel) kmkernel->dumpDeadLetters();
67  // Return to DrKonqi.
68 }
69 //-----------------------------------------------------------------------------
70 
71 
72 void kmsetSignalHandler(void (*handler)(int))
73 {
74  signal(SIGKILL, handler);
75  signal(SIGTERM, handler);
76  signal(SIGHUP, handler);
77  TDECrash::setEmergencySaveFunction(kmcrashHandler);
78 }
79 
80 }
81 //-----------------------------------------------------------------------------
82 
83 namespace {
84  TQString getMyHostName() {
85  char hostNameC[256];
86  // null terminate this C string
87  hostNameC[255] = 0;
88  // set the string to 0 length if gethostname fails
89  if(gethostname(hostNameC, 255))
90  hostNameC[0] = 0;
91  return TQString::fromLocal8Bit(hostNameC);
92  }
93 } // anon namespace
94 
95 namespace KMail {
96 
97 void checkConfigUpdates() {
98  static const char * const updates[] = {
99  "9",
100  "3.1-update-identities",
101  "3.1-use-identity-uoids",
102  "3.1-new-mail-notification",
103  "3.2-update-loop-on-goto-unread-settings",
104  "3.1.4-dont-use-UOID-0-for-any-identity",
105  "3.2-misc",
106  "3.2-moves",
107  "3.3-use-ID-for-accounts",
108  "3.3-update-filter-rules",
109  "3.3-move-identities-to-own-file",
110  "3.3-aegypten-kpgprc-to-kmailrc",
111  "3.3-aegypten-kpgprc-to-libkleopatrarc",
112  "3.3-aegypten-emailidentities-split-sign-encr-keys",
113  "3.3-misc",
114  "3.3b1-misc",
115  "3.4-misc",
116  "3.4a",
117  "3.4b",
118  "3.4.1",
119  "3.5-filter-icons",
120  "3.5.4",
121  "3.5.7-imap-flag-migration"
122  };
123  static const int numUpdates = sizeof updates / sizeof *updates;
124  // Warning: do not remove entries in the above array, or the update-level check below will break
125 
126  TDEConfig * config = KMKernel::config();
127  TDEConfigGroup startup( config, "Startup" );
128  const int configUpdateLevel = startup.readNumEntry( "update-level", 0 );
129  if ( configUpdateLevel == numUpdates ) // Optimize for the common case that everything is OK
130  return;
131 
132  for ( int i = configUpdateLevel ; i < numUpdates ; ++i ) {
133  config->checkUpdate( updates[i], "kmail.upd" );
134  }
135  startup.writeEntry( "update-level", numUpdates );
136 }
137 
138 void lockOrDie() {
139 // Check and create a lock file to prevent concurrent access to kmail files
140  TQString appName = kapp->instanceName();
141  if ( appName.isEmpty() )
142  appName = "kmail";
143 
144  TQString programName;
145  const TDEAboutData *about = kapp->aboutData();
146  if ( about )
147  programName = about->programName();
148  if ( programName.isEmpty() )
149  programName = i18n("KMail");
150 
151  TQString lockLocation = locateLocal("data", "kmail/lock");
152  KSimpleConfig config(lockLocation);
153  int oldPid = config.readNumEntry("pid", -1);
154  const TQString oldHostName = config.readEntry("hostname");
155  const TQString oldAppName = config.readEntry( "appName", appName );
156  const TQString oldProgramName = config.readEntry( "programName", programName );
157  const TQString hostName = getMyHostName();
158  bool first_instance = false;
159  if ( oldPid == -1 )
160  first_instance = true;
161  else if (hostName == oldHostName && oldPid != getpid()) {
162  // check if the lock file is stale
163 #ifdef TQ_OS_LINUX
164  if ( ::access("/proc", X_OK ) == 0 ) {
165  // On linux with /proc we can even check that it's really kmail and not something else
166  char path_buffer[MAXPATHLEN + 1];
167  path_buffer[MAXPATHLEN] = 0;
168  const TQString procPath = TQString("/proc/%1/exe").arg(oldPid);
169  const int length = readlink (procPath.latin1(), path_buffer, MAXPATHLEN);
170  if ( length == -1 ) // not such pid
171  first_instance = true;
172  else {
173  path_buffer[length] = '\0';
174  const TQString path = TQFile::decodeName(path_buffer);
175  kdDebug() << k_funcinfo << path << endl;
176  const int pos = path.findRev('/');
177  const TQString fileName = path.mid(pos+1);
178  kdDebug() << "Found process " << oldPid << " running. It's: " << fileName << endl;
179  first_instance = fileName != "kmail" && fileName != "kontact";
180  }
181  } else
182 #endif
183  {
184  // Otherwise we just check if the other pid is currently running.
185  // Not 100% correct but better safe than sorry.
186  if ( kill(oldPid, 0) == -1 )
187  first_instance = ( errno == ESRCH );
188  }
189  }
190 
191  if ( !first_instance ) {
192  TQString msg;
193  if ( oldHostName == hostName ) {
194  // this can only happen if the user is running this application on
195  // different displays on the same machine. All other cases will be
196  // taken care of by TDEUniqueApplication()
197  if ( oldAppName == appName )
198  msg = i18n("%1 already seems to be running on another display on "
199  "this machine. Running %2 more than once "
200  "can cause the loss of mail. You should not start %1 "
201  "unless you are sure that it is not already running.")
202  .arg( programName, programName );
203  // TQString::arg( st ) only replaces the first occurrence of %1
204  // with st while TQString::arg( s1, s2 ) replacess all occurrences
205  // of %1 with s1 and all occurrences of %2 with s2. So don't
206  // even think about changing the above to .arg( programName ).
207  else
208  msg = i18n("%1 seems to be running on another display on this "
209  "machine. Running %1 and %2 at the same "
210  "time can cause the loss of mail. You should not start %2 "
211  "unless you are sure that %1 is not running.")
212  .arg( oldProgramName, programName );
213  }
214  else {
215  if ( oldAppName == appName )
216  msg = i18n("%1 already seems to be running on %2. Running %1 more "
217  "than once can cause the loss of mail. You should not "
218  "start %1 on this computer unless you are sure that it is "
219  "not already running on %2.")
220  .arg( programName, oldHostName );
221  else
222  msg = i18n("%1 seems to be running on %3. Running %1 and %2 at the "
223  "same time can cause the loss of mail. You should not "
224  "start %2 on this computer unless you are sure that %1 is "
225  "not running on %3.")
226  .arg( oldProgramName, programName, oldHostName );
227  }
228 
229  KCursorSaver idle( KBusyPtr::idle() );
230  if ( KMessageBox::No ==
231  KMessageBox::warningYesNo( 0, msg, TQString(),
232  i18n("Start %1").arg( programName ),
233  i18n("Exit") ) ) {
234  exit(1);
235  }
236  }
237 
238  config.writeEntry("pid", getpid());
239  config.writeEntry("hostname", hostName);
240  config.writeEntry( "appName", appName );
241  config.writeEntry( "programName", programName );
242  config.sync();
243 }
244 
245 void insertLibraryCataloguesAndIcons() {
246  static const char * const catalogues[] = {
247  "libtdepim",
248  "libksieve",
249  "libkleopatra",
250  "libkmime"
251  };
252 
253  TDELocale * l = TDEGlobal::locale();
254  TDEIconLoader * il = TDEGlobal::iconLoader();
255  for ( unsigned int i = 0 ; i < sizeof catalogues / sizeof *catalogues ; ++i ) {
256  l->insertCatalogue( catalogues[i] );
257  il->addAppDir( catalogues[i] );
258  }
259 
260 }
261 
262 void cleanup()
263 {
264  const TQString lockLocation = locateLocal("data", "kmail/lock");
265  KSimpleConfig config(lockLocation);
266  config.writeEntry("pid", -1);
267  config.sync();
268 }
269 }
sets a cursor and makes sure it's restored on destruction Create a KCursorSaver object when you want ...
Definition: kcursorsaver.h:14
folderdiaquotatab.h
Definition: aboutdata.cpp:40