1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <config_features.h>
21#include <config_folders.h>
22
23#include "sal/config.h"
24
25#include <iostream>
26
27#include "app.hxx"
28#include "desktop.hrc"
29#include "cmdlineargs.hxx"
30#include "cmdlinehelp.hxx"
31#include "dispatchwatcher.hxx"
32#include "configinit.hxx"
33#include "lockfile.hxx"
34#include "userinstall.hxx"
35#include "desktopcontext.hxx"
36#include "exithelper.h"
37#include "migration.hxx"
38
39#include <svl/languageoptions.hxx>
40#include <svtools/javacontext.hxx>
41#include <com/sun/star/beans/XPropertySet.hpp>
42#include <com/sun/star/frame/theAutoRecovery.hpp>
43#include <com/sun/star/frame/theGlobalEventBroadcaster.hpp>
44#include <com/sun/star/frame/SessionListener.hpp>
45#include <com/sun/star/frame/XSessionManagerListener.hpp>
46#include <com/sun/star/frame/XSynchronousDispatch.hpp>
47#include <com/sun/star/document/CorruptedFilterConfigurationException.hpp>
48#include <com/sun/star/configuration/CorruptedConfigurationException.hpp>
49#include <com/sun/star/configuration/theDefaultProvider.hpp>
50#include <com/sun/star/util/XFlushable.hpp>
51#include <com/sun/star/system/SystemShellExecuteFlags.hpp>
52#include <com/sun/star/frame/Desktop.hpp>
53#include <com/sun/star/frame/StartModule.hpp>
54#include <com/sun/star/frame/XComponentLoader.hpp>
55#include <com/sun/star/view/XPrintable.hpp>
56#include <com/sun/star/awt/XTopWindow.hpp>
57#include "com/sun/star/util/URLTransformer.hpp"
58#include <com/sun/star/util/XURLTransformer.hpp>
59#include <com/sun/star/util/XCloseable.hpp>
60#include <com/sun/star/frame/XDispatchProvider.hpp>
61#include <com/sun/star/lang/ServiceNotRegisteredException.hpp>
62#include <com/sun/star/configuration/MissingBootstrapFileException.hpp>
63#include <com/sun/star/configuration/InvalidBootstrapFileException.hpp>
64#include <com/sun/star/configuration/InstallationIncompleteException.hpp>
65#include <com/sun/star/configuration/backend/BackendSetupException.hpp>
66#include <com/sun/star/configuration/backend/BackendAccessException.hpp>
67#include <com/sun/star/task/theJobExecutor.hpp>
68#include <com/sun/star/task/OfficeRestartManager.hpp>
69#include <com/sun/star/task/XRestartManager.hpp>
70#include <com/sun/star/document/XEventListener.hpp>
71#include <com/sun/star/frame/theUICommandDescription.hpp>
72#include <com/sun/star/ui/theUIElementFactoryManager.hpp>
73#include <com/sun/star/ui/theWindowStateConfiguration.hpp>
74#include <com/sun/star/frame/XUIControllerRegistration.hpp>
75#include <com/sun/star/frame/thePopupMenuControllerFactory.hpp>
76#include <com/sun/star/office/Quickstart.hpp>
77
78#include <toolkit/helper/vclunohelper.hxx>
79#include <comphelper/configuration.hxx>
80#include <comphelper/processfactory.hxx>
81#include <unotools/bootstrap.hxx>
82#include <unotools/configmgr.hxx>
83#include <unotools/moduleoptions.hxx>
84#include <officecfg/Office/Common.hxx>
85#include <officecfg/Office/Recovery.hxx>
86#include <officecfg/Setup.hxx>
87#include <osl/file.hxx>
88#include <osl/process.h>
89#include <rtl/uri.hxx>
90#include <unotools/pathoptions.hxx>
91#include <svtools/miscopt.hxx>
92#include <svtools/menuoptions.hxx>
93#include <rtl/bootstrap.hxx>
94#include <vcl/help.hxx>
95#include <vcl/msgbox.hxx>
96#include <sfx2/sfx.hrc>
97#include <sfx2/app.hxx>
98#include <svl/itemset.hxx>
99#include <svl/eitem.hxx>
100
101#include <svtools/fontsubstconfig.hxx>
102#include <svtools/accessibilityoptions.hxx>
103#include <svtools/apearcfg.hxx>
104#include <vcl/graphicfilter.hxx>
105
106#include "langselect.hxx"
107
108#include <config_telepathy.h>
109
110#if ENABLE_TELEPATHY
111#include <tubes/manager.hxx>
112#endif
113
114#if defined MACOSX
115#include <errno.h>
116#include <sys/wait.h>
117#endif
118
119#ifdef WNT
120#ifdef _MSC_VER
121#pragma warning(push, 1) /* disable warnings within system headers */
122#pragma warning (disable: 4005)
123#endif
124#define WIN32_LEAN_AND_MEAN
125#include <windows.h>
126#ifdef _MSC_VER
127#pragma warning(pop)
128#endif
129#endif //WNT
130
131#if defined WNT
132#include <process.h>
133#define GETPID _getpid
134#else
135#include <unistd.h>
136#define GETPID getpid
137#endif
138
139using namespace ::com::sun::star::awt;
140using namespace ::com::sun::star::uno;
141using namespace ::com::sun::star::util;
142using namespace ::com::sun::star::lang;
143using namespace ::com::sun::star::beans;
144using namespace ::com::sun::star::frame;
145using namespace ::com::sun::star::document;
146using namespace ::com::sun::star::view;
147using namespace ::com::sun::star::task;
148using namespace ::com::sun::star::system;
149using namespace ::com::sun::star::ui;
150using namespace ::com::sun::star::ui::dialogs;
151using namespace ::com::sun::star::container;
152
153ResMgr* desktop::Desktop::pResMgr = 0;
154
155namespace desktop
156{
157
158static oslSignalHandler pSignalHandler = 0;
159static sal_Bool _bCrashReporterEnabled = sal_True;
160
161namespace {
162
163void removeTree(OUString const & url) {
164 osl::Directory dir(url);
165 osl::FileBase::RC rc = dir.open();
166 switch (rc) {
167 case osl::FileBase::E_None:
168 break;
169 case osl::FileBase::E_NOENT:
170 return; //TODO: SAL_WARN if recursive
171 default:
172 SAL_WARN("desktop.app", "cannot open directory " << dir.getURL() << ": " << +rc);
173 return;
174 }
175 for (;;) {
176 osl::DirectoryItem i;
177 rc = dir.getNextItem(i, SAL_MAX_UINT32);
178 if (rc == osl::FileBase::E_NOENT) {
179 break;
180 }
181 if (rc != osl::FileBase::E_None) {
182 SAL_WARN( "desktop.app", "cannot iterate directory " << dir.getURL() << ": " << +rc);
183 break;
184 }
185 osl::FileStatus stat(
186 osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName |
187 osl_FileStatus_Mask_FileURL);
188 rc = i.getFileStatus(stat);
189 if (rc != osl::FileBase::E_None) {
190 SAL_WARN( "desktop.app", "cannot stat in directory " << dir.getURL() << ": " << +rc);
191 continue;
192 }
193 if (stat.getFileType() == osl::FileStatus::Directory) { //TODO: symlinks
194 removeTree(stat.getFileURL());
195 } else {
196 rc = osl::File::remove(stat.getFileURL());
197 SAL_WARN_IF(
198 rc != osl::FileBase::E_None, "desktop.app",
199 "cannot remove file " << stat.getFileURL() << ": " << +rc);
200 }
201 }
202 if (dir.isOpen()) {
203 rc = dir.close();
204 SAL_WARN_IF(
205 rc != osl::FileBase::E_None, "desktop.app",
206 "cannot close directory " << dir.getURL() << ": " << +rc);
207 }
208 rc = osl::Directory::remove(url);
209 SAL_WARN_IF(
210 rc != osl::FileBase::E_None, "desktop.app",
211 "cannot remove directory " << url << ": " << +rc);
212}
213
214// Remove any existing UserInstallation's extensions cache data remaining from
215// old installations. This addresses at least two problems:
216//
217// For one, apparently due to the old share/prereg/bundled mechanism (disabled
218// since 5c47e5f63a79a9e72ec4a100786b1bbf65137ed4 "fdo#51252 Disable copying
219// share/prereg/bundled to avoid startup crashes"), the user/extensions/bundled
220// cache could contain corrupted information (like a UNO component registered
221// twice, which got changed from active to passive registration in one LO
222// version, but the version of the corresponding bundled extension only
223// incremented in a later LO version).
224//
225// For another, UserInstallations have been seen in the wild where no extensions
226// were installed per-user (any longer), but user/uno_packages/cache/registry/
227// com.sun.star.comp.deployment.component.PackageRegistryBackend/*.rdb files
228// contained data nevertheless.
229//
230// When a LO upgrade is detected (i.e., no user/extensions/buildid or one
231// containing an old build ID), then user/extensions and
232// user/uno_packages/cache/registry/
233// com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc are
234// removed. That should prevent any problems starting the service manager due
235// to old junk. Later on in Desktop::SynchronizeExtensionRepositories, the
236// removed cache data is recreated.
237//
238// Multiple instances of soffice.bin can execute this code in parallel for a
239// single UserInstallation, as it is called before OfficeIPCThread is set up.
240// Therefore, any errors here only lead to SAL_WARNs.
241//
242// At least in theory, this function could be removed again once no
243// UserInstallation can be poisoned by old junk any more.
244bool cleanExtensionCache() {
245 OUString buildId(
246 "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("version") ":buildid}");
247 rtl::Bootstrap::expandMacros(buildId); //TODO: detect failure
248 OUString extDir(
249 "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap")
250 ":UserInstallation}/user/extensions");
251 rtl::Bootstrap::expandMacros(extDir); //TODO: detect failure
252 OUString buildIdFile(extDir + "/buildid");
253 osl::File fr(buildIdFile);
254 osl::FileBase::RC rc = fr.open(osl_File_OpenFlag_Read);
255 switch (rc) {
256 case osl::FileBase::E_None:
257 {
258 rtl::ByteSequence s1;
259 rc = fr.readLine(s1);
260 osl::FileBase::RC rc2 = fr.close();
261 SAL_WARN_IF(
262 rc2 != osl::FileBase::E_None, "desktop.app",
263 "cannot close " << fr.getURL() << " after reading: " << +rc2);
264 if (rc != osl::FileBase::E_None) {
265 SAL_WARN( "desktop.app", "cannot read from " << fr.getURL() << ": " << +rc);
266 break;
267 }
268 OUString s2(
269 reinterpret_cast< char const * >(s1.getConstArray()),
270 s1.getLength(), RTL_TEXTENCODING_ISO_8859_1);
271 // using ISO 8859-1 avoids any and all conversion errors; the
272 // content should only be a subset of ASCII, anyway
273 if (s2 == buildId) {
274 return false;
275 }
276 break;
277 }
278 case osl::FileBase::E_NOENT:
279 break;
280 default:
281 SAL_WARN( "desktop.app", "cannot open " << fr.getURL() << " for reading: " << +rc);
282 break;
283 }
284 removeTree(extDir);
285 OUString userRcFile(
286 "$UNO_USER_PACKAGES_CACHE/registry/"
287 "com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc");
288 rtl::Bootstrap::expandMacros(userRcFile); //TODO: detect failure
289 rc = osl::File::remove(userRcFile);
290 SAL_WARN_IF(
291 rc != osl::FileBase::E_None && rc != osl::FileBase::E_NOENT, "desktop.app",
292 "cannot remove file " << userRcFile << ": " << +rc);
293 rc = osl::Directory::createPath(extDir);
294 SAL_WARN_IF(
295 rc != osl::FileBase::E_None && rc != osl::FileBase::E_EXIST, "desktop.app",
296 "cannot create path " << extDir << ": " << +rc);
297 osl::File fw(buildIdFile);
298 rc = fw.open(osl_File_OpenFlag_Write | osl_File_OpenFlag_Create);
299 if (rc != osl::FileBase::E_None) {
300 SAL_WARN( "desktop.app", "cannot open " << fw.getURL() << " for writing: " << +rc);
301 return true;
302 }
303 OString buf(OUStringToOString(buildId, RTL_TEXTENCODING_UTF8));
304 // using UTF-8 avoids almost all conversion errors (and buildid
305 // containing single surrogate halves should never happen, anyway); the
306 // content should only be a subset of ASCII, anyway
307 sal_uInt64 n = 0;
308 rc = fw.write(buf.getStr(), buf.getLength(), n);
309 SAL_WARN_IF(
310 (rc != osl::FileBase::E_None
311 || n != static_cast< sal_uInt32 >(buf.getLength())),
312 "desktop.app",
313 "cannot write to " << fw.getURL() << ": " << +rc << ", " << n);
314 rc = fw.close();
315 SAL_WARN_IF(
316 rc != osl::FileBase::E_None, "desktop.app",
317 "cannot close " << fw.getURL() << " after writing: " << +rc);
318 return true;
319}
320
321bool shouldLaunchQuickstart()
322{
323 bool bQuickstart = Desktop::GetCommandLineArgs().IsQuickstart();
324 if (!bQuickstart)
325 {
326 const SfxPoolItem* pItem=0;
327 SfxItemSet aQLSet(SFX_APP()->GetPool(), SID_ATTR_QUICKLAUNCHER, SID_ATTR_QUICKLAUNCHER);
328 SFX_APP()->GetOptions(aQLSet);
329 SfxItemState eState = aQLSet.GetItemState(SID_ATTR_QUICKLAUNCHER, sal_False, &pItem);
330 if (SFX_ITEM_SET == eState)
331 bQuickstart = ((SfxBoolItem*)pItem)->GetValue();
332 }
333 return bQuickstart;
334}
335
336void SetRestartState() {
337 try {
338 boost::shared_ptr< comphelper::ConfigurationChanges > batch(
339 comphelper::ConfigurationChanges::create());
340 officecfg::Setup::Office::OfficeRestartInProgress::set(true, batch);
341 batch->commit();
342 } catch (css::uno::Exception & e) {
343 SAL_WARN("desktop.app", "ignoring Exception \"" << e.Message << "\"");
344 }
345}
346
347void DoRestartActionsIfNecessary(bool quickstart) {
348 if (quickstart) {
349 try {
350 if (officecfg::Setup::Office::OfficeRestartInProgress::get()) {
351 boost::shared_ptr< comphelper::ConfigurationChanges > batch(
352 comphelper::ConfigurationChanges::create());
353 officecfg::Setup::Office::OfficeRestartInProgress::set(
354 false, batch);
355 batch->commit();
356 css::office::Quickstart::createStart(
357 comphelper::getProcessComponentContext(),
358 shouldLaunchQuickstart());
359 }
360 } catch (css::uno::Exception & e) {
361 SAL_WARN(
362 "desktop.app", "ignoring Exception \"" << e.Message << "\"");
363 }
364 }
365}
366
367}
368
369// ----------------------------------------------------------------------------
370
371ResMgr* Desktop::GetDesktopResManager()
372{
373 if ( !Desktop::pResMgr )
374 {
375 // Create desktop resource manager and bootstrap process
376 // was successful. Use default way to get language specific message.
377 if ( Application::IsInExecute() )
378 Desktop::pResMgr = ResMgr::CreateResMgr("dkt");
379
380 if ( !Desktop::pResMgr )
381 {
382 // Use VCL to get the correct language specific message as we
383 // are in the bootstrap process and not able to get the installed
384 // language!!
385 OUString aUILocaleString = langselect::getEmergencyLocale();
386 LanguageTag aLanguageTag( aUILocaleString);
387 //! ResMgr may modify the Locale for fallback!
388 Desktop::pResMgr = ResMgr::SearchCreateResMgr( "dkt", aLanguageTag);
389 AllSettings as = GetSettings();
390 as.SetUILanguageTag(aLanguageTag);
391 SetSettings(as);
392 }
393 }
394
395 return Desktop::pResMgr;
396}
397
398namespace {
399
400// ----------------------------------------------------------------------------
401// Get a message string securely. There is a fallback string if the resource
402// is not available.
403
404OUString GetMsgString(
405 sal_uInt16 nId, const OUString& aFallbackMsg,
406 bool bAlwaysUseFallbackMsg = false )
407{
408 if ( !bAlwaysUseFallbackMsg )
409 {
410 ResMgr* resMgr = Desktop::GetDesktopResManager();
411 if ( resMgr )
412 return ResId(nId, *resMgr).toString();
413 }
414 return aFallbackMsg;
415}
416
417OUString MakeStartupErrorMessage(
418 OUString const & aErrorMessage, bool bAlwaysUseFallbackMsg = false )
419{
420 OUStringBuffer aDiagnosticMessage( 100 );
421
422 aDiagnosticMessage.append(
423 GetMsgString(
424 STR_BOOTSTRAP_ERR_CANNOT_START, "The program cannot be started.",
425 bAlwaysUseFallbackMsg ) );
426
427 aDiagnosticMessage.appendAscii( "\n" );
428
429 aDiagnosticMessage.append( aErrorMessage );
430
431 return aDiagnosticMessage.makeStringAndClear();
432}
433
434OUString MakeStartupConfigAccessErrorMessage( OUString const & aInternalErrMsg )
435{
436 OUStringBuffer aDiagnosticMessage( 200 );
437
438 ResMgr* pResMgr = Desktop::GetDesktopResManager();
439 if ( pResMgr )
440 aDiagnosticMessage.append( ResId(STR_BOOTSTRAP_ERR_CFG_DATAACCESS, *pResMgr).toString() );
441 else
442 aDiagnosticMessage.appendAscii( "The program cannot be started." );
443
444 if ( !aInternalErrMsg.isEmpty() )
445 {
446 aDiagnosticMessage.appendAscii( "\n\n" );
447 if ( pResMgr )
448 aDiagnosticMessage.append( ResId(STR_INTERNAL_ERRMSG, *pResMgr).toString() );
449 else
450 aDiagnosticMessage.appendAscii( "The following internal error has occurred:\n\n" );
451 aDiagnosticMessage.append( aInternalErrMsg );
452 }
453
454 return aDiagnosticMessage.makeStringAndClear();
455}
456
457//=============================================================================
458// shows a simple error box with the given message ... but exits from these process !
459// Fatal errors cant be solved by the process ... nor any recovery can help.
460// Mostly the installation was damaged and must be repaired manually .. or by calling
461// setup again.
462// On the other side we must make sure that no further actions will be possible within
463// the current office process ! No pipe requests, no menu/toolbar/shortuct actions
464// are allowed. Otherwise we will force a "crash inside a crash".
465// Thats why we have to use a special native message box here which does not use yield :-)
466//=============================================================================
467void FatalError(const OUString& sMessage)
468{
469 OUString sProductKey = ::utl::Bootstrap::getProductKey();
470 if ( sProductKey.isEmpty())
471 {
472 osl_getExecutableFile( &sProductKey.pData );
473
474 ::sal_uInt32 nLastIndex = sProductKey.lastIndexOf('/');
475 if ( nLastIndex > 0 )
476 sProductKey = sProductKey.copy( nLastIndex+1 );
477 }
478
479 OUStringBuffer sTitle (128);
480 sTitle.append (sProductKey );
481 sTitle.appendAscii (" - Fatal Error");
482
483 Application::ShowNativeErrorBox (sTitle.makeStringAndClear (), sMessage);
484 _exit(EXITHELPER_FATAL_ERROR);
485}
486
487static bool ShouldSuppressUI(const CommandLineArgs& rCmdLine)
488{
489 return rCmdLine.IsInvisible() ||
490 rCmdLine.IsHeadless() ||
491 rCmdLine.IsQuickstart();
492}
493
494struct theCommandLineArgs : public rtl::Static< CommandLineArgs, theCommandLineArgs > {};
495
496}
497
498CommandLineArgs& Desktop::GetCommandLineArgs()
499{
500 return theCommandLineArgs::get();
501}
502
503namespace
504{
505 struct BrandName
506 : public rtl::Static< OUString, BrandName > {};
507 struct Version
508 : public rtl::Static< OUString, Version > {};
509 struct AboutBoxVersion
510 : public rtl::Static< OUString, AboutBoxVersion > {};
511 struct AboutBoxVersionSuffix
512 : public rtl::Static< OUString, AboutBoxVersionSuffix > {};
513 struct OOOVendor
514 : public rtl::Static< OUString, OOOVendor > {};
515 struct Extension
516 : public rtl::Static< OUString, Extension > {};
517}
518
519OUString ReplaceStringHookProc( const OUString& rStr )
520{
521 OUString sRet(rStr);
522
523 if (sRet.indexOf("%PRODUCT") != -1 || sRet.indexOf("%ABOUTBOX") != -1)
524 {
525 OUString sBrandName = BrandName::get();
526 OUString sVersion = Version::get();
527 OUString sBuildId = utl::Bootstrap::getBuildIdData("development");
528 OUString sAboutBoxVersion = AboutBoxVersion::get();
529 OUString sAboutBoxVersionSuffix = AboutBoxVersionSuffix::get();
530 OUString sExtension = Extension::get();
531
532 if ( sBrandName.isEmpty() )
533 {
534 sBrandName = utl::ConfigManager::getProductName();
535 sVersion = utl::ConfigManager::getProductVersion();
536 sAboutBoxVersion = utl::ConfigManager::getAboutBoxProductVersion();
537 sAboutBoxVersionSuffix = utl::ConfigManager::getAboutBoxProductVersionSuffix();
538 if ( sExtension.isEmpty() )
539 {
540 sExtension = utl::ConfigManager::getProductExtension();
541 }
542 }
543
544 sRet = sRet.replaceAll( "%PRODUCTNAME", sBrandName );
545 sRet = sRet.replaceAll( "%PRODUCTVERSION", sVersion );
546 sRet = sRet.replaceAll( "%BUILDID", sBuildId );
547 sRet = sRet.replaceAll( "%ABOUTBOXPRODUCTVERSIONSUFFIX", sAboutBoxVersionSuffix );
548 sRet = sRet.replaceAll( "%ABOUTBOXPRODUCTVERSION", sAboutBoxVersion );
549 sRet = sRet.replaceAll( "%PRODUCTEXTENSION", sExtension );
550 }
551
552 if ( sRet.indexOf( "%OOOVENDOR" ) != -1 )
553 {
554 OUString sOOOVendor = OOOVendor::get();
555
556 if ( sOOOVendor.isEmpty() )
557 {
558 sOOOVendor = utl::ConfigManager::getVendor();
559 }
560
561 sRet = sRet.replaceAll( "%OOOVENDOR", sOOOVendor );
562 }
563
564 return sRet;
565}
566
567Desktop::Desktop()
568: m_bCleanedExtensionCache( false )
569, m_bServicesRegistered( false )
570, m_aBootstrapError( BE_OK )
571{
572 SAL_INFO( "desktop.app", "desktop (cd100003) ::Desktop::Desktop" );
573}
574
575Desktop::~Desktop()
576{
577#if ENABLE_TELEPATHY
578 TeleManager::finalize();
579#endif
580}
581
582void Desktop::Init()
583{
584 SAL_INFO( "desktop.app", "desktop (cd100003) ::Desktop::Init" );
585 SetBootstrapStatus(BS_OK);
586
587 m_bCleanedExtensionCache = cleanExtensionCache();
588
589 // We need to have service factory before going further, but see fdo#37195.
590 // Doing this will mmap common.rdb, making it not overwritable on windows,
591 // so this can't happen before the synchronization above. Lets rework this
592 // so that the above is called *from* CreateApplicationServiceManager or
593 // something to enforce this gotcha
594 try
595 {
596 InitApplicationServiceManager();
597 }
598 catch (css::uno::Exception & e)
599 {
600 SetBootstrapError( BE_UNO_SERVICEMANAGER, e.Message );
601 }
602
603 if ( m_aBootstrapError == BE_OK )
604 {
605 try
606 {
607 if (!langselect::prepareLocale())
608 {
609 SetBootstrapError( BE_LANGUAGE_MISSING, OUString() );
610 }
611 }
612 catch (css::uno::Exception & e)
613 {
614 SetBootstrapError( BE_OFFICECONFIG_BROKEN, e.Message );
615 }
616 }
617
618 if ( true )
619 {
620 const CommandLineArgs& rCmdLineArgs = GetCommandLineArgs();
621
622 // start ipc thread only for non-remote offices
623 SAL_INFO( "desktop.app", "desktop (cd100003) ::OfficeIPCThread::EnableOfficeIPCThread" );
624 OfficeIPCThread::Status aStatus = OfficeIPCThread::EnableOfficeIPCThread();
625 if ( aStatus == OfficeIPCThread::IPC_STATUS_PIPE_ERROR )
626 {
627#if HAVE_FEATURE_MACOSX_SANDBOX
628 // In a sandboxed LO, on 10.8.2 at least, creating the
629 // Unix domain socket fails. Ignore that as hopefully
630 // people running a sandboxed LO won't attempt starting it
631 // from the command-line or otherwise in tricky ways, so
632 // the normal OS X mechanism that prevents multiple
633 // instances of an app from being started should work
634 // fine. I hope.
635#elif defined ANDROID
636 // Ignore crack pipe errors on Android, too
637#else
638 // Keep using this oddly named BE_PATHINFO_MISSING value
639 // for pipe-related errors on other platforms. Of course
640 // this crack with two (if not more) levels of our own
641 // error codes hiding the actual system error code is
642 // broken, but that is done all over the code, let's leave
643 // re-enginering that to another year.
644 SetBootstrapError( BE_PATHINFO_MISSING, OUString() );
645#endif
646 }
647 else if ( aStatus == OfficeIPCThread::IPC_STATUS_BOOTSTRAP_ERROR )
648 {
649 SetBootstrapError( BE_PATHINFO_MISSING, OUString() );
650 }
651 else if ( aStatus == OfficeIPCThread::IPC_STATUS_2ND_OFFICE )
652 {
653 // 2nd office startup should terminate after sending cmdlineargs through pipe
654 SetBootstrapStatus(BS_TERMINATE);
655 }
656 else if ( !rCmdLineArgs.GetUnknown().isEmpty()
657 || rCmdLineArgs.IsHelp() || rCmdLineArgs.IsVersion() )
658 {
659 // disable IPC thread in an instance that is just showing a help message
660 OfficeIPCThread::DisableOfficeIPCThread();
661 }
662 pSignalHandler = osl_addSignalHandler(SalMainPipeExchangeSignal_impl, NULL);
663 }
664}
665
666void Desktop::InitFinished()
667{
668 SAL_INFO( "desktop.app", "desktop (cd100003) ::Desktop::InitFinished" );
669
670 CloseSplashScreen();
671}
672
673void Desktop::DeInit()
674{
675 SAL_INFO( "desktop.app", "desktop (cd100003) ::Desktop::DeInit" );
676
677 try {
678 // instead of removing of the configManager just let it commit all the changes
679 SAL_INFO( "desktop.app", "<- store config items" );
680 utl::ConfigManager::storeConfigItems();
681 FlushConfiguration();
682 SAL_INFO( "desktop.app", "<- store config items" );
683
684 // close splashscreen if it's still open
685 CloseSplashScreen();
686 Reference< XComponent >(
687 comphelper::getProcessComponentContext(), UNO_QUERY_THROW )->
688 dispose();
689 // nobody should get a destroyed service factory...
690 ::comphelper::setProcessServiceFactory( NULL );
691
692 // clear lockfile
693 m_xLockfile.reset();
694
695 OfficeIPCThread::DisableOfficeIPCThread();
696 if( pSignalHandler )
697 osl_removeSignalHandler( pSignalHandler );
698 } catch (const RuntimeException&) {
699 // someone threw an exception during shutdown
700 // this will leave some garbage behind..
701 }
702
703 SAL_INFO( "desktop.app", "FINISHED WITH Destop::DeInit" );
704}
705
706sal_Bool Desktop::QueryExit()
707{
708 try
709 {
710 SAL_INFO( "desktop.app", "<- store config items" );
711 utl::ConfigManager::storeConfigItems();
712 SAL_INFO( "desktop.app", "<- store config items" );
713 }
714 catch ( const RuntimeException& )
715 {
716 }
717
718 const sal_Char SUSPEND_QUICKSTARTVETO[] = "SuspendQuickstartVeto";
719
720 Reference< XDesktop2 > xDesktop = css::frame::Desktop::create( ::comphelper::getProcessComponentContext() );
721 Reference< XPropertySet > xPropertySet(xDesktop, UNO_QUERY_THROW);
722 xPropertySet->setPropertyValue( OUString(SUSPEND_QUICKSTARTVETO ), Any((sal_Bool)sal_True) );
723
724 sal_Bool bExit = xDesktop->terminate();
725
726 if ( !bExit )
727 {
728 xPropertySet->setPropertyValue( OUString(SUSPEND_QUICKSTARTVETO ), Any((sal_Bool)sal_False) );
729 }
730 else
731 {
732 FlushConfiguration();
733 try
734 {
735 // it is no problem to call DisableOfficeIPCThread() more than once
736 // it also looks to be threadsafe
737 OfficeIPCThread::DisableOfficeIPCThread();
738 }
739 catch ( const RuntimeException& )
740 {
741 }
742
743 m_xLockfile.reset();
744
745 }
746
747 return bExit;
748}
749
750void Desktop::HandleBootstrapPathErrors( ::utl::Bootstrap::Status aBootstrapStatus, const OUString& aDiagnosticMessage )
751{
752 if ( aBootstrapStatus != ::utl::Bootstrap::DATA_OK )
753 {
754 OUString aProductKey;
755 OUString aTemp;
756
757 osl_getExecutableFile( &aProductKey.pData );
758 sal_uInt32 lastIndex = aProductKey.lastIndexOf('/');
759 if ( lastIndex > 0 )
760 aProductKey = aProductKey.copy( lastIndex+1 );
761
762 aTemp = ::utl::Bootstrap::getProductKey( aProductKey );
763 if ( !aTemp.isEmpty() )
764 aProductKey = aTemp;
765
766 OUString const aMessage(aDiagnosticMessage + "\n");
767
768 ErrorBox aBootstrapFailedBox( NULL, WB_OK, aMessage );
769 aBootstrapFailedBox.SetText( aProductKey );
770 aBootstrapFailedBox.Execute();
771 }
772}
773
774// Create a error message depending on bootstrap failure code and an optional file url
775OUString Desktop::CreateErrorMsgString(
776 utl::Bootstrap::FailureCode nFailureCode,
777 const OUString& aFileURL )
778{
779 OUString aMsg;
780 OUString aFilePath;
781 sal_Bool bFileInfo = sal_True;
782
783 switch ( nFailureCode )
784 {
785 /// the shared installation directory could not be located
786 case ::utl::Bootstrap::MISSING_INSTALL_DIRECTORY:
787 {
788 aMsg = GetMsgString( STR_BOOTSTRAP_ERR_PATH_INVALID,
789 OUString( "The installation path is not available." ) );
790 bFileInfo = sal_False;
791 }
792 break;
793
794 /// the bootstrap INI file could not be found or read
795 case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE:
796 {
797 aMsg = GetMsgString( STR_BOOTSTRAP_ERR_FILE_MISSING,
798 OUString( "The configuration file \"$1\" is missing." ) );
799 }
800 break;
801
802 /// the bootstrap INI is missing a required entry
803 /// the bootstrap INI contains invalid data
804 case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE_ENTRY:
805 case ::utl::Bootstrap::INVALID_BOOTSTRAP_FILE_ENTRY:
806 {
807 aMsg = GetMsgString( STR_BOOTSTRAP_ERR_FILE_CORRUPT,
808 OUString( "The configuration file \"$1\" is corrupt." ) );
809 }
810 break;
811
812 /// the version locator INI file could not be found or read
813 case ::utl::Bootstrap::MISSING_VERSION_FILE:
814 {
815 aMsg = GetMsgString( STR_BOOTSTRAP_ERR_FILE_MISSING,
816 OUString( "The configuration file \"$1\" is missing." ) );
817 }
818 break;
819
820 /// the version locator INI has no entry for this version
821 case ::utl::Bootstrap::MISSING_VERSION_FILE_ENTRY:
822 {
823 aMsg = GetMsgString( STR_BOOTSTRAP_ERR_NO_SUPPORT,
824 OUString( "The main configuration file \"$1\" does not support the current version." ) );
825 }
826 break;
827
828 /// the user installation directory does not exist
829 case ::utl::Bootstrap::MISSING_USER_DIRECTORY:
830 {
831 aMsg = GetMsgString( STR_BOOTSTRAP_ERR_DIR_MISSING,
832 OUString( "The configuration directory \"$1\" is missing." ) );
833 }
834 break;
835
836 /// some bootstrap data was invalid in unexpected ways
837 case ::utl::Bootstrap::INVALID_BOOTSTRAP_DATA:
838 {
839 aMsg = GetMsgString( STR_BOOTSTRAP_ERR_INTERNAL,
840 OUString( "An internal failure occurred." ) );
841 bFileInfo = sal_False;
842 }
843 break;
844
845 case ::utl::Bootstrap::INVALID_VERSION_FILE_ENTRY:
846 {
847 // This needs to be improved, see #i67575#:
848 aMsg = "Invalid version file entry";
849 bFileInfo = sal_False;
850 }
851 break;
852
853 case ::utl::Bootstrap::NO_FAILURE:
854 {
855 OSL_ASSERT(false);
856 }
857 break;
858 }
859
860 if ( bFileInfo )
861 {
862 OUString aMsgString( aMsg );
863
864 osl::File::getSystemPathFromFileURL( aFileURL, aFilePath );
865
866 aMsgString = aMsgString.replaceFirst( "$1", aFilePath );
867 aMsg = aMsgString;
868 }
869
870 return MakeStartupErrorMessage( aMsg );
871}
872
873void Desktop::HandleBootstrapErrors(
874 BootstrapError aBootstrapError, OUString const & aErrorMessage )
875{
876 if ( aBootstrapError == BE_PATHINFO_MISSING )
877 {
878 OUString aErrorMsg;
879 OUString aBuffer;
880 utl::Bootstrap::Status aBootstrapStatus;
881 utl::Bootstrap::FailureCode nFailureCode;
882
883 aBootstrapStatus = ::utl::Bootstrap::checkBootstrapStatus( aBuffer, nFailureCode );
884 if ( aBootstrapStatus != ::utl::Bootstrap::DATA_OK )
885 {
886 switch ( nFailureCode )
887 {
888 case ::utl::Bootstrap::MISSING_INSTALL_DIRECTORY:
889 case ::utl::Bootstrap::INVALID_BOOTSTRAP_DATA:
890 {
891 aErrorMsg = CreateErrorMsgString( nFailureCode, OUString() );
892 }
893 break;
894
895 /// the bootstrap INI file could not be found or read
896 /// the bootstrap INI is missing a required entry
897 /// the bootstrap INI contains invalid data
898 case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE_ENTRY:
899 case ::utl::Bootstrap::INVALID_BOOTSTRAP_FILE_ENTRY:
900 case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE:
901 {
902 OUString aBootstrapFileURL;
903
904 utl::Bootstrap::locateBootstrapFile( aBootstrapFileURL );
905 aErrorMsg = CreateErrorMsgString( nFailureCode, aBootstrapFileURL );
906 }
907 break;
908
909 /// the version locator INI file could not be found or read
910 /// the version locator INI has no entry for this version
911 /// the version locator INI entry is not a valid directory URL
912 case ::utl::Bootstrap::INVALID_VERSION_FILE_ENTRY:
913 case ::utl::Bootstrap::MISSING_VERSION_FILE_ENTRY:
914 case ::utl::Bootstrap::MISSING_VERSION_FILE:
915 {
916 OUString aVersionFileURL;
917
918 utl::Bootstrap::locateVersionFile( aVersionFileURL );
919 aErrorMsg = CreateErrorMsgString( nFailureCode, aVersionFileURL );
920 }
921 break;
922
923 /// the user installation directory does not exist
924 case ::utl::Bootstrap::MISSING_USER_DIRECTORY:
925 {
926 OUString aUserInstallationURL;
927
928 utl::Bootstrap::locateUserInstallation( aUserInstallationURL );
929 aErrorMsg = CreateErrorMsgString( nFailureCode, aUserInstallationURL );
930 }
931 break;
932
933 case ::utl::Bootstrap::NO_FAILURE:
934 {
935 OSL_ASSERT(false);
936 }
937 break;
938 }
939
940 HandleBootstrapPathErrors( aBootstrapStatus, aErrorMsg );
941 }
942 }
943 else if ( aBootstrapError == BE_UNO_SERVICEMANAGER || aBootstrapError == BE_UNO_SERVICE_CONFIG_MISSING )
944 {
945 // Uno service manager is not available. VCL needs a uno service manager to display a message box!!!
946 // Currently we are not able to display a message box with a service manager due to this limitations inside VCL.
947
948 // When UNO is not properly initialized, all kinds of things can fail
949 // and cause the process to crash (e.g., a call to GetMsgString may
950 // crash when somewhere deep within that call Any::operator <= is used
951 // with a PropertyValue, and no binary UNO type description for
952 // PropertyValue is available). To give the user a hint even if
953 // generating and displaying a message box below crashes, print a
954 // hard-coded message on stderr first:
955 std::cerr
956 << "The application cannot be started.\n"
957 // STR_BOOTSTRAP_ERR_CANNOT_START
958 << (aBootstrapError == BE_UNO_SERVICEMANAGER
959 ? "The component manager is not available.\n"
960 // STR_BOOTSTRAP_ERR_NO_SERVICE
961 : "The configuration service is not available.\n");
962 // STR_BOOTSTRAP_ERR_NO_CFG_SERVICE
963 if ( !aErrorMessage.isEmpty() )
964 {
965 std::cerr << "(\"" << aErrorMessage << "\")\n";
966 }
967
968 // First sentence. We cannot bootstrap office further!
969 OUString aMessage;
970 OUStringBuffer aDiagnosticMessage( 100 );
971
972 OUString aErrorMsg;
973
974 if ( aBootstrapError == BE_UNO_SERVICEMANAGER )
975 aErrorMsg = "The service manager is not available.";
976 else
977 aErrorMsg = GetMsgString( STR_BOOTSTRAP_ERR_NO_CFG_SERVICE,
978 OUString( "The configuration service is not available." ) );
979
980 aDiagnosticMessage.append( aErrorMsg );
981 aDiagnosticMessage.appendAscii( "\n" );
982 if ( !aErrorMessage.isEmpty() )
983 {
984 aDiagnosticMessage.appendAscii( "(\"" );
985 aDiagnosticMessage.append( aErrorMessage );
986 aDiagnosticMessage.appendAscii( "\")\n" );
987 }
988
989 // Due to the fact the we haven't a backup applicat.rdb file anymore it is not possible to
990 // repair the installation with the setup executable besides the office executable. Now
991 // we have to ask the user to start the setup on CD/installation directory manually!!
992 OUString aStartSetupManually( GetMsgString(
993 STR_ASK_START_SETUP_MANUALLY,
994 OUString( "Start setup application to repair the installation from CD, or the folder containing the installation packages." ),
995 aBootstrapError == BE_UNO_SERVICEMANAGER ) );
996
997 aDiagnosticMessage.append( aStartSetupManually );
998 aMessage = MakeStartupErrorMessage(
999 aDiagnosticMessage.makeStringAndClear(),
1000 aBootstrapError == BE_UNO_SERVICEMANAGER );
1001
1002 FatalError( aMessage);
1003 }
1004 else if ( aBootstrapError == BE_OFFICECONFIG_BROKEN )
1005 {
1006 OUString msg(
1007 GetMsgString(
1008 STR_CONFIG_ERR_ACCESS_GENERAL,
1009 ("A general error occurred while accessing your central"
1010 " configuration.")));
1011 if (!aErrorMessage.isEmpty()) {
1012 msg += "\n(\"" + aErrorMessage + "\")";
1013 }
1014 FatalError(MakeStartupErrorMessage(msg));
1015 }
1016 else if ( aBootstrapError == BE_USERINSTALL_FAILED )
1017 {
1018 OUString aMessage;
1019 OUStringBuffer aDiagnosticMessage( 100 );
1020 OUString aErrorMsg;
1021 aErrorMsg = GetMsgString( STR_BOOTSTRAP_ERR_USERINSTALL_FAILED,
1022 OUString( "User installation could not be completed" ) );
1023 aDiagnosticMessage.append( aErrorMsg );
1024 aMessage = MakeStartupErrorMessage( aDiagnosticMessage.makeStringAndClear() );
1025 FatalError(aMessage);
1026 }
1027 else if ( aBootstrapError == BE_LANGUAGE_MISSING )
1028 {
1029 OUString aMessage;
1030 OUStringBuffer aDiagnosticMessage( 100 );
1031 OUString aErrorMsg;
1032 aErrorMsg = GetMsgString(
1033 //@@@ FIXME: should use an own resource string => #i36213#
1034 STR_BOOTSTRAP_ERR_LANGUAGE_MISSING,
1035 OUString( "Language could not be determined." ) );
1036 aDiagnosticMessage.append( aErrorMsg );
1037 aMessage = MakeStartupErrorMessage(
1038 aDiagnosticMessage.makeStringAndClear() );
1039 FatalError(aMessage);
1040 }
1041 else if (( aBootstrapError == BE_USERINSTALL_NOTENOUGHDISKSPACE ) ||
1042 ( aBootstrapError == BE_USERINSTALL_NOWRITEACCESS ))
1043 {
1044 OUString aUserInstallationURL;
1045 OUString aUserInstallationPath;
1046 OUString aMessage;
1047 OUString aErrorMsg;
1048 OUStringBuffer aDiagnosticMessage( 100 );
1049
1050 utl::Bootstrap::locateUserInstallation( aUserInstallationURL );
1051
1052 if ( aBootstrapError == BE_USERINSTALL_NOTENOUGHDISKSPACE )
1053 aErrorMsg = GetMsgString(
1054 STR_BOOSTRAP_ERR_NOTENOUGHDISKSPACE,
1055 OUString( "User installation could not be completed due to insufficient free disk space." ) );
1056 else
1057 aErrorMsg = GetMsgString(
1058 STR_BOOSTRAP_ERR_NOACCESSRIGHTS,
1059 OUString( "User installation could not be processed due to missing access rights." ) );
1060
1061 osl::File::getSystemPathFromFileURL( aUserInstallationURL, aUserInstallationPath );
1062
1063 aDiagnosticMessage.append( aErrorMsg );
1064 aDiagnosticMessage.append( aUserInstallationPath );
1065 aMessage = MakeStartupErrorMessage(
1066 aDiagnosticMessage.makeStringAndClear() );
1067 FatalError(aMessage);
1068 }
1069
1070 return;
1071}
1072
1073
1074void Desktop::retrieveCrashReporterState()
1075{
1076 _bCrashReporterEnabled
1077 = officecfg::Office::Recovery::CrashReporter::Enabled::get();
1078}
1079
1080sal_Bool Desktop::isUIOnSessionShutdownAllowed()
1081{
1082 return officecfg::Office::Recovery::SessionShutdown::DocumentStoreUIEnabled
1083 ::get();
1084}
1085
1086//-----------------------------------------------
1087/** @short check if crash reporter feature is enabled or
1088 disabled.
1089*/
1090sal_Bool Desktop::isCrashReporterEnabled()
1091{
1092 return _bCrashReporterEnabled;
1093}
1094
1095//-----------------------------------------------
1096/** @short check if recovery must be started or not.
1097
1098 @param bCrashed [boolean ... out!]
1099 the office crashed last times.
1100 But may be there are no recovery data.
1101 Useful to trigger the error report tool without
1102 showing the recovery UI.
1103
1104 @param bRecoveryDataExists [boolean ... out!]
1105 there exists some recovery data.
1106
1107 @param bSessionDataExists [boolean ... out!]
1108 there exists some session data.
1109 Because the user may be logged out last time from it's
1110 unix session...
1111*/
1112void impl_checkRecoveryState(sal_Bool& bCrashed ,
1113 sal_Bool& bRecoveryDataExists,
1114 sal_Bool& bSessionDataExists )
1115{
1116 bCrashed = officecfg::Office::Recovery::RecoveryInfo::Crashed::get();
1117 bool elements = officecfg::Office::Recovery::RecoveryList::get()->
1118 hasElements();
1119 bool session
1120 = officecfg::Office::Recovery::RecoveryInfo::SessionData::get();
1121 bRecoveryDataExists = elements && !session;
1122 bSessionDataExists = elements && session;
1123}
1124
1125//-----------------------------------------------
1126/* @short start the recovery wizard.
1127
1128 @param bEmergencySave
1129 differs between EMERGENCY_SAVE and RECOVERY
1130*/
1131sal_Bool impl_callRecoveryUI(sal_Bool bEmergencySave ,
1132 sal_Bool bCrashed ,
1133 sal_Bool bExistsRecoveryData)
1134{
1135 static OUString SERVICENAME_RECOVERYUI("com.sun.star.comp.svx.RecoveryUI");
1136 static OUString COMMAND_EMERGENCYSAVE("vnd.sun.star.autorecovery:/doEmergencySave");
1137 static OUString COMMAND_RECOVERY("vnd.sun.star.autorecovery:/doAutoRecovery");
1138 static OUString COMMAND_CRASHREPORT("vnd.sun.star.autorecovery:/doCrashReport");
1139
1140 css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
1141
1142 Reference< css::frame::XSynchronousDispatch > xRecoveryUI(
1143 xContext->getServiceManager()->createInstanceWithContext(SERVICENAME_RECOVERYUI, xContext),
1144 css::uno::UNO_QUERY_THROW);
1145
1146 Reference< css::util::XURLTransformer > xURLParser =
1147 css::util::URLTransformer::create(::comphelper::getProcessComponentContext());
1148
1149 css::util::URL aURL;
1150 if (bEmergencySave)
1151 aURL.Complete = COMMAND_EMERGENCYSAVE;
1152 else if (bExistsRecoveryData)
1153 aURL.Complete = COMMAND_RECOVERY;
1154 else if (bCrashed && Desktop::isCrashReporterEnabled() )
1155 aURL.Complete = COMMAND_CRASHREPORT;
1156 else
1157 return false;
1158
1159 xURLParser->parseStrict(aURL);
1160
1161 css::uno::Any aRet = xRecoveryUI->dispatchWithReturnValue(aURL, css::uno::Sequence< css::beans::PropertyValue >());
1162 sal_Bool bRet = sal_False;
1163 aRet >>= bRet;
1164 return !bEmergencySave || bRet;
1165}
1166
1167/*
1168 * Save all open documents so they will be reopened
1169 * the next time the application is started
1170 *
1171 * returns sal_True if at least one document could be saved...
1172 *
1173 */
1174
1175sal_Bool Desktop::SaveTasks()
1176{
1177 return impl_callRecoveryUI(
1178 sal_True , // sal_True => force emergency save
1179 sal_False, // 2. and 3. param not used if 1. = true!
1180 sal_False);
1181}
1182
1183namespace {
1184
1185void restartOnMac(bool passArguments) {
1186#if defined MACOSX
1187 OfficeIPCThread::DisableOfficeIPCThread();
1188#if HAVE_FEATURE_MACOSX_SANDBOX
1189 (void) passArguments; // avoid warnings
1190 ResMgr *resMgr = Desktop::GetDesktopResManager();
1191 OUString aMessage = ResId(STR_LO_MUST_BE_RESTARTED, *resMgr).toString();
1192
1193 ErrorBox aRestartBox( NULL, WB_OK, aMessage );
1194 aRestartBox.Execute();
1195#else
1196 OUString execUrl;
1197 OSL_VERIFY(osl_getExecutableFile(&execUrl.pData) == osl_Process_E_None);
1198 OUString execPath;
1199 OString execPath8;
1200 if ((osl::FileBase::getSystemPathFromFileURL(execUrl, execPath)
1201 != osl::FileBase::E_None) ||
1202 !execPath.convertToString(
1203 &execPath8, osl_getThreadTextEncoding(),
1204 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
1205 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
1206 {
1207 std::abort();
1208 }
1209 std::vector< OString > args;
1210 args.push_back(execPath8);
1211 bool wait = false;
1212 if (passArguments) {
1213 sal_uInt32 n = osl_getCommandArgCount();
1214 for (sal_uInt32 i = 0; i < n; ++i) {
1215 OUString arg;
1216 OSL_VERIFY(osl_getCommandArg(i, &arg.pData) == osl_Process_E_None);
1217 if (arg.match("--accept=")) {
1218 wait = true;
1219 }
1220 OString arg8;
1221 if (!arg.convertToString(
1222 &arg8, osl_getThreadTextEncoding(),
1223 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
1224 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
1225 {
1226 std::abort();
1227 }
1228 args.push_back(arg8);
1229 }
1230 }
1231 std::vector< char const * > argPtrs;
1232 for (std::vector< OString >::iterator i(args.begin()); i != args.end();
1233 ++i)
1234 {
1235 argPtrs.push_back(i->getStr());
1236 }
1237 argPtrs.push_back(0);
1238 execv(execPath8.getStr(), const_cast< char ** >(&argPtrs[0]));
1239 if (errno == ENOTSUP) { // happens when multithreaded on OS X < 10.6
1240 pid_t pid = fork();
1241 if (pid == 0) {
1242 execv(execPath8.getStr(), const_cast< char ** >(&argPtrs[0]));
1243 } else if (pid > 0) {
1244 // Two simultaneously running soffice processes lead to two dock
1245 // icons, so avoid waiting here unless it must be assumed that the
1246 // process invoking soffice itself wants to wait for soffice to
1247 // finish:
1248 if (!wait) {
1249 return;
1250 }
1251 int stat;
1252 if (waitpid(pid, &stat, 0) == pid && WIFEXITED(stat)) {
1253 _exit(WEXITSTATUS(stat));
1254 }
1255 }
1256 }
1257 std::abort();
1258#endif
1259#else
1260 (void) passArguments; // avoid warnings
1261#endif
1262}
1263
1264}
1265
1266sal_uInt16 Desktop::Exception(sal_uInt16 nError)
1267{
1268 // protect against recursive calls
1269 static sal_Bool bInException = sal_False;
1270
1271 sal_uInt16 nOldMode = Application::GetSystemWindowMode();
1272 Application::SetSystemWindowMode( nOldMode & ~SYSTEMWINDOW_MODE_NOAUTOMODE );
1273 Application::SetDefDialogParent( NULL );
1274
1275 if ( bInException )
1276 {
1277 OUString aDoubleExceptionString;
1278 Application::Abort( aDoubleExceptionString );
1279 }
1280
1281 bInException = sal_True;
1282 const CommandLineArgs& rArgs = GetCommandLineArgs();
1283
1284 // save all modified documents ... if it's allowed doing so.
1285 sal_Bool bRestart = sal_False;
1286 sal_Bool bAllowRecoveryAndSessionManagement = (
1287 ( !rArgs.IsNoRestore() ) && // some use cases of office must work without recovery
1288 ( !rArgs.IsHeadless() ) &&
1289 (( nError & EXC_MAJORTYPE ) != EXC_DISPLAY ) && // recovery cant work without UI ... but UI layer seams to be the reason for this crash
1290 ( Application::IsInExecute() ) // crashes during startup and shutdown should be ignored (they indicates a corrupt installation ...)
1291 );
1292 if ( bAllowRecoveryAndSessionManagement )
1293 bRestart = SaveTasks();
1294
1295 FlushConfiguration();
1296
1297 switch( nError & EXC_MAJORTYPE )
1298 {
1299 case EXC_RSCNOTLOADED:
1300 {
1301 OUString aResExceptionString;
1302 Application::Abort( aResExceptionString );
1303 break;
1304 }
1305
1306 default:
1307 {
1308 m_xLockfile.reset();
1309
1310 if( bRestart )
1311 {
1312 OfficeIPCThread::DisableOfficeIPCThread();
1313 if( pSignalHandler )
1314 osl_removeSignalHandler( pSignalHandler );
1315
1316 restartOnMac(false);
1317 if ( m_rSplashScreen.is() )
1318 m_rSplashScreen->reset();
1319
1320 _exit( EXITHELPER_CRASH_WITH_RESTART );
1321 }
1322 else
1323 {
1324 Application::Abort( OUString() );
1325 }
1326
1327 break;
1328 }
1329 }
1330
1331 OSL_ASSERT(false); // unreachable
1332 return 0;
1333}
1334
1335void Desktop::AppEvent( const ApplicationEvent& rAppEvent )
1336{
1337 HandleAppEvent( rAppEvent );
1338}
1339
1340
1341struct ExecuteGlobals
1342{
1343 Reference < css::document::XEventListener > xGlobalBroadcaster;
1344 sal_Bool bRestartRequested;
1345 sal_Bool bUseSystemFileDialog;
1346 std::auto_ptr<SvtLanguageOptions> pLanguageOptions;
1347 std::auto_ptr<SvtPathOptions> pPathOptions;
1348
1349 ExecuteGlobals()
1350 : bRestartRequested( sal_False )
1351 , bUseSystemFileDialog( sal_True )
1352 {}
1353};
1354
1355static ExecuteGlobals* pExecGlobals = NULL;
1356
1357int Desktop::Main()
1358{
1359 pExecGlobals = new ExecuteGlobals();
1360
1361 SAL_INFO( "desktop.app", "desktop (cd100003) ::Desktop::Main" );
1362
1363 // Remember current context object
1364 com::sun::star::uno::ContextLayer layer(
1365 com::sun::star::uno::getCurrentContext() );
1366
1367 if ( m_aBootstrapError != BE_OK )
1368 {
1369 HandleBootstrapErrors( m_aBootstrapError, m_aBootstrapErrorMessage );
1370 return EXIT_FAILURE;
1371 }
1372
1373 BootstrapStatus eStatus = GetBootstrapStatus();
1374 if (eStatus == BS_TERMINATE) {
1375 return EXIT_SUCCESS;
1376 }
1377
1378 // Detect desktop environment - need to do this as early as possible
1379 com::sun::star::uno::setCurrentContext(
1380 new DesktopContext( com::sun::star::uno::getCurrentContext() ) );
1381
1382 CommandLineArgs& rCmdLineArgs = GetCommandLineArgs();
1383
1384#if HAVE_FEATURE_DESKTOP
1385 OUString aUnknown( rCmdLineArgs.GetUnknown() );
1386 if ( !aUnknown.isEmpty() )
1387 {
1388 displayCmdlineHelp( aUnknown );
1389 return EXIT_FAILURE;
1390 }
1391 if ( rCmdLineArgs.IsHelp() )
1392 {
1393 displayCmdlineHelp( OUString() );
1394 return EXIT_SUCCESS;
1395 }
1396 if ( rCmdLineArgs.IsVersion() )
1397 {
1398 displayVersion();
1399 return EXIT_SUCCESS;
1400 }
1401#endif
1402 // setup configuration error handling
1403 ConfigurationErrorHandler aConfigErrHandler;
1404 if (!ShouldSuppressUI(rCmdLineArgs))
1405 aConfigErrHandler.activate();
1406
1407 ResMgr::SetReadStringHook( ReplaceStringHookProc );
1408
1409 // Startup screen
1410 SAL_INFO( "desktop.app", "desktop (lo119109) Desktop::Main { OpenSplashScreen" );
1411 OpenSplashScreen();
1412 SAL_INFO( "desktop.app", "desktop (lo119109) Desktop::Main } OpenSplashScreen" );
1413
1414 SetSplashScreenProgress(10);
1415
1416 userinstall::Status inst_fin = userinstall::finalize();
1417 if (inst_fin != userinstall::EXISTED && inst_fin != userinstall::CREATED)
1418 {
1419 SAL_WARN( "desktop.app", "userinstall failed");
1420 if ( inst_fin == userinstall::ERROR_NO_SPACE )
1421 HandleBootstrapErrors(
1422 BE_USERINSTALL_NOTENOUGHDISKSPACE, OUString() );
1423 else if ( inst_fin == userinstall::ERROR_CANT_WRITE )
1424 HandleBootstrapErrors( BE_USERINSTALL_NOWRITEACCESS, OUString() );
1425 else
1426 HandleBootstrapErrors( BE_USERINSTALL_FAILED, OUString() );
1427 return EXIT_FAILURE;
1428 }
1429 // refresh path information
1430 utl::Bootstrap::reloadData();
1431 SetSplashScreenProgress(20);
1432
1433 Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext();
1434
1435 Reference< XRestartManager > xRestartManager( OfficeRestartManager::get(xContext) );
1436
1437 Reference< XDesktop2 > xDesktop;
1438 try
1439 {
1440 RegisterServices(xContext);
1441
1442 SetSplashScreenProgress(25);
1443
1444 // check user installation directory for lockfile so we can be sure
1445 // there is no other instance using our data files from a remote host
1446 SAL_INFO( "desktop.app", "desktop (lo119109) Desktop::Main -> Lockfile" );
1447 m_xLockfile.reset(new Lockfile);
1448
1449#if HAVE_FEATURE_DESKTOP
1450 if ( !rCmdLineArgs.IsHeadless() && !rCmdLineArgs.IsInvisible() &&
1451 !rCmdLineArgs.IsNoLockcheck() && !m_xLockfile->check( Lockfile_execWarning ))
1452 {
1453 // Lockfile exists, and user clicked 'no'
1454 return EXIT_FAILURE;
1455 }
1456 SAL_INFO( "desktop.app", "desktop (lo119109) Desktop::Main <- Lockfile" );
1457
1458 // check if accessibility is enabled but not working and allow to quit
1459 SAL_INFO( "desktop.app", "{ GetEnableATToolSupport" );
1460 if( Application::GetSettings().GetMiscSettings().GetEnableATToolSupport() )
1461 {
1462 if( !InitAccessBridge() )
1463 return EXIT_FAILURE;
1464 }
1465 SAL_INFO( "desktop.app", "} GetEnableATToolSupport" );
1466#endif
1467
1468 // terminate if requested...
1469 if( rCmdLineArgs.IsTerminateAfterInit() )
1470 return EXIT_SUCCESS;
1471
1472 // Read the common configuration items for optimization purpose
1473 if ( !InitializeConfiguration() )
1474 return EXIT_FAILURE;
1475
1476 SetSplashScreenProgress(30);
1477
1478 // set static variable to enabled/disable crash reporter
1479 retrieveCrashReporterState();
1480 const bool bCrashReporterEnabled = isCrashReporterEnabled();
1481 osl_setErrorReporting( !bCrashReporterEnabled );
1482
1483 // create title string
1484 LanguageTag aLocale( LANGUAGE_SYSTEM);
1485 ResMgr* pLabelResMgr = ResMgr::SearchCreateResMgr( "ofa", aLocale );
1486 OUString aTitle = pLabelResMgr ? ResId(RID_APPTITLE, *pLabelResMgr).toString() : OUString();
1487 delete pLabelResMgr;
1488
1489#ifdef DBG_UTIL
1490 //include buildid in non product builds
1491 OUString aDefault("development");
1492 aTitle += " [";
1493 aTitle += utl::Bootstrap::getBuildIdData(aDefault);
1494 aTitle += "]";
1495#endif
1496
1497 SetDisplayName( aTitle );
1498 SetSplashScreenProgress(35);
1499 SAL_INFO( "desktop.app", "{ create SvtPathOptions and SvtLanguageOptions" );
1500 pExecGlobals->pPathOptions.reset( new SvtPathOptions);
1501 SetSplashScreenProgress(40);
1502 SAL_INFO( "desktop.app", "} create SvtPathOptions and SvtLanguageOptions" );
1503
1504 xDesktop = css::frame::Desktop::create( xContext );
1505
1506 // create service for loadin SFX (still needed in startup)
1507 pExecGlobals->xGlobalBroadcaster = Reference < css::document::XEventListener >
1508 ( css::frame::theGlobalEventBroadcaster::get(xContext), UNO_QUERY_THROW );
1509
1510 /* ensure existance of a default window that messages can be dispatched to
1511 This is for the benefit of testtool which uses PostUserEvent extensively
1512 and else can deadlock while creating this window from another tread while
1513 the main thread is not yet in the event loop.
1514 */
1515 Application::GetDefaultDevice();
1516
1517#if HAVE_FEATURE_EXTENSIONS
1518 // Check if bundled or shared extensions were added /removed
1519 // and process those extensions (has to be done before checking
1520 // the extension dependencies!
1521 SynchronizeExtensionRepositories();
1522 bool bAbort = CheckExtensionDependencies();
1523 if ( bAbort )
1524 return EXIT_FAILURE;
1525
1526 if (inst_fin == userinstall::CREATED)
1527 {
1528 Migration::migrateSettingsIfNecessary();
1529 }
1530#endif
1531
1532 // keep a language options instance...
1533 pExecGlobals->pLanguageOptions.reset( new SvtLanguageOptions(sal_True));
1534
1535 css::document::EventObject aEvent;
1536 aEvent.EventName = "OnStartApp";
1537 pExecGlobals->xGlobalBroadcaster->notifyEvent(aEvent);
1538
1539 SetSplashScreenProgress(50);
1540
1541 // Backing Component
1542 sal_Bool bCrashed = sal_False;
1543 sal_Bool bExistsRecoveryData = sal_False;
1544 sal_Bool bExistsSessionData = sal_False;
1545
1546 SAL_INFO( "desktop.app", "{ impl_checkRecoveryState" );
1547 impl_checkRecoveryState(bCrashed, bExistsRecoveryData, bExistsSessionData);
1548 SAL_INFO( "desktop.app", "} impl_checkRecoveryState" );
1549
1550 OUString pidfileName = rCmdLineArgs.GetPidfileName();
1551 if ( !pidfileName.isEmpty() )
1552 {
1553 OUString pidfileURL;
1554
1555 if ( osl_getFileURLFromSystemPath(pidfileName.pData, &pidfileURL.pData) == osl_File_E_None )
1556 {
1557 osl::File pidfile( pidfileURL );
1558 osl::FileBase::RC rc;
1559
1560 osl::File::remove( pidfileURL );
1561 if ( (rc = pidfile.open( osl_File_OpenFlag_Write | osl_File_OpenFlag_Create ) ) == osl::File::E_None )
1562 {
1563 OString pid( OString::number( GETPID() ) );
1564 sal_uInt64 written = 0;
1565 if ( pidfile.write(pid.getStr(), pid.getLength(), written) != osl::File::E_None )
1566 {
1567 SAL_WARN("desktop.app", "cannot write pidfile " << pidfile.getURL());
1568 }
1569 pidfile.close();
1570 }
1571 else
1572 {
1573 SAL_WARN("desktop.app", "cannot open pidfile " << pidfile.getURL() << osl::FileBase::RC(rc));
1574 }
1575 }
1576 else
1577 {
1578 SAL_WARN("desktop.app", "cannot get pidfile URL from path" << pidfileName);
1579 }
1580 }
1581
1582 if ( rCmdLineArgs.IsHeadless() )
1583 {
1584 // Ensure that we use not the system file dialogs as
1585 // headless mode relies on Application::EnableHeadlessMode()
1586 // which does only work for VCL dialogs!!
1587 SvtMiscOptions aMiscOptions;
1588 pExecGlobals->bUseSystemFileDialog = aMiscOptions.UseSystemFileDialog();
1589 aMiscOptions.SetUseSystemFileDialog( sal_False );
1590 }
1591
1592 pExecGlobals->bRestartRequested = xRestartManager->isRestartRequested(
1593 true);
1594 if ( !pExecGlobals->bRestartRequested )
1595 {
1596 if ((!rCmdLineArgs.WantsToLoadDocument() && !rCmdLineArgs.IsInvisible() && !rCmdLineArgs.IsHeadless() && !rCmdLineArgs.IsQuickstart()) &&
1597 (SvtModuleOptions().IsModuleInstalled(SvtModuleOptions::E_SSTARTMODULE)) &&
1598 (!bExistsRecoveryData ) &&
1599 (!bExistsSessionData ) &&
1600 (!Application::AnyInput( VCL_INPUT_APPEVENT ) ))
1601 {
1602 SAL_INFO( "desktop.app", "{ create BackingComponent" );
1603 ShowBackingComponent(this);
1604 SAL_INFO( "desktop.app", "} create BackingComponent" );
1605 }
1606 }
1607 }
1608 catch ( const com::sun::star::lang::WrappedTargetException& wte )
1609 {
1610 com::sun::star::uno::Exception te;
1611 wte.TargetException >>= te;
1612 FatalError( MakeStartupConfigAccessErrorMessage(wte.Message + te.Message) );
1613 }
1614 catch ( const com::sun::star::uno::Exception& e )
1615 {
1616 FatalError( MakeStartupErrorMessage(e.Message) );
1617 }
1618 SetSplashScreenProgress(55);
1619
1620 SvtFontSubstConfig().Apply();
1621
1622 SvtTabAppearanceCfg aAppearanceCfg;
1623 aAppearanceCfg.SetInitialized();
1624 aAppearanceCfg.SetApplicationDefaults( this );
1625 SvtAccessibilityOptions aOptions;
1626 aOptions.SetVCLSettings();
1627 SetSplashScreenProgress(60);
1628
1629#if ENABLE_TELEPATHY
1630 bool bListen = rCmdLineArgs.IsInvisible();
1631 TeleManager::init( bListen );
1632#endif
1633
1634 if ( !pExecGlobals->bRestartRequested )
1635 {
1636 Application::SetFilterHdl( LINK( this, Desktop, ImplInitFilterHdl ) );
1637 sal_Bool bTerminateRequested = sal_False;
1638
1639 // Preload function depends on an initialized sfx application!
1640 SetSplashScreenProgress(75);
1641
1642 // use system window dialogs
1643 Application::SetSystemWindowMode( SYSTEMWINDOW_MODE_DIALOG );
1644
1645 SetSplashScreenProgress(80);
1646
1647 if ( !bTerminateRequested && !rCmdLineArgs.IsInvisible() &&
1648 !rCmdLineArgs.IsNoQuickstart() )
1649 InitializeQuickstartMode( xContext );
1650
1651 SAL_INFO( "desktop.app", "desktop (cd100003) createInstance com.sun.star.frame.Desktop" );
1652 try
1653 {
1654 if ( xDesktop.is() )
1655 xDesktop->addTerminateListener( new OfficeIPCThreadController );
1656 SetSplashScreenProgress(100);
1657 }
1658 catch ( const com::sun::star::uno::Exception& e )
1659 {
1660 FatalError( MakeStartupErrorMessage(e.Message) );
1661 }
1662
1663 // Release solar mutex just before we wait for our client to connect
1664 int nAcquireCount = Application::ReleaseSolarMutex();
1665
1666 // Post user event to startup first application component window
1667 // We have to send this OpenClients message short before execute() to
1668 // minimize the risk that this message overtakes type detection contruction!!
1669 Application::PostUserEvent( LINK( this, Desktop, OpenClients_Impl ) );
1670
1671 // Post event to enable acceptors
1672 Application::PostUserEvent( LINK( this, Desktop, EnableAcceptors_Impl) );
1673
1674 // The configuration error handler currently is only for startup
1675 aConfigErrHandler.deactivate();
1676
1677 // Acquire solar mutex just before we enter our message loop
1678 if ( nAcquireCount )
1679 Application::AcquireSolarMutex( nAcquireCount );
1680
1681 // call Application::Execute to process messages in vcl message loop
1682 SAL_INFO( "desktop.app", "PERFORMANCE - enter Application::Execute()" );
1683
1684 try
1685 {
1686#if HAVE_FEATURE_JAVA
1687 // The JavaContext contains an interaction handler which is used when
1688 // the creation of a Java Virtual Machine fails
1689 com::sun::star::uno::ContextLayer layer2(
1690 new svt::JavaContext( com::sun::star::uno::getCurrentContext() ) );
1691#endif
1692 // check whether the shutdown is caused by restart just before entering the Execute
1693 pExecGlobals->bRestartRequested = pExecGlobals->bRestartRequested ||
1694 xRestartManager->isRestartRequested(true);
1695
1696 if ( !pExecGlobals->bRestartRequested )
1697 {
1698 // if this run of the office is triggered by restart, some additional actions should be done
1699 DoRestartActionsIfNecessary( !rCmdLineArgs.IsInvisible() && !rCmdLineArgs.IsNoQuickstart() );
1700
1701 Execute();
1702 }
1703 }
1704 catch(const com::sun::star::document::CorruptedFilterConfigurationException& exFilterCfg)
1705 {
1706 OfficeIPCThread::SetDowning();
1707 FatalError( MakeStartupErrorMessage(exFilterCfg.Message) );
1708 }
1709 catch(const com::sun::star::configuration::CorruptedConfigurationException& exAnyCfg)
1710 {
1711 OfficeIPCThread::SetDowning();
1712 FatalError( MakeStartupErrorMessage(exAnyCfg.Message) );
1713 }
1714 catch( const ::com::sun::star::uno::Exception& exUNO)
1715 {
1716 OfficeIPCThread::SetDowning();
1717 FatalError( exUNO.Message);
1718 }
1719 catch( const std::exception& exSTD)
1720 {
1721 OfficeIPCThread::SetDowning();
1722 FatalError( OUString::createFromAscii( exSTD.what()));
1723 }
1724 catch( ...)
1725 {
1726 OfficeIPCThread::SetDowning();
1727 FatalError( OUString( "Caught Unknown Exception: Aborting!"));
1728 }
1729 }
1730 else
1731 {
1732 if (xDesktop.is())
1733 xDesktop->terminate();
1734 }
1735 // CAUTION: you do not necessarily get here e.g. on the Mac.
1736 // please put all deinitialization code into doShutdown
1737 return doShutdown();
1738}
1739
1740int Desktop::doShutdown()
1741{
1742 if( ! pExecGlobals )
1743 return EXIT_SUCCESS;
1744
1745 pExecGlobals->bRestartRequested = pExecGlobals->bRestartRequested ||
1746 OfficeRestartManager::get(comphelper::getProcessComponentContext())->
1747 isRestartRequested(true);
1748 if ( pExecGlobals->bRestartRequested )
1749 SetRestartState();
1750
1751 if (pExecGlobals->xGlobalBroadcaster.is())
1752 {
1753 css::document::EventObject aEvent;
1754 aEvent.EventName = "OnCloseApp";
1755 pExecGlobals->xGlobalBroadcaster->notifyEvent(aEvent);
1756 }
1757
1758 delete pResMgr, pResMgr = NULL;
1759 // Restore old value
1760 const CommandLineArgs& rCmdLineArgs = GetCommandLineArgs();
1761 if ( rCmdLineArgs.IsHeadless() )
1762 SvtMiscOptions().SetUseSystemFileDialog( pExecGlobals->bUseSystemFileDialog );
1763
1764 OUString pidfileName = rCmdLineArgs.GetPidfileName();
1765 if ( !pidfileName.isEmpty() )
1766 {
1767 OUString pidfileURL;
1768
1769 if ( osl_getFileURLFromSystemPath(pidfileName.pData, &pidfileURL.pData) == osl_File_E_None )
1770 {
1771 if ( osl::File::remove( pidfileURL ) != osl::FileBase::E_None )
1772 {
1773 SAL_WARN("desktop.app", "shutdown: cannot remove pidfile " << pidfileURL);
1774 }
1775 }
1776 else
1777 {
1778 SAL_WARN("desktop.app", "shutdown: cannot get pidfile URL from path" << pidfileName);
1779 }
1780 }
1781
1782 // remove temp directory
1783 RemoveTemporaryDirectory();
1784 FlushConfiguration();
1785 // The acceptors in the AcceptorMap must be released (in DeregisterServices)
1786 // with the solar mutex unlocked, to avoid deadlock:
1787 sal_uLong nAcquireCount = Application::ReleaseSolarMutex();
1788 DeregisterServices();
1789 Application::AcquireSolarMutex(nAcquireCount);
1790 // be sure that path/language options gets destroyed before
1791 // UCB is deinitialized
1792 SAL_INFO( "desktop.app", "-> dispose path/language options" );
1793 pExecGlobals->pLanguageOptions.reset( 0 );
1794 pExecGlobals->pPathOptions.reset( 0 );
1795 SAL_INFO( "desktop.app", "<- dispose path/language options" );
1796
1797 sal_Bool bRR = pExecGlobals->bRestartRequested;
1798 delete pExecGlobals, pExecGlobals = NULL;
1799
1800 SAL_INFO( "desktop.app", "FINISHED WITH Destop::Main" );
1801 if ( bRR )
1802 {
1803 restartOnMac(true);
1804 if ( m_rSplashScreen.is() )
1805 m_rSplashScreen->reset();
1806
1807 return EXITHELPER_NORMAL_RESTART;
1808 }
1809 return EXIT_SUCCESS;
1810}
1811
1812IMPL_LINK( Desktop, ImplInitFilterHdl, ConvertData*, pData )
1813{
1814 return GraphicFilter::GetGraphicFilter().GetFilterCallback().Call( pData );
1815}
1816
1817bool Desktop::InitializeConfiguration()
1818{
1819 SAL_INFO( "desktop.app", "desktop (jb99855) ::InitConfiguration" );
1820 try
1821 {
1822 css::configuration::theDefaultProvider::get(
1823 comphelper::getProcessComponentContext() );
1824 return true;
1825 }
1826 catch( ::com::sun::star::lang::ServiceNotRegisteredException & e )
1827 {
1828 this->HandleBootstrapErrors(
1829 Desktop::BE_UNO_SERVICE_CONFIG_MISSING, e.Message );
1830 }
1831 catch( const ::com::sun::star::configuration::MissingBootstrapFileException& e )
1832 {
1833 OUString aMsg( CreateErrorMsgString( utl::Bootstrap::MISSING_BOOTSTRAP_FILE,
1834 e.BootstrapFileURL ));
1835 HandleBootstrapPathErrors( ::utl::Bootstrap::INVALID_USER_INSTALL, aMsg );
1836 }
1837 catch( const ::com::sun::star::configuration::InvalidBootstrapFileException& e )
1838 {
1839 OUString aMsg( CreateErrorMsgString( utl::Bootstrap::INVALID_BOOTSTRAP_FILE_ENTRY,
1840 e.BootstrapFileURL ));
1841 HandleBootstrapPathErrors( ::utl::Bootstrap::INVALID_BASE_INSTALL, aMsg );
1842 }
1843 catch( const ::com::sun::star::configuration::InstallationIncompleteException& )
1844 {
1845 OUString aVersionFileURL;
1846 OUString aMsg;
1847 utl::Bootstrap::PathStatus aPathStatus = utl::Bootstrap::locateVersionFile( aVersionFileURL );
1848 if ( aPathStatus == utl::Bootstrap::PATH_EXISTS )
1849 aMsg = CreateErrorMsgString( utl::Bootstrap::MISSING_VERSION_FILE_ENTRY, aVersionFileURL );
1850 else
1851 aMsg = CreateErrorMsgString( utl::Bootstrap::MISSING_VERSION_FILE, aVersionFileURL );
1852
1853 HandleBootstrapPathErrors( ::utl::Bootstrap::MISSING_USER_INSTALL, aMsg );
1854 }
1855 catch ( const com::sun::star::configuration::backend::BackendAccessException& exception)
1856 {
1857 // [cm122549] It is assumed in this case that the message
1858 // coming from InitConfiguration (in fact CreateApplicationConf...)
1859 // is suitable for display directly.
1860 FatalError( MakeStartupErrorMessage( exception.Message ) );
1861 }
1862 catch ( const com::sun::star::configuration::backend::BackendSetupException& exception)
1863 {
1864 // [cm122549] It is assumed in this case that the message
1865 // coming from InitConfiguration (in fact CreateApplicationConf...)
1866 // is suitable for display directly.
1867 FatalError( MakeStartupErrorMessage( exception.Message ) );
1868 }
1869 catch ( const ::com::sun::star::configuration::CannotLoadConfigurationException& )
1870 {
1871 OUString aMsg( CreateErrorMsgString( utl::Bootstrap::INVALID_BOOTSTRAP_DATA,
1872 OUString() ));
1873 HandleBootstrapPathErrors( ::utl::Bootstrap::INVALID_BASE_INSTALL, aMsg );
1874 }
1875 catch( const ::com::sun::star::uno::Exception& )
1876 {
1877 OUString aMsg( CreateErrorMsgString( utl::Bootstrap::INVALID_BOOTSTRAP_DATA,
1878 OUString() ));
1879 HandleBootstrapPathErrors( ::utl::Bootstrap::INVALID_BASE_INSTALL, aMsg );
1880 }
1881 return false;
1882}
1883
1884void Desktop::FlushConfiguration()
1885{
1886 css::uno::Reference< css::util::XFlushable >(
1887 css::configuration::theDefaultProvider::get(
1888 comphelper::getProcessComponentContext()),
1889 css::uno::UNO_QUERY_THROW)->flush();
1890}
1891
1892sal_Bool Desktop::InitializeQuickstartMode( const Reference< XComponentContext >& rxContext )
1893{
1894 try
1895 {
1896 // the shutdown icon sits in the systray and allows the user to keep
1897 // the office instance running for quicker restart
1898 // this will only be activated if --quickstart was specified on cmdline
1899 SAL_INFO( "desktop.app", "desktop (cd100003) createInstance com.sun.star.office.Quickstart" );
1900
1901 sal_Bool bQuickstart = shouldLaunchQuickstart();
1902
1903 // Try to instantiate quickstart service. This service is not mandatory, so
1904 // do nothing if service is not available
1905
1906 // #i105753# the following if was invented for performance
1907 // unfortunately this broke the Mac behavior which is to always run
1908 // in quickstart mode since Mac applications do not usually quit
1909 // when the last document closes.
1910 // Note that this claim that on OS X we "always run in quickstart mode"
1911 // has nothing to do with (quick) *starting* (i.e. starting automatically
1912 // when the user logs in), though, but with not quitting when no documents
1913 // are open.
1914 #ifndef MACOSX
1915 if ( bQuickstart )
1916 #endif
1917 {
1918 css::office::Quickstart::createStart(rxContext, bQuickstart);
1919 }
1920 return sal_True;
1921 }
1922 catch( const ::com::sun::star::uno::Exception& )
1923 {
1924 return sal_False;
1925 }
1926}
1927
1928void Desktop::OverrideSystemSettings( AllSettings& rSettings )
1929{
1930 if ( !SvtTabAppearanceCfg::IsInitialized () )
1931 return;
1932
1933 StyleSettings hStyleSettings = rSettings.GetStyleSettings();
1934 MouseSettings hMouseSettings = rSettings.GetMouseSettings();
1935
1936 sal_uInt32 nDragFullOptions = hStyleSettings.GetDragFullOptions();
1937
1938 SvtTabAppearanceCfg aAppearanceCfg;
1939 sal_uInt16 nDragMode = aAppearanceCfg.GetDragMode();
1940 switch ( nDragMode )
1941 {
1942 case DragFullWindow:
1943 nDragFullOptions |= DRAGFULL_OPTION_ALL;
1944 break;
1945 case DragFrame:
1946 nDragFullOptions &= ((sal_uInt32)~DRAGFULL_OPTION_ALL);
1947 break;
1948 case DragSystemDep:
1949 default:
1950 break;
1951 }
1952
1953 sal_uInt32 nFollow = hMouseSettings.GetFollow();
1954 hMouseSettings.SetFollow( aAppearanceCfg.IsMenuMouseFollow() ? (nFollow|MOUSE_FOLLOW_MENU) : (nFollow&~MOUSE_FOLLOW_MENU));
1955 rSettings.SetMouseSettings(hMouseSettings);
1956
1957 SvtMenuOptions aMenuOpt;
1958 hStyleSettings.SetUseImagesInMenus(aMenuOpt.GetMenuIconsState());
1959 hStyleSettings.SetDragFullOptions( nDragFullOptions );
1960 rSettings.SetStyleSettings ( hStyleSettings );
1961}
1962
1963// ========================================================================
1964IMPL_LINK_NOARG(Desktop, AsyncInitFirstRun)
1965{
1966 DoFirstRunInitializations();
1967 return 0L;
1968}
1969
1970// ========================================================================
1971
1972class ExitTimer : public Timer
1973{
1974 public:
1975 ExitTimer()
1976 {
1977 SetTimeout(500);
1978 Start();
1979 }
1980 virtual void Timeout()
1981 {
1982 exit(42);
1983 }
1984};
1985
1986IMPL_LINK_NOARG(Desktop, OpenClients_Impl)
1987{
1988 SAL_INFO( "desktop.app", "PERFORMANCE - DesktopOpenClients_Impl()" );
1989
1990 try {
1991 OpenClients();
1992
1993 OfficeIPCThread::SetReady();
1994
1995 CloseSplashScreen();
1996 CheckFirstRun( );
1997 EnableOleAutomation();
1998
1999 if (getenv ("OOO_EXIT_POST_STARTUP"))
2000 new ExitTimer();
2001 } catch (const ::com::sun::star::uno::Exception &e) {
2002 OUString a( "UNO exception during client open:\n" );
2003 Application::Abort( a + e.Message );
2004 }
2005 return 0;
2006}
2007
2008// enable acceptos
2009IMPL_LINK_NOARG(Desktop, EnableAcceptors_Impl)
2010{
2011 enableAcceptors();
2012 return 0;
2013}
2014
2015
2016// Registers a COM class factory of the service manager with the windows operating system.
2017void Desktop::EnableOleAutomation()
2018{
2019 SAL_INFO( "desktop.app", "desktop (jl97489) ::Desktop::EnableOleAutomation" );
2020#ifdef WNT
2021 Reference< XMultiServiceFactory > xSMgr= comphelper::getProcessServiceFactory();
2022 xSMgr->createInstance("com.sun.star.bridge.OleApplicationRegistration");
2023 xSMgr->createInstance("com.sun.star.comp.ole.EmbedServer");
2024#endif
2025}
2026
2027void Desktop::PreloadModuleData( const CommandLineArgs& rArgs )
2028{
2029 Sequence < com::sun::star::beans::PropertyValue > args(1);
2030 args[0].Name = "Hidden";
2031 args[0].Value <<= sal_True;
2032 Reference < XDesktop2 > xDesktop = css::frame::Desktop::create( ::comphelper::getProcessComponentContext() );
2033
2034 if ( rArgs.IsWriter() )
2035 {
2036 try
2037 {
2038 Reference < ::com::sun::star::util::XCloseable > xDoc( xDesktop->loadComponentFromURL( OUString("private:factory/swriter"),
2039 OUString("_blank"), 0, args ), UNO_QUERY_THROW );
2040 xDoc->close( sal_False );
2041 }
2042 catch ( const com::sun::star::uno::Exception& )
2043 {
2044 }
2045 }
2046 if ( rArgs.IsCalc() )
2047 {
2048 try
2049 {
2050 Reference < ::com::sun::star::util::XCloseable > xDoc( xDesktop->loadComponentFromURL( OUString("private:factory/scalc"),
2051 OUString("_blank"), 0, args ), UNO_QUERY_THROW );
2052 xDoc->close( sal_False );
2053 }
2054 catch ( const com::sun::star::uno::Exception& )
2055 {
2056 }
2057 }
2058 if ( rArgs.IsDraw() )
2059 {
2060 try
2061 {
2062 Reference < ::com::sun::star::util::XCloseable > xDoc( xDesktop->loadComponentFromURL( OUString("private:factory/sdraw"),
2063 OUString("_blank"), 0, args ), UNO_QUERY_THROW );
2064 xDoc->close( sal_False );
2065 }
2066 catch ( const com::sun::star::uno::Exception& )
2067 {
2068 }
2069 }
2070 if ( rArgs.IsImpress() )
2071 {
2072 try
2073 {
2074 Reference < ::com::sun::star::util::XCloseable > xDoc( xDesktop->loadComponentFromURL( OUString("private:factory/simpress"),
2075 OUString("_blank"), 0, args ), UNO_QUERY_THROW );
2076 xDoc->close( sal_False );
2077 }
2078 catch ( const com::sun::star::uno::Exception& )
2079 {
2080 }
2081 }
2082}
2083
2084void Desktop::PreloadConfigurationData()
2085{
2086 Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext();
2087 Reference< XNameAccess > xNameAccess = css::frame::theUICommandDescription::get(xContext);
2088
2089 OUString aWriterDoc( "com.sun.star.text.TextDocument" );
2090 OUString aCalcDoc( "com.sun.star.sheet.SpreadsheetDocument" );
2091 OUString aDrawDoc( "com.sun.star.drawing.DrawingDocument" );
2092 OUString aImpressDoc( "com.sun.star.presentation.PresentationDocument" );
2093
2094 // preload commands configuration
2095 Any a;
2096 Reference< XNameAccess > xCmdAccess;
2097
2098 try
2099 {
2100 a = xNameAccess->getByName( aWriterDoc );
2101 a >>= xCmdAccess;
2102 if ( xCmdAccess.is() )
2103 {
2104 xCmdAccess->getByName(".uno:BasicShapes");
2105 xCmdAccess->getByName(".uno:EditGlossary");
2106 }
2107 }
2108 catch ( const ::com::sun::star::uno::Exception& )
2109 {
2110 }
2111
2112 try
2113 {
2114 a = xNameAccess->getByName( aCalcDoc );
2115 a >>= xCmdAccess;
2116 if ( xCmdAccess.is() )
2117 xCmdAccess->getByName(".uno:InsertObjectStarMath");
2118 }
2119 catch ( const ::com::sun::star::uno::Exception& )
2120 {
2121 }
2122
2123 try
2124 {
2125 // draw and impress share the same configuration file (DrawImpressCommands.xcu)
2126 a = xNameAccess->getByName( aDrawDoc );
2127 a >>= xCmdAccess;
2128 if ( xCmdAccess.is() )
2129 xCmdAccess->getByName(".uno:Polygon");
2130 }
2131 catch ( const ::com::sun::star::uno::Exception& )
2132 {
2133 }
2134
2135 // preload window state configuration
2136 xNameAccess = theWindowStateConfiguration::get( xContext );
2137 Reference< XNameAccess > xWindowAccess;
2138 try
2139 {
2140 a = xNameAccess->getByName( aWriterDoc );
2141 a >>= xWindowAccess;
2142 if ( xWindowAccess.is() )
2143 xWindowAccess->getByName("private:resource/toolbar/standardbar");
2144 }
2145 catch ( const ::com::sun::star::uno::Exception& )
2146 {
2147 }
2148 try
2149 {
2150 a = xNameAccess->getByName( aCalcDoc );
2151 a >>= xWindowAccess;
2152 if ( xWindowAccess.is() )
2153 xWindowAccess->getByName("private:resource/toolbar/standardbar");
2154 }
2155 catch ( const ::com::sun::star::uno::Exception& )
2156 {
2157 }
2158 try
2159 {
2160 a = xNameAccess->getByName( aDrawDoc );
2161 a >>= xWindowAccess;
2162 if ( xWindowAccess.is() )
2163 xWindowAccess->getByName("private:resource/toolbar/standardbar");
2164 }
2165 catch ( const ::com::sun::star::uno::Exception& )
2166 {
2167 }
2168 try
2169 {
2170 a = xNameAccess->getByName( aImpressDoc );
2171 a >>= xWindowAccess;
2172 if ( xWindowAccess.is() )
2173 xWindowAccess->getByName("private:resource/toolbar/standardbar");
2174 }
2175 catch ( const ::com::sun::star::uno::Exception& )
2176 {
2177 }
2178
2179 // preload user interface element factories
2180 Sequence< Sequence< css::beans::PropertyValue > > aSeqSeqPropValue;
2181 Reference< XUIElementFactoryManager > xUIElementFactory = theUIElementFactoryManager::get( xContext );
2182 try
2183 {
2184 aSeqSeqPropValue = xUIElementFactory->getRegisteredFactories();
2185 }
2186 catch ( const ::com::sun::star::uno::Exception& )
2187 {
2188 }
2189
2190 // preload popup menu controller factories. As all controllers are in the same
2191 // configuration file they also get preloaded!
2192
2193 Reference< css::frame::XUIControllerRegistration > xPopupMenuControllerFactory =
2194 css::frame::thePopupMenuControllerFactory::get( xContext );
2195 try
2196 {
2197 xPopupMenuControllerFactory->hasController(
2198 OUString( ".uno:CharFontName" ),
2199 OUString() );
2200 }
2201 catch ( const ::com::sun::star::uno::Exception& )
2202 {
2203 }
2204
2205 // preload filter configuration
2206 Sequence< OUString > aSeq;
2207 xNameAccess = Reference< XNameAccess >(
2208 xContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.FilterFactory", xContext),
2209 UNO_QUERY );
2210 if ( xNameAccess.is() )
2211 {
2212 try
2213 {
2214 aSeq = xNameAccess->getElementNames();
2215 }
2216 catch ( const ::com::sun::star::uno::Exception& )
2217 {
2218 }
2219 }
2220
2221 // preload type detection configuration
2222 xNameAccess = Reference< XNameAccess >(
2223 xContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.TypeDetection", xContext),
2224 UNO_QUERY );
2225 if ( xNameAccess.is() )
2226 {
2227 try
2228 {
2229 aSeq = xNameAccess->getElementNames();
2230 }
2231 catch ( const ::com::sun::star::uno::Exception& )
2232 {
2233 }
2234 }
2235}
2236
2237void Desktop::OpenClients()
2238{
2239
2240 // check if a document has been recovered - if there is one of if a document was loaded by cmdline, no default document
2241 // should be created
2242 Reference < XComponent > xFirst;
2243 bool bRecovery = false;
2244
2245 const CommandLineArgs& rArgs = GetCommandLineArgs();
2246
2247 if (!rArgs.IsQuickstart())
2248 {
2249 sal_Bool bShowHelp = sal_False;
2250 OUStringBuffer aHelpURLBuffer;
2251 if (rArgs.IsHelpWriter()) {
2252 bShowHelp = sal_True;
2253 aHelpURLBuffer.appendAscii("vnd.sun.star.help://swriter/start");
2254 } else if (rArgs.IsHelpCalc()) {
2255 bShowHelp = sal_True;
2256 aHelpURLBuffer.appendAscii("vnd.sun.star.help://scalc/start");
2257 } else if (rArgs.IsHelpDraw()) {
2258 bShowHelp = sal_True;
2259 aHelpURLBuffer.appendAscii("vnd.sun.star.help://sdraw/start");
2260 } else if (rArgs.IsHelpImpress()) {
2261 bShowHelp = sal_True;
2262 aHelpURLBuffer.appendAscii("vnd.sun.star.help://simpress/start");
2263 } else if (rArgs.IsHelpBase()) {
2264 bShowHelp = sal_True;
2265 aHelpURLBuffer.appendAscii("vnd.sun.star.help://sdatabase/start");
2266 } else if (rArgs.IsHelpBasic()) {
2267 bShowHelp = sal_True;
2268 aHelpURLBuffer.appendAscii("vnd.sun.star.help://sbasic/start");
2269 } else if (rArgs.IsHelpMath()) {
2270 bShowHelp = sal_True;
2271 aHelpURLBuffer.appendAscii("vnd.sun.star.help://smath/start");
2272 }
2273 if (bShowHelp) {
2274 aHelpURLBuffer.appendAscii("?Language=");
2275 aHelpURLBuffer.append(utl::ConfigManager::getLocale());
2276#if defined UNX
2277 aHelpURLBuffer.appendAscii("&System=UNX");
2278#elif defined WNT
2279 aHelpURLBuffer.appendAscii("&System=WIN");
2280#endif
2281 Application::GetHelp()->Start(
2282 aHelpURLBuffer.makeStringAndClear(), NULL);
2283 return;
2284 }
2285 }
2286 else
2287 {
2288 OUString aIniName;
2289
2290 osl_getExecutableFile( &aIniName.pData );
2291 sal_uInt32 lastIndex = aIniName.lastIndexOf('/');
2292 if ( lastIndex > 0 )
2293 {
2294 aIniName = aIniName.copy( 0, lastIndex+1 );
2295 aIniName += "perftune";
2296#if defined(WNT)
2297 aIniName += ".ini";
2298#else
2299 aIniName += "rc";
2300#endif
2301 }
2302
2303 rtl::Bootstrap aPerfTuneIniFile( aIniName );
2304
2305 OUString aDefault( "0" );
2306 OUString aPreloadData;
2307
2308 aPerfTuneIniFile.getFrom( OUString( "QuickstartPreloadConfiguration" ), aPreloadData, aDefault );
2309 if ( aPreloadData == "1" )
2310 {
2311 if ( rArgs.IsWriter() ||
2312 rArgs.IsCalc() ||
2313 rArgs.IsDraw() ||
2314 rArgs.IsImpress() )
2315 {
2316 PreloadModuleData( rArgs );
2317 }
2318
2319 PreloadConfigurationData();
2320 }
2321 }
2322
2323 // Disable AutoSave feature in case "--norestore" or a similar command line switch is set on the command line.
2324 // The reason behind: AutoSave/EmergencySave/AutoRecovery share the same data.
2325 // But the require that all documents, which are saved as backup should exists inside
2326 // memory. May be this mechanism will be inconsistent if the configuration exists ...
2327 // but no document inside memory corrspond to this data.
2328 // Furter it's not acceptable to recover such documents without any UI. It can
2329 // need some time, where the user wont see any results and wait for finishing the office startup ...
2330 sal_Bool bAllowRecoveryAndSessionManagement = (
2331 ( !rArgs.IsNoRestore() ) &&
2332 ( !rArgs.IsHeadless() )
2333 );
2334
2335 if ( ! bAllowRecoveryAndSessionManagement )
2336 {
2337 try
2338 {
2339 Reference< XDispatch > xRecovery = css::frame::theAutoRecovery::get( ::comphelper::getProcessComponentContext() );
2340 Reference< css::util::XURLTransformer > xParser = css::util::URLTransformer::create( ::comphelper::getProcessComponentContext() );
2341
2342 css::util::URL aCmd;
2343 aCmd.Complete = "vnd.sun.star.autorecovery:/disableRecovery";
2344 xParser->parseStrict(aCmd);
2345
2346 xRecovery->dispatch(aCmd, css::uno::Sequence< css::beans::PropertyValue >());
2347 }
2348 catch(const css::uno::Exception& e)
2349 {
2350 SAL_WARN( "desktop.app", "Could not disable AutoRecovery." << e.Message);
2351 }
2352 }
2353 else
2354 {
2355 sal_Bool bCrashed = sal_False;
2356 sal_Bool bExistsRecoveryData = sal_False;
2357 sal_Bool bExistsSessionData = sal_False;
2358
2359 impl_checkRecoveryState(bCrashed, bExistsRecoveryData, bExistsSessionData);
2360
2361 if ( !getenv ("OOO_DISABLE_RECOVERY") &&
2362 (
2363 ( bExistsRecoveryData ) || // => crash with files => recovery
2364 ( bCrashed ) // => crash without files => error report
2365 )
2366 )
2367 {
2368 try
2369 {
2370 bRecovery = impl_callRecoveryUI(
2371 sal_False , // false => force recovery instead of emergency save
2372 bCrashed ,
2373 bExistsRecoveryData);
2374 }
2375 catch(const css::uno::Exception& e)
2376 {
2377 SAL_WARN( "desktop.app", "Error during recovery" << e.Message);
2378 }
2379 }
2380
2381 Reference< XSessionManagerListener2 > xSessionListener;
2382 try
2383 {
2384 // specifies whether the UI-interaction on Session shutdown is allowed
2385 sal_Bool bAllowUI = isUIOnSessionShutdownAllowed();
2386
2387 xSessionListener = SessionListener::createWithOnQuitFlag(::comphelper::getProcessComponentContext(), bAllowUI);
2388
2389// css::beans::NamedValue aProperty( OUString( "AllowUserInteractionOnQuit" ),
2390 // css::uno::makeAny( bAllowUI ) );
2391 // css::uno::Sequence< css::uno::Any > aArgs( 1 );
2392 // aArgs[0] <<= aProperty;
2393
2394 // xSessionListener->initialize( aArgs );
2395 }
2396 catch(const com::sun::star::uno::Exception& e)
2397 {
2398 SAL_WARN( "desktop.app", "Registration of session listener failed" << e.Message);
2399 }
2400
2401 if ( !bExistsRecoveryData )
2402 {
2403 // session management
2404 try
2405 {
2406 xSessionListener->doRestore();
2407 }
2408 catch(const com::sun::star::uno::Exception& e)
2409 {
2410 SAL_WARN( "desktop.app", "Error in session management" << e.Message);
2411 }
2412 }
2413 }
2414
2415 OfficeIPCThread::EnableRequests();
2416
2417 ProcessDocumentsRequest aRequest(rArgs.getCwdUrl());
2418 aRequest.pcProcessed = NULL;
2419
2420 aRequest.aOpenList = rArgs.GetOpenList();
2421 aRequest.aViewList = rArgs.GetViewList();
2422 aRequest.aStartList = rArgs.GetStartList();
2423 aRequest.aPrintList = rArgs.GetPrintList();
2424 aRequest.aPrintToList = rArgs.GetPrintToList();
2425 aRequest.aPrinterName = rArgs.GetPrinterName();
2426 aRequest.aForceOpenList = rArgs.GetForceOpenList();
2427 aRequest.aForceNewList = rArgs.GetForceNewList();
2428 aRequest.aConversionList = rArgs.GetConversionList();
2429 aRequest.aConversionParams = rArgs.GetConversionParams();
2430 aRequest.aConversionOut = rArgs.GetConversionOut();
2431 aRequest.aInFilter = rArgs.GetInFilter();
2432
2433 if ( !aRequest.aOpenList.empty() ||
2434 !aRequest.aViewList.empty() ||
2435 !aRequest.aStartList.empty() ||
2436 !aRequest.aPrintList.empty() ||
2437 !aRequest.aForceOpenList.empty() ||
2438 !aRequest.aForceNewList.empty() ||
2439 ( !aRequest.aPrintToList.empty() && !aRequest.aPrinterName.isEmpty() ) ||
2440 !aRequest.aConversionList.empty() )
2441 {
2442 if ( rArgs.HasModuleParam() )
2443 {
2444 SvtModuleOptions aOpt;
2445
2446 // Support command line parameters to start a module (as preselection)
2447 if ( rArgs.IsWriter() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SWRITER ) )
2448 aRequest.aModule = aOpt.GetFactoryName( SvtModuleOptions::E_WRITER );
2449 else if ( rArgs.IsCalc() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SCALC ) )
2450 aRequest.aModule = aOpt.GetFactoryName( SvtModuleOptions::E_CALC );
2451 else if ( rArgs.IsImpress() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SIMPRESS ) )
2452 aRequest.aModule= aOpt.GetFactoryName( SvtModuleOptions::E_IMPRESS );
2453 else if ( rArgs.IsDraw() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SDRAW ) )
2454 aRequest.aModule= aOpt.GetFactoryName( SvtModuleOptions::E_DRAW );
2455 }
2456
2457 // check for printing disabled
2458 if( ( !(aRequest.aPrintList.empty() && aRequest.aPrintToList.empty()) )
2459 && Application::GetSettings().GetMiscSettings().GetDisablePrinting() )
2460 {
2461 aRequest.aPrintList.clear();
2462 aRequest.aPrintToList.clear();
2463 ResMgr* pDtResMgr = GetDesktopResManager();
2464 if( pDtResMgr )
2465 {
2466 ErrorBox aBox( NULL, ResId( EBX_ERR_PRINTDISABLED, *pDtResMgr ) );
2467 aBox.Execute();
2468 }
2469 }
2470
2471 // Process request
2472 if ( OfficeIPCThread::ExecuteCmdLineRequests( aRequest ) )
2473 {
2474 // Don't do anything if we have successfully called terminate at desktop:
2475 return;
2476 }
2477 }
2478
2479 // no default document if a document was loaded by recovery or by command line or if soffice is used as server
2480 Reference< XDesktop2 > xDesktop = css::frame::Desktop::create( ::comphelper::getProcessComponentContext() );
2481 Reference< XElementAccess > xList( xDesktop->getFrames(), UNO_QUERY_THROW );
2482 if ( xList->hasElements() )
2483 return;
2484
2485 if ( rArgs.IsQuickstart() || rArgs.IsInvisible() || Application::AnyInput( VCL_INPUT_APPEVENT ) )
2486 // soffice was started as tray icon ...
2487 return;
2488
2489 if ( bRecovery )
2490 {
2491 ShowBackingComponent(0);
2492 }
2493 else
2494 {
2495 OpenDefault();
2496 }
2497}
2498
2499void Desktop::OpenDefault()
2500{
2501
2502 SAL_INFO( "desktop.app", "desktop (cd100003) ::Desktop::OpenDefault" );
2503
2504 OUString aName;
2505 SvtModuleOptions aOpt;
2506
2507 const CommandLineArgs& rArgs = GetCommandLineArgs();
2508 if ( rArgs.IsNoDefault() ) return;
2509 if ( rArgs.HasModuleParam() )
2510 {
2511 // Support new command line parameters to start a module
2512 if ( rArgs.IsWriter() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SWRITER ) )
2513 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_WRITER );
2514 else if ( rArgs.IsCalc() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SCALC ) )
2515 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_CALC );
2516 else if ( rArgs.IsImpress() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SIMPRESS ) )
2517 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_IMPRESS );
2518 else if ( rArgs.IsBase() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SDATABASE ) )
2519 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_DATABASE );
2520 else if ( rArgs.IsDraw() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SDRAW ) )
2521 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_DRAW );
2522 else if ( rArgs.IsMath() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SMATH ) )
2523 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_MATH );
2524 else if ( rArgs.IsGlobal() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SWRITER ) )
2525 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_WRITERGLOBAL );
2526 else if ( rArgs.IsWeb() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SWRITER ) )
2527 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_WRITERWEB );
2528 }
2529
2530 if ( aName.isEmpty() )
2531 {
2532 // Old way to create a default document
2533 if ( aOpt.IsModuleInstalled( SvtModuleOptions::E_SWRITER ) )
2534 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_WRITER );
2535 else if ( aOpt.IsModuleInstalled( SvtModuleOptions::E_SCALC ) )
2536 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_CALC );
2537 else if ( aOpt.IsModuleInstalled( SvtModuleOptions::E_SIMPRESS ) )
2538 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_IMPRESS );
2539 else if ( aOpt.IsModuleInstalled( SvtModuleOptions::E_SDATABASE ) )
2540 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_DATABASE );
2541 else if ( aOpt.IsModuleInstalled( SvtModuleOptions::E_SDRAW ) )
2542 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_DRAW );
2543 else
2544 return;
2545 }
2546
2547 ProcessDocumentsRequest aRequest(rArgs.getCwdUrl());
2548 aRequest.pcProcessed = NULL;
2549 aRequest.aOpenList.push_back(aName);
2550 OfficeIPCThread::ExecuteCmdLineRequests( aRequest );
2551}
2552
2553
2554OUString GetURL_Impl(
2555 const OUString& rName, boost::optional< OUString > const & cwdUrl )
2556{
2557 // if rName is a vnd.sun.star.script URL do not attempt to parse it
2558 // as INetURLObj does not handle handle there URLs
2559 if (rName.startsWith("vnd.sun.star.script"))
2560 {
2561 return rName;
2562 }
2563
2564 // dont touch file urls, those should already be in internal form
2565 // they won't get better here (#112849#)
2566 if (rName.startsWith("file:"))
2567 {
2568 return rName;
2569 }
2570
2571 if ( rName.startsWith("service:"))
2572 {
2573 return rName;
2574 }
2575
2576 // Add path separator to these directory and make given URL (rName) absolute by using of current working directory
2577 // Attention: "setFinalSlash()" is necessary for calling "smartRel2Abs()"!!!
2578 // Otherwhise last part will be ignored and wrong result will be returned!!!
2579 // "smartRel2Abs()" interpret given URL as file not as path. So he truncate last element to get the base path ...
2580 // But if we add a separator - he doesn't do it anymore.
2581 INetURLObject aObj;
2582 if (cwdUrl) {
2583 aObj.SetURL(*cwdUrl);
2584 aObj.setFinalSlash();
2585 }
2586
2587 // Use the provided parameters for smartRel2Abs to support the usage of '%' in system paths.
2588 // Otherwise this char won't get encoded and we are not able to load such files later,
2589 bool bWasAbsolute;
2590 INetURLObject aURL = aObj.smartRel2Abs( rName, bWasAbsolute, false, INetURLObject::WAS_ENCODED,
2591 RTL_TEXTENCODING_UTF8, true );
2592 OUString aFileURL = aURL.GetMainURL(INetURLObject::NO_DECODE);
2593
2594 ::osl::FileStatus aStatus( osl_FileStatus_Mask_FileURL );
2595 ::osl::DirectoryItem aItem;
2596 if( ::osl::FileBase::E_None == ::osl::DirectoryItem::get( aFileURL, aItem ) &&
2597 ::osl::FileBase::E_None == aItem.getFileStatus( aStatus ) )
2598 aFileURL = aStatus.getFileURL();
2599
2600 return aFileURL;
2601}
2602
2603void Desktop::HandleAppEvent( const ApplicationEvent& rAppEvent )
2604{
2605 switch ( rAppEvent.GetEvent() )
2606 {
2607 case ApplicationEvent::TYPE_ACCEPT:
2608 // every time an accept parameter is used we create an acceptor
2609 // with the corresponding accept-string
2610 createAcceptor(rAppEvent.GetStringData());
2611 break;
2612 case ApplicationEvent::TYPE_APPEAR:
2613 if ( !GetCommandLineArgs().IsInvisible() )
2614 {
2615 Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
2616
2617 // find active task - the active task is always a visible task
2618 Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create( xContext );
2619 Reference< css::frame::XFrame > xTask = xDesktop->getActiveFrame();
2620 if ( !xTask.is() )
2621 {
2622 // get any task if there is no active one
2623 Reference< css::container::XIndexAccess > xList( xDesktop->getFrames(), ::com::sun::star::uno::UNO_QUERY );
2624 if ( xList->getCount() > 0 )
2625 xList->getByIndex(0) >>= xTask;
2626 }
2627
2628 if ( xTask.is() )
2629 {
2630 Reference< com::sun::star::awt::XTopWindow > xTop( xTask->getContainerWindow(), UNO_QUERY );
2631 xTop->toFront();
2632 }
2633 else
2634 {
2635 // no visible task that could be activated found
2636 Reference< ::com::sun::star::awt::XWindow > xContainerWindow;
2637 Reference< XFrame > xBackingFrame = xDesktop->findFrame(OUString( "_blank" ), 0);
2638 if (xBackingFrame.is())
2639 xContainerWindow = xBackingFrame->getContainerWindow();
2640 if (xContainerWindow.is())
2641 {
2642 Reference< XController > xStartModule = StartModule::createWithParentWindow(xContext, xContainerWindow);
2643 Reference< ::com::sun::star::awt::XWindow > xBackingWin(xStartModule, UNO_QUERY);
2644 // Attention: You MUST(!) call setComponent() before you call attachFrame().
2645 // Because the backing component set the property "IsBackingMode" of the frame
2646 // to true inside attachFrame(). But setComponent() reset this state every time ...
2647 xBackingFrame->setComponent(xBackingWin, xStartModule);
2648 xStartModule->attachFrame(xBackingFrame);
2649 xContainerWindow->setVisible(sal_True);
2650
2651 Window* pCompWindow = VCLUnoHelper::GetWindow(xBackingFrame->getComponentWindow());
2652 if (pCompWindow)
2653 pCompWindow->Update();
2654 }
2655 }
2656 }
2657 break;
2658 case ApplicationEvent::TYPE_HELP:
2659 displayCmdlineHelp(rAppEvent.GetStringData());
2660 break;
2661 case ApplicationEvent::TYPE_VERSION:
2662 displayVersion();
2663 break;
2664 case ApplicationEvent::TYPE_OPEN:
2665 {
2666 const CommandLineArgs& rCmdLine = GetCommandLineArgs();
2667 if ( !rCmdLine.IsInvisible() && !rCmdLine.IsTerminateAfterInit() )
2668 {
2669 ProcessDocumentsRequest* pDocsRequest = new ProcessDocumentsRequest(
2670 rCmdLine.getCwdUrl());
2671 std::vector<OUString> const & data(rAppEvent.GetStringsData());
2672 pDocsRequest->aOpenList.insert(
2673 pDocsRequest->aOpenList.end(), data.begin(), data.end());
2674 pDocsRequest->pcProcessed = NULL;
2675
2676 OfficeIPCThread::ExecuteCmdLineRequests( *pDocsRequest );
2677 delete pDocsRequest;
2678 }
2679 }
2680 break;
2681 case ApplicationEvent::TYPE_OPENHELPURL:
2682 // start help for a specific URL
2683 Application::GetHelp()->Start(rAppEvent.GetStringData(), NULL);
2684 break;
2685 case ApplicationEvent::TYPE_PRINT:
2686 {
2687 const CommandLineArgs& rCmdLine = GetCommandLineArgs();
2688 if ( !rCmdLine.IsInvisible() && !rCmdLine.IsTerminateAfterInit() )
2689 {
2690 ProcessDocumentsRequest* pDocsRequest = new ProcessDocumentsRequest(
2691 rCmdLine.getCwdUrl());
2692 std::vector<OUString> const & data(rAppEvent.GetStringsData());
2693 pDocsRequest->aPrintList.insert(
2694 pDocsRequest->aPrintList.end(), data.begin(), data.end());
2695 pDocsRequest->pcProcessed = NULL;
2696
2697 OfficeIPCThread::ExecuteCmdLineRequests( *pDocsRequest );
2698 delete pDocsRequest;
2699 }
2700 }
2701 break;
2702 case ApplicationEvent::TYPE_PRIVATE_DOSHUTDOWN:
2703 {
2704 Desktop* pD = dynamic_cast<Desktop*>(GetpApp());
2705 OSL_ENSURE( pD, "no desktop ?!?" );
2706 if( pD )
2707 pD->doShutdown();
2708 }
2709 break;
2710 case ApplicationEvent::TYPE_QUICKSTART:
2711 if ( !GetCommandLineArgs().IsInvisible() )
2712 {
2713 // If the office has been started the second time its command line arguments are sent through a pipe
2714 // connection to the first office. We want to reuse the quickstart option for the first office.
2715 // NOTICE: The quickstart service must be initialized inside the "main thread", so we use the
2716 // application events to do this (they are executed inside main thread)!!!
2717 // Don't start quickstart service if the user specified "--invisible" on the command line!
2718 Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
2719 css::office::Quickstart::createStart(xContext, true/*Quickstart*/);
2720 }
2721 break;
2722 case ApplicationEvent::TYPE_SHOWDIALOG:
2723 // ignore all errors here. It's clicking a menu entry only ...
2724 // The user will try it again, in case nothing happens .-)
2725 try
2726 {
2727 Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
2728
2729 Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create( xContext );
2730
2731 Reference< css::util::XURLTransformer > xParser = css::util::URLTransformer::create(xContext);
2732 css::util::URL aCommand;
2733 if( rAppEvent.GetStringData() == "PREFERENCES" )
2734 aCommand.Complete = ".uno:OptionsTreeDialog";
2735 else if( rAppEvent.GetStringData() == "ABOUT" )
2736 aCommand.Complete = ".uno:About";
2737 if( !aCommand.Complete.isEmpty() )
2738 {
2739 xParser->parseStrict(aCommand);
2740
2741 css::uno::Reference< css::frame::XDispatch > xDispatch = xDesktop->queryDispatch(aCommand, OUString(), 0);
2742 if (xDispatch.is())
2743 xDispatch->dispatch(aCommand, css::uno::Sequence< css::beans::PropertyValue >());
2744 }
2745 }
2746 catch(const css::uno::Exception&)
2747 {}
2748 break;
2749 case ApplicationEvent::TYPE_UNACCEPT:
2750 // try to remove corresponding acceptor
2751 destroyAcceptor(rAppEvent.GetStringData());
2752 break;
2753 default:
2754 SAL_WARN( "desktop.app", "this cannot happen");
2755 break;
2756 }
2757}
2758
2759void Desktop::OpenSplashScreen()
2760{
2761 const CommandLineArgs &rCmdLine = GetCommandLineArgs();
2762 sal_Bool bVisible = sal_False;
2763 // Show intro only if this is normal start (e.g. no server, no quickstart, no printing )
2764 if ( !rCmdLine.IsInvisible() &&
2765 !rCmdLine.IsHeadless() &&
2766 !rCmdLine.IsQuickstart() &&
2767 !rCmdLine.IsMinimized() &&
2768 !rCmdLine.IsNoLogo() &&
2769 !rCmdLine.IsTerminateAfterInit() &&
2770 rCmdLine.GetPrintList().empty() &&
2771 rCmdLine.GetPrintToList().empty() &&
2772 rCmdLine.GetConversionList().empty() )
2773 {
2774 // Determine application name from command line parameters
2775 OUString aAppName;
2776 if ( rCmdLine.IsWriter() )
2777 aAppName = "writer";
2778 else if ( rCmdLine.IsCalc() )
2779 aAppName = "calc";
2780 else if ( rCmdLine.IsDraw() )
2781 aAppName = "draw";
2782 else if ( rCmdLine.IsImpress() )
2783 aAppName = "impress";
2784 else if ( rCmdLine.IsBase() )
2785 aAppName = "base";
2786 else if ( rCmdLine.IsGlobal() )
2787 aAppName = "global";
2788 else if ( rCmdLine.IsMath() )
2789 aAppName = "math";
2790 else if ( rCmdLine.IsWeb() )
2791 aAppName = "web";
2792
2793 // Which splash to use
2794 OUString aSplashService( "com.sun.star.office.SplashScreen" );
2795 if ( rCmdLine.HasSplashPipe() )
2796 aSplashService = "com.sun.star.office.PipeSplashScreen";
2797
2798 bVisible = sal_True;
2799 Sequence< Any > aSeq( 2 );
2800 aSeq[0] <<= bVisible;
2801 aSeq[1] <<= aAppName;
2802 css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
2803 m_rSplashScreen = Reference<XStatusIndicator>(
2804 xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aSplashService, aSeq, xContext),
2805 UNO_QUERY);
2806
2807 if(m_rSplashScreen.is())
2808 m_rSplashScreen->start(OUString("SplashScreen"), 100);
2809 }
2810
2811}
2812
2813void Desktop::SetSplashScreenProgress(sal_Int32 iProgress)
2814{
2815 if(m_rSplashScreen.is())
2816 {
2817 m_rSplashScreen->setValue(iProgress);
2818 }
2819}
2820
2821void Desktop::SetSplashScreenText( const OUString& rText )
2822{
2823 if( m_rSplashScreen.is() )
2824 {
2825 m_rSplashScreen->setText( rText );
2826 }
2827}
2828
2829void Desktop::CloseSplashScreen()
2830{
2831 if(m_rSplashScreen.is())
2832 {
2833 m_rSplashScreen->end();
2834 m_rSplashScreen = NULL;
2835 }
2836}
2837
2838// ========================================================================
2839void Desktop::DoFirstRunInitializations()
2840{
2841 try
2842 {
2843 Reference< XJobExecutor > xExecutor = theJobExecutor::get( ::comphelper::getProcessComponentContext() );
2844 xExecutor->trigger( OUString("onFirstRunInitialization") );
2845 }
2846 catch(const ::com::sun::star::uno::Exception&)
2847 {
2848 SAL_WARN( "desktop.app", "Desktop::DoFirstRunInitializations: caught an exception while trigger job executor ..." );
2849 }
2850}
2851
2852void Desktop::ShowBackingComponent(Desktop * progress)
2853{
2854 if (GetCommandLineArgs().IsNoDefault())
2855 {
2856 return;
2857 }
2858 Reference< XComponentContext > xContext = comphelper::getProcessComponentContext();
2859 Reference< XDesktop2 > xDesktop = css::frame::Desktop::create(xContext);
2860 if (progress != 0)
2861 {
2862 progress->SetSplashScreenProgress(60);
2863 }
2864 Reference< XFrame > xBackingFrame = xDesktop->findFrame(OUString( "_blank" ), 0);
2865 Reference< ::com::sun::star::awt::XWindow > xContainerWindow;
2866
2867 if (xBackingFrame.is())
2868 xContainerWindow = xBackingFrame->getContainerWindow();
2869 if (xContainerWindow.is())
2870 {
2871 // set the WB_EXT_DOCUMENT style. Normally, this is done by the TaskCreator service when a "_blank"
2872 // frame/window is created. Since we do not use the TaskCreator here, we need to mimic its behavior,
2873 // otherwise documents loaded into this frame will later on miss functionality depending on the style.
2874 Window* pContainerWindow = VCLUnoHelper::GetWindow( xContainerWindow );
2875 SAL_WARN_IF( !pContainerWindow, "desktop.app", "Desktop::Main: no implementation access to the frame's container window!" );
2876 pContainerWindow->SetExtendedStyle( pContainerWindow->GetExtendedStyle() | WB_EXT_DOCUMENT );
2877 if (progress != 0)
2878 {
2879 progress->SetSplashScreenProgress(75);
2880 }
2881
2882 Reference< XController > xStartModule = StartModule::createWithParentWindow( xContext, xContainerWindow);
2883 // Attention: You MUST(!) call setComponent() before you call attachFrame().
2884 // Because the backing component set the property "IsBackingMode" of the frame
2885 // to true inside attachFrame(). But setComponent() reset this state everytimes ...
2886 xBackingFrame->setComponent(Reference< XWindow >(xStartModule, UNO_QUERY), xStartModule);
2887 if (progress != 0)
2888 {
2889 progress->SetSplashScreenProgress(100);
2890 }
2891 xStartModule->attachFrame(xBackingFrame);
2892 if (progress != 0)
2893 {
2894 progress->CloseSplashScreen();
2895 }
2896 xContainerWindow->setVisible(sal_True);
2897 }
2898}
2899
2900// ========================================================================
2901void Desktop::CheckFirstRun( )
2902{
2903 if (officecfg::Office::Common::Misc::FirstRun::get())
2904 {
2905 // this has once been done using a vos timer. this could lead to problems when
2906 // the timer would trigger when the app is already going down again, since VCL would
2907 // no longer be available. Since the old handler would do a postUserEvent to the main
2908 // thread anyway, we can use a vcl timer here to prevent the race contition (#107197#)
2909 m_firstRunTimer.SetTimeout(3000); // 3 sec.
2910 m_firstRunTimer.SetTimeoutHdl(LINK(this, Desktop, AsyncInitFirstRun));
2911 m_firstRunTimer.Start();
2912
2913#ifdef WNT
2914 // Check if Quckstarter should be started (on Windows only)
2915 TCHAR szValue[8192];
2916 DWORD nValueSize = sizeof(szValue);
2917 HKEY hKey;
2918 if ( ERROR_SUCCESS == RegOpenKey( HKEY_LOCAL_MACHINE, "Software\\LibreOffice", &hKey ) )
2919 {
2920 if ( ERROR_SUCCESS == RegQueryValueEx( hKey, TEXT("RunQuickstartAtFirstStart"), NULL, NULL, (LPBYTE)szValue, &nValueSize ) )
2921 {
2922 css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
2923 css::office::Quickstart::createAutoStart(xContext, true/*Quickstart*/, true/*bAutostart*/);
2924 RegCloseKey( hKey );
2925 }
2926 }
2927#endif
2928
2929 boost::shared_ptr< comphelper::ConfigurationChanges > batch(
2930 comphelper::ConfigurationChanges::create());
2931 officecfg::Office::Common::Misc::FirstRun::set(false, batch);
2932 batch->commit();
2933 }
2934}
2935
2936}
2937
2938/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2939