Line data Source code
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 "dp_misc.h"
22 : #include "dp_backend.h"
23 : #include "dp_ucb.h"
24 : #include "dp_interact.h"
25 : #include "rtl/string.hxx"
26 : #include "osl/file.hxx"
27 : #include "ucbhelper/content.hxx"
28 : #include "comphelper/servicedecl.hxx"
29 : #include "svl/inettype.hxx"
30 : #include "cppuhelper/implbase1.hxx"
31 : #include "dp_executablebackenddb.hxx"
32 :
33 : using namespace ::com::sun::star;
34 : using namespace ::com::sun::star::uno;
35 : using namespace ::com::sun::star::ucb;
36 : using namespace dp_misc;
37 : using ::rtl::OUString;
38 :
39 : namespace dp_registry {
40 : namespace backend {
41 : namespace executable {
42 : namespace {
43 :
44 0 : class BackendImpl : public ::dp_registry::backend::PackageRegistryBackend
45 : {
46 0 : class ExecutablePackageImpl : public ::dp_registry::backend::Package
47 : {
48 : BackendImpl * getMyBackend() const;
49 :
50 : // Package
51 : virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_(
52 : ::osl::ResettableMutexGuard & guard,
53 : ::rtl::Reference<dp_misc::AbortChannel> const & abortChannel,
54 : Reference<XCommandEnvironment> const & xCmdEnv );
55 : virtual void processPackage_(
56 : ::osl::ResettableMutexGuard & guard,
57 : bool registerPackage,
58 : bool startup,
59 : ::rtl::Reference<dp_misc::AbortChannel> const & abortChannel,
60 : Reference<XCommandEnvironment> const & xCmdEnv );
61 :
62 : bool getFileAttributes(sal_uInt64& out_Attributes);
63 : bool isUrlTargetInExtension();
64 :
65 : public:
66 0 : inline ExecutablePackageImpl(
67 : ::rtl::Reference<PackageRegistryBackend> const & myBackend,
68 : OUString const & url, OUString const & name,
69 : Reference<deployment::XPackageTypeInfo> const & xPackageType,
70 : bool bRemoved, OUString const & identifier)
71 : : Package( myBackend, url, name, name /* display-name */,
72 0 : xPackageType, bRemoved, identifier)
73 0 : {}
74 : };
75 : friend class ExecutablePackageImpl;
76 :
77 : typedef ::boost::unordered_map< OUString, Reference<XInterface>,
78 : ::rtl::OUStringHash > t_string2object;
79 :
80 : // PackageRegistryBackend
81 : virtual Reference<deployment::XPackage> bindPackage_(
82 : OUString const & url, OUString const & mediaType, sal_Bool bRemoved,
83 : OUString const & identifier, Reference<XCommandEnvironment> const & xCmdEnv );
84 :
85 : void addDataToDb(OUString const & url);
86 : bool hasActiveEntry(OUString const & url);
87 : void revokeEntryFromDb(OUString const & url);
88 :
89 : Reference<deployment::XPackageTypeInfo> m_xExecutableTypeInfo;
90 : std::auto_ptr<ExecutableBackendDb> m_backendDb;
91 : public:
92 : BackendImpl( Sequence<Any> const & args,
93 : Reference<XComponentContext> const & xComponentContext );
94 :
95 : // XPackageRegistry
96 : virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL
97 : getSupportedPackageTypes() throw (RuntimeException);
98 : virtual void SAL_CALL packageRemoved(OUString const & url, OUString const & mediaType)
99 : throw (deployment::DeploymentException,
100 : uno::RuntimeException);
101 :
102 : using PackageRegistryBackend::disposing;
103 : };
104 :
105 :
106 0 : BackendImpl::BackendImpl(
107 : Sequence<Any> const & args,
108 : Reference<XComponentContext> const & xComponentContext )
109 : : PackageRegistryBackend( args, xComponentContext ),
110 : m_xExecutableTypeInfo(new Package::TypeInfo(
111 : OUSTR("application/vnd.sun.star.executable"),
112 : OUSTR(""),
113 : OUSTR("Executable"),
114 0 : RID_IMG_COMPONENT ) )
115 : {
116 0 : if (!transientMode())
117 : {
118 0 : OUString dbFile = makeURL(getCachePath(), OUSTR("backenddb.xml"));
119 : m_backendDb.reset(
120 0 : new ExecutableBackendDb(getComponentContext(), dbFile));
121 : }
122 0 : }
123 :
124 0 : void BackendImpl::addDataToDb(OUString const & url)
125 : {
126 0 : if (m_backendDb.get())
127 0 : m_backendDb->addEntry(url);
128 0 : }
129 :
130 0 : void BackendImpl::revokeEntryFromDb(OUString const & url)
131 : {
132 0 : if (m_backendDb.get())
133 0 : m_backendDb->revokeEntry(url);
134 0 : }
135 :
136 0 : bool BackendImpl::hasActiveEntry(OUString const & url)
137 : {
138 0 : if (m_backendDb.get())
139 0 : return m_backendDb->hasActiveEntry(url);
140 0 : return false;
141 : }
142 :
143 :
144 : // XPackageRegistry
145 : Sequence< Reference<deployment::XPackageTypeInfo> >
146 0 : BackendImpl::getSupportedPackageTypes() throw (RuntimeException)
147 : {
148 : return Sequence<Reference<deployment::XPackageTypeInfo> >(
149 0 : & m_xExecutableTypeInfo, 1);
150 : }
151 :
152 0 : void BackendImpl::packageRemoved(OUString const & url, OUString const & /*mediaType*/)
153 : throw (deployment::DeploymentException,
154 : uno::RuntimeException)
155 : {
156 0 : if (m_backendDb.get())
157 0 : m_backendDb->removeEntry(url);
158 0 : }
159 :
160 : // PackageRegistryBackend
161 0 : Reference<deployment::XPackage> BackendImpl::bindPackage_(
162 : OUString const & url, OUString const & mediaType, sal_Bool bRemoved,
163 : OUString const & identifier, Reference<XCommandEnvironment> const & xCmdEnv )
164 : {
165 0 : if (mediaType.isEmpty())
166 : {
167 : throw lang::IllegalArgumentException(
168 0 : StrCannotDetectMediaType::get() + url,
169 0 : static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) );
170 : }
171 :
172 0 : OUString type, subType;
173 0 : INetContentTypeParameterList params;
174 0 : if (INetContentTypes::parse( mediaType, type, subType, ¶ms ))
175 : {
176 0 : if (type.equalsIgnoreAsciiCaseAscii("application"))
177 : {
178 0 : OUString name;
179 0 : if (!bRemoved)
180 : {
181 : ::ucbhelper::Content ucbContent(
182 0 : url, xCmdEnv, getComponentContext() );
183 0 : name = StrTitle::getTitle( ucbContent );
184 : }
185 0 : if (subType.equalsIgnoreAsciiCaseAscii("vnd.sun.star.executable"))
186 : {
187 : return new BackendImpl::ExecutablePackageImpl(
188 : this, url, name, m_xExecutableTypeInfo, bRemoved,
189 0 : identifier);
190 0 : }
191 : }
192 : }
193 0 : return Reference<deployment::XPackage>();
194 : }
195 :
196 :
197 :
198 : // Package
199 0 : BackendImpl * BackendImpl::ExecutablePackageImpl::getMyBackend() const
200 : {
201 0 : BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get());
202 0 : if (NULL == pBackend)
203 : {
204 : //May throw a DisposedException
205 0 : check();
206 : //We should never get here...
207 : throw RuntimeException(
208 : OUSTR("Failed to get the BackendImpl"),
209 0 : static_cast<OWeakObject*>(const_cast<ExecutablePackageImpl *>(this)));
210 : }
211 0 : return pBackend;
212 : }
213 :
214 : beans::Optional< beans::Ambiguous<sal_Bool> >
215 0 : BackendImpl::ExecutablePackageImpl::isRegistered_(
216 : ::osl::ResettableMutexGuard &,
217 : ::rtl::Reference<dp_misc::AbortChannel> const &,
218 : Reference<XCommandEnvironment> const & )
219 : {
220 0 : bool registered = getMyBackend()->hasActiveEntry(getURL());
221 : return beans::Optional< beans::Ambiguous<sal_Bool> >(
222 : sal_True /* IsPresent */,
223 : beans::Ambiguous<sal_Bool>(
224 0 : registered, sal_False /* IsAmbiguous */ ) );
225 : }
226 :
227 0 : void BackendImpl::ExecutablePackageImpl::processPackage_(
228 : ::osl::ResettableMutexGuard &,
229 : bool doRegisterPackage,
230 : bool /*startup*/,
231 : ::rtl::Reference<dp_misc::AbortChannel> const & abortChannel,
232 : Reference<XCommandEnvironment> const & /*xCmdEnv*/ )
233 : {
234 0 : checkAborted(abortChannel);
235 0 : if (doRegisterPackage)
236 : {
237 0 : if (!isUrlTargetInExtension())
238 : {
239 : OSL_ASSERT(0);
240 0 : return;
241 : }
242 0 : sal_uInt64 attributes = 0;
243 : //Setting the executable attribut does not affect executables on Windows
244 0 : if (getFileAttributes(attributes))
245 : {
246 0 : if(getMyBackend()->m_context.equals(OUSTR("user")))
247 0 : attributes |= osl_File_Attribute_OwnExe;
248 0 : else if (getMyBackend()->m_context.equals(OUSTR("shared")))
249 : attributes |= (osl_File_Attribute_OwnExe | osl_File_Attribute_GrpExe
250 0 : | osl_File_Attribute_OthExe);
251 0 : else if (!getMyBackend()->m_context.equals(OUSTR("bundled")))
252 : //Bundled extension are required to be in the properly
253 : //installed. That is an executable must have the right flags
254 : OSL_ASSERT(0);
255 :
256 : //This won't have affect on Windows
257 : osl::File::setAttributes(
258 0 : dp_misc::expandUnoRcUrl(m_url), attributes);
259 : }
260 0 : getMyBackend()->addDataToDb(getURL());
261 : }
262 : else
263 : {
264 0 : getMyBackend()->revokeEntryFromDb(getURL());
265 : }
266 : }
267 :
268 : //We currently cannot check if this XPackage represents a content of a particular extension
269 : //But we can check if we are within $UNO_USER_PACKAGES_CACHE etc.
270 : //Done for security reasons. For example an extension manifest could contain a path to
271 : //an executable outside the extension.
272 0 : bool BackendImpl::ExecutablePackageImpl::isUrlTargetInExtension()
273 : {
274 0 : bool bSuccess = false;
275 0 : OUString sExtensionDir;
276 0 : if(getMyBackend()->m_context.equals(OUSTR("user")))
277 0 : sExtensionDir = dp_misc::expandUnoRcTerm(OUSTR("$UNO_USER_PACKAGES_CACHE"));
278 0 : else if (getMyBackend()->m_context.equals(OUSTR("shared")))
279 0 : sExtensionDir = dp_misc::expandUnoRcTerm(OUSTR("$UNO_SHARED_PACKAGES_CACHE"));
280 0 : else if (getMyBackend()->m_context.equals(OUSTR("bundled")))
281 0 : sExtensionDir = dp_misc::expandUnoRcTerm(OUSTR("$BUNDLED_EXTENSIONS"));
282 : else
283 : OSL_ASSERT(0);
284 : //remove file ellipses
285 0 : if (osl::File::E_None == osl::File::getAbsoluteFileURL(OUString(), sExtensionDir, sExtensionDir))
286 : {
287 0 : OUString sFile;
288 0 : if (osl::File::E_None == osl::File::getAbsoluteFileURL(
289 0 : OUString(), dp_misc::expandUnoRcUrl(m_url), sFile))
290 : {
291 0 : if (sal_True == sFile.match(sExtensionDir, 0))
292 0 : bSuccess = true;
293 0 : }
294 : }
295 0 : return bSuccess;
296 : }
297 :
298 0 : bool BackendImpl::ExecutablePackageImpl::getFileAttributes(sal_uInt64& out_Attributes)
299 : {
300 0 : bool bSuccess = false;
301 0 : const OUString url(dp_misc::expandUnoRcUrl(m_url));
302 0 : osl::DirectoryItem item;
303 0 : if (osl::FileBase::E_None == osl::DirectoryItem::get(url, item))
304 : {
305 0 : osl::FileStatus aStatus(osl_FileStatus_Mask_Attributes);
306 0 : if( osl::FileBase::E_None == item.getFileStatus(aStatus))
307 : {
308 0 : out_Attributes = aStatus.getAttributes();
309 0 : bSuccess = true;
310 0 : }
311 : }
312 0 : return bSuccess;
313 : }
314 :
315 :
316 :
317 : } // anon namespace
318 :
319 : namespace sdecl = comphelper::service_decl;
320 1 : sdecl::class_<BackendImpl, sdecl::with_args<true> > serviceBI;
321 1 : extern sdecl::ServiceDecl const serviceDecl(
322 : serviceBI,
323 : "com.sun.star.comp.deployment.executable.PackageRegistryBackend",
324 : BACKEND_SERVICE_NAME );
325 :
326 : } // namespace component
327 : } // namespace backend
328 3 : } // namespace dp_registry
329 :
330 :
331 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|