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
21 #include <algorithm>
22
23 #include <app.hxx>
24 #include <dp_shared.hxx>
25 #include "cmdlineargs.hxx"
26 #include <strings.hrc>
27 #include <com/sun/star/lang/XInitialization.hpp>
28 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
29 #include <com/sun/star/uno/Exception.hpp>
30 #include <com/sun/star/ucb/UniversalContentBroker.hpp>
31 #include <cppuhelper/bootstrap.hxx>
32 #include <officecfg/Setup.hxx>
33 #include <osl/file.hxx>
34 #include <rtl/bootstrap.hxx>
35 #include <sal/log.hxx>
36 #include <comphelper/diagnose_ex.hxx>
37
38 #include <comphelper/processfactory.hxx>
39 #include <unotools/ucbhelper.hxx>
40 #include <unotools/tempfile.hxx>
41 #include <vcl/svapp.hxx>
42 #include <unotools/pathoptions.hxx>
43
44 #include <iostream>
45 #include <map>
46
47 #if defined EMSCRIPTEN
48 #include <bindings_uno.hxx>
49 #endif
50
51 using namespace ::com::sun::star::uno;
52 using namespace ::com::sun::star::lang;
53 using namespace ::com::sun::star::ucb;
54
55 namespace desktop
56 {
57
58
configureUcb()59 static void configureUcb()
60 {
61 // For backwards compatibility, in case some code still uses plain
62 // createInstance w/o args directly to obtain an instance:
63 UniversalContentBroker::create(comphelper::getProcessComponentContext());
64 }
65
InitApplicationServiceManager()66 void Desktop::InitApplicationServiceManager()
67 {
68 Reference<XMultiServiceFactory> sm;
69 #ifdef ANDROID
70 OUString aUnoRc( "file:///assets/program/unorc" );
71 sm.set(
72 cppu::defaultBootstrap_InitialComponentContext( aUnoRc )->getServiceManager(),
73 UNO_QUERY_THROW);
74 #elif defined(IOS)
75 OUString uri( "$APP_DATA_DIR" );
76 rtl_bootstrap_expandMacros( &uri.pData );
77 OUString aUnoRc("file://" + uri + "/unorc");
78 sm.set(
79 cppu::defaultBootstrap_InitialComponentContext( aUnoRc )->getServiceManager(),
80 UNO_QUERY_THROW);
81 #else
82 sm.set(
83 cppu::defaultBootstrap_InitialComponentContext()->getServiceManager(),
84 UNO_QUERY_THROW);
85 #endif
86 comphelper::setProcessServiceFactory(sm);
87 #if defined EMSCRIPTEN
88 init_unoembind_uno();
89 #endif
90 }
91
RegisterServices()92 void Desktop::RegisterServices()
93 {
94 if( m_bServicesRegistered )
95 return;
96
97 // interpret command line arguments
98 CommandLineArgs& rCmdLine = GetCommandLineArgs();
99
100 // Headless mode for FAT Office, auto cancels any dialogs that popup
101 if (rCmdLine.IsHeadless())
102 Application::EnableHeadlessMode(false);
103
104 // read accept string from configuration
105 OUString conDcpCfg(
106 officecfg::Setup::Office::ooSetupConnectionURL::get());
107 if (!conDcpCfg.isEmpty()) {
108 createAcceptor(conDcpCfg);
109 }
110
111 std::vector< OUString > const & conDcp = rCmdLine.GetAccept();
112 for (auto const& elem : conDcp)
113 {
114 createAcceptor(elem);
115 }
116
117 configureUcb();
118
119 CreateTemporaryDirectory();
120 m_bServicesRegistered = true;
121 }
122
123 typedef std::map< OUString, css::uno::Reference<css::lang::XInitialization> > AcceptorMap;
124
125 namespace
126 {
acceptorMap()127 AcceptorMap& acceptorMap()
128 {
129 static AcceptorMap SINGLETON;
130 return SINGLETON;
131 }
CurrentTempURL()132 OUString& CurrentTempURL()
133 {
134 static OUString SINGLETON;
135 return SINGLETON;
136 }
137 }
138
139 static bool bAccept = false;
140
createAcceptor(const OUString & aAcceptString)141 void Desktop::createAcceptor(const OUString& aAcceptString)
142 {
143 // check whether the requested acceptor already exists
144 AcceptorMap &rMap = acceptorMap();
145 AcceptorMap::const_iterator pIter = rMap.find(aAcceptString);
146 if (pIter != rMap.end() )
147 {
148 // there is already an acceptor with this description
149 SAL_WARN( "desktop.app", "Acceptor already exists.");
150 return;
151 }
152
153 Sequence< Any > aSeq{ Any(aAcceptString), Any(bAccept) };
154 Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext();
155 Reference<XInitialization> rAcceptor(
156 xContext->getServiceManager()->createInstanceWithContext(u"com.sun.star.office.Acceptor"_ustr, xContext),
157 UNO_QUERY );
158 if ( rAcceptor.is() )
159 {
160 try
161 {
162 rAcceptor->initialize( aSeq );
163 rMap.emplace(aAcceptString, rAcceptor);
164 }
165 catch (const css::uno::Exception&)
166 {
167 // no error handling needed...
168 // acceptor just won't come up
169 TOOLS_WARN_EXCEPTION( "desktop.app", "Acceptor could not be created");
170 }
171 }
172 else
173 {
174 ::std::cerr << "UNO Remote Protocol acceptor could not be created, presumably because it has been disabled in configuration." << ::std::endl;
175 }
176 }
177
178 namespace {
179
180 class enable
181 {
182 private:
183 Sequence<Any> m_aSeq{ Any(true) };
184 public:
185 enable() = default;
operator ()(const AcceptorMap::value_type & val)186 void operator() (const AcceptorMap::value_type& val) {
187 if (val.second.is()) {
188 val.second->initialize(m_aSeq);
189 }
190 }
191 };
192
193 }
194
195 // enable acceptors
IMPL_STATIC_LINK_NOARG(Desktop,EnableAcceptors_Impl,void *,void)196 IMPL_STATIC_LINK_NOARG(Desktop, EnableAcceptors_Impl, void*, void)
197 {
198 if (!bAccept)
199 {
200 // from now on, all new acceptors are enabled
201 bAccept = true;
202 // enable existing acceptors by calling initialize(true)
203 // on all existing acceptors
204 AcceptorMap &rMap = acceptorMap();
205 std::for_each(rMap.begin(), rMap.end(), enable());
206 }
207 }
208
destroyAcceptor(const OUString & aAcceptString)209 void Desktop::destroyAcceptor(const OUString& aAcceptString)
210 {
211 // special case stop all acceptors
212 AcceptorMap &rMap = acceptorMap();
213 if (aAcceptString == "all") {
214 rMap.clear();
215
216 } else {
217 // try to remove acceptor from map
218 AcceptorMap::const_iterator pIter = rMap.find(aAcceptString);
219 if (pIter != rMap.end() ) {
220 // remove reference from map
221 // this is the last reference and the acceptor will be destructed
222 rMap.erase(aAcceptString);
223 } else {
224 SAL_WARN( "desktop.app", "Found no acceptor to remove");
225 }
226 }
227 }
228
229
DeregisterServices()230 void Desktop::DeregisterServices()
231 {
232 // stop all acceptors by clearing the map
233 acceptorMap().clear();
234 }
235
CreateTemporaryDirectory()236 void Desktop::CreateTemporaryDirectory()
237 {
238 OUString aTempBaseURL;
239 try
240 {
241 SvtPathOptions aOpt;
242 aTempBaseURL = aOpt.GetTempPath();
243 }
244 catch (RuntimeException& e)
245 {
246 // Catch runtime exception here: We have to add language dependent info
247 // to the exception message. Fallback solution uses hard coded string.
248 OUString aMsg = DpResId(STR_BOOTSTRAP_ERR_NO_PATHSET_SERVICE);
249 e.Message = aMsg + e.Message;
250 throw;
251 }
252
253 // create new current temporary directory
254 OUString aTempPath = ::utl::SetTempNameBaseDirectory( aTempBaseURL );
255 if ( aTempPath.isEmpty()
256 && ::osl::File::getTempDirURL( aTempBaseURL ) == osl::FileBase::E_None )
257 {
258 aTempPath = ::utl::SetTempNameBaseDirectory( aTempBaseURL );
259 }
260
261 // set new current temporary directory
262 OUString aRet;
263 if (osl::FileBase::getFileURLFromSystemPath( aTempPath, aRet )
264 != osl::FileBase::E_None)
265 {
266 aRet.clear();
267 }
268 CurrentTempURL() = aRet;
269 }
270
RemoveTemporaryDirectory()271 void Desktop::RemoveTemporaryDirectory()
272 {
273 // remove current temporary directory
274 OUString &rCurrentTempURL = CurrentTempURL();
275 if ( !rCurrentTempURL.isEmpty() )
276 {
277 ::utl::UCBContentHelper::Kill( rCurrentTempURL );
278 }
279 }
280
281 } // namespace desktop
282
283 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
284