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