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_script.hrc" 32 #include "dp_lib_container.h" 33 #include "dp_backend.h" 34 #include "dp_ucb.h" 35 #include "rtl/uri.hxx" 36 #include "ucbhelper/content.hxx" 37 #include "cppuhelper/exc_hlp.hxx" 38 #include "cppuhelper/implbase1.hxx" 39 #include "comphelper/servicedecl.hxx" 40 #include "svl/inettype.hxx" 41 #include "com/sun/star/util/XUpdatable.hpp" 42 #include "com/sun/star/script/XLibraryContainer3.hpp" 43 #include <com/sun/star/ucb/XSimpleFileAccess.hpp> 44 #include <com/sun/star/util/XMacroExpander.hpp> 45 #include <com/sun/star/uri/XUriReferenceFactory.hpp> 46 #include <memory> 47 #include "dp_scriptbackenddb.hxx" 48 49 using namespace ::dp_misc; 50 using namespace ::com::sun::star; 51 using namespace ::com::sun::star::uno; 52 using namespace ::com::sun::star::ucb; 53 using ::rtl::OUString; 54 namespace css = ::com::sun::star; 55 56 namespace dp_registry { 57 namespace backend { 58 namespace script { 59 namespace { 60 61 typedef ::cppu::ImplInheritanceHelper1< 62 ::dp_registry::backend::PackageRegistryBackend, util::XUpdatable > t_helper; 63 64 //============================================================================== 65 class BackendImpl : public t_helper 66 { 67 class PackageImpl : public ::dp_registry::backend::Package 68 { 69 BackendImpl * getMyBackend() const; 70 71 const OUString m_scriptURL; 72 const OUString m_dialogURL; 73 OUString m_dialogName; 74 75 // Package 76 virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_( 77 ::osl::ResettableMutexGuard & guard, 78 ::rtl::Reference<AbortChannel> const & abortChannel, 79 Reference<XCommandEnvironment> const & xCmdEnv ); 80 virtual void processPackage_( 81 ::osl::ResettableMutexGuard & guard, 82 bool registerPackage, 83 bool startup, 84 ::rtl::Reference<AbortChannel> const & abortChannel, 85 Reference<XCommandEnvironment> const & xCmdEnv ); 86 87 public: 88 PackageImpl( 89 ::rtl::Reference<BackendImpl> const & myBackend, 90 OUString const & url, 91 Reference<XCommandEnvironment> const &xCmdEnv, 92 OUString const & scriptURL, OUString const & dialogURL, 93 bool bRemoved, OUString const & identifier); 94 }; 95 friend class PackageImpl; 96 97 // PackageRegistryBackend 98 virtual Reference<deployment::XPackage> bindPackage_( 99 OUString const & url, OUString const & mediaType, 100 sal_Bool bRemoved, OUString const & identifier, 101 Reference<XCommandEnvironment> const & xCmdEnv ); 102 103 void addDataToDb(OUString const & url); 104 bool hasActiveEntry(OUString const & url); 105 void revokeEntryFromDb(OUString const & url); 106 107 const Reference<deployment::XPackageTypeInfo> m_xBasicLibTypeInfo; 108 const Reference<deployment::XPackageTypeInfo> m_xDialogLibTypeInfo; 109 Sequence< Reference<deployment::XPackageTypeInfo> > m_typeInfos; 110 std::auto_ptr<ScriptBackendDb> m_backendDb; 111 public: 112 BackendImpl( Sequence<Any> const & args, 113 Reference<XComponentContext> const & xComponentContext ); 114 115 // XUpdatable 116 virtual void SAL_CALL update() throw (RuntimeException); 117 118 // XPackageRegistry 119 virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL 120 getSupportedPackageTypes() throw (RuntimeException); 121 virtual void SAL_CALL packageRemoved(OUString const & url, OUString const & mediaType) 122 throw (deployment::DeploymentException, 123 uno::RuntimeException); 124 125 }; 126 127 //______________________________________________________________________________ 128 BackendImpl::PackageImpl::PackageImpl( 129 ::rtl::Reference<BackendImpl> const & myBackend, 130 OUString const & url, 131 Reference<XCommandEnvironment> const &xCmdEnv, 132 OUString const & scriptURL, OUString const & dialogURL, bool bRemoved, 133 OUString const & identifier) 134 : Package( myBackend.get(), url, 135 OUString(), OUString(), // will be late-initialized 136 scriptURL.getLength() > 0 ? myBackend->m_xBasicLibTypeInfo 137 : myBackend->m_xDialogLibTypeInfo, bRemoved, identifier), 138 m_scriptURL( scriptURL ), 139 m_dialogURL( dialogURL ) 140 { 141 // name, displayName: 142 if (dialogURL.getLength() > 0) { 143 m_dialogName = LibraryContainer::get_libname( 144 dialogURL, xCmdEnv, myBackend->getComponentContext() ); 145 } 146 if (scriptURL.getLength() > 0) { 147 m_name = LibraryContainer::get_libname( 148 scriptURL, xCmdEnv, myBackend->getComponentContext() ); 149 } 150 else 151 m_name = m_dialogName; 152 m_displayName = m_name; 153 } 154 155 //______________________________________________________________________________ 156 BackendImpl::BackendImpl( 157 Sequence<Any> const & args, 158 Reference<XComponentContext> const & xComponentContext ) 159 : t_helper( args, xComponentContext ), 160 m_xBasicLibTypeInfo( new Package::TypeInfo( 161 OUSTR("application/" 162 "vnd.sun.star.basic-library"), 163 OUString() /* no file filter */, 164 getResourceString(RID_STR_BASIC_LIB), 165 RID_IMG_SCRIPTLIB, RID_IMG_SCRIPTLIB_HC ) ), 166 m_xDialogLibTypeInfo( new Package::TypeInfo( 167 OUSTR("application/" 168 "vnd.sun.star.dialog-library"), 169 OUString() /* no file filter */, 170 getResourceString(RID_STR_DIALOG_LIB), 171 RID_IMG_DIALOGLIB, RID_IMG_DIALOGLIB_HC ) ), 172 m_typeInfos( 2 ) 173 { 174 m_typeInfos[ 0 ] = m_xBasicLibTypeInfo; 175 m_typeInfos[ 1 ] = m_xDialogLibTypeInfo; 176 177 OSL_ASSERT( ! transientMode() ); 178 179 if (!transientMode()) 180 { 181 OUString dbFile = makeURL(getCachePath(), OUSTR("backenddb.xml")); 182 m_backendDb.reset( 183 new ScriptBackendDb(getComponentContext(), dbFile)); 184 } 185 186 } 187 void BackendImpl::addDataToDb(OUString const & url) 188 { 189 if (m_backendDb.get()) 190 m_backendDb->addEntry(url); 191 } 192 193 bool BackendImpl::hasActiveEntry(OUString const & url) 194 { 195 if (m_backendDb.get()) 196 return m_backendDb->hasActiveEntry(url); 197 return false; 198 } 199 200 // XUpdatable 201 //______________________________________________________________________________ 202 void BackendImpl::update() throw (RuntimeException) 203 { 204 // Nothing to do here after fixing i70283!? 205 } 206 207 // XPackageRegistry 208 //______________________________________________________________________________ 209 Sequence< Reference<deployment::XPackageTypeInfo> > 210 BackendImpl::getSupportedPackageTypes() throw (RuntimeException) 211 { 212 return m_typeInfos; 213 } 214 void BackendImpl::revokeEntryFromDb(OUString const & url) 215 { 216 if (m_backendDb.get()) 217 m_backendDb->revokeEntry(url); 218 } 219 220 void BackendImpl::packageRemoved(OUString const & url, OUString const & /*mediaType*/) 221 throw (deployment::DeploymentException, 222 uno::RuntimeException) 223 { 224 if (m_backendDb.get()) 225 m_backendDb->removeEntry(url); 226 } 227 228 // PackageRegistryBackend 229 //______________________________________________________________________________ 230 Reference<deployment::XPackage> BackendImpl::bindPackage_( 231 OUString const & url, OUString const & mediaType_, 232 sal_Bool bRemoved, OUString const & identifier, 233 Reference<XCommandEnvironment> const & xCmdEnv ) 234 { 235 OUString mediaType( mediaType_ ); 236 if (mediaType.getLength() == 0) 237 { 238 // detect media-type: 239 ::ucbhelper::Content ucbContent; 240 if (create_ucb_content( &ucbContent, url, xCmdEnv ) && 241 ucbContent.isFolder()) 242 { 243 // probe for script.xlb: 244 if (create_ucb_content( 245 0, makeURL( url, OUSTR("script.xlb") ), 246 xCmdEnv, false /* no throw */ )) 247 mediaType = OUSTR("application/vnd.sun.star.basic-library"); 248 // probe for dialog.xlb: 249 else if (create_ucb_content( 250 0, makeURL( url, OUSTR("dialog.xlb") ), 251 xCmdEnv, false /* no throw */ )) 252 mediaType = OUSTR("application/vnd.sun.star.dialog-library"); 253 } 254 if (mediaType.getLength() == 0) 255 throw lang::IllegalArgumentException( 256 StrCannotDetectMediaType::get() + url, 257 static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) ); 258 } 259 260 String type, subType; 261 INetContentTypeParameterList params; 262 if (INetContentTypes::parse( mediaType, type, subType, ¶ms )) 263 { 264 if (type.EqualsIgnoreCaseAscii("application")) 265 { 266 OUString dialogURL( makeURL( url, OUSTR("dialog.xlb") ) ); 267 if (! create_ucb_content( 268 0, dialogURL, xCmdEnv, false /* no throw */ )) { 269 dialogURL = OUString(); 270 } 271 272 if (subType.EqualsIgnoreCaseAscii("vnd.sun.star.basic-library")) 273 { 274 OUString scriptURL( makeURL( url, OUSTR("script.xlb"))); 275 if (! create_ucb_content( 276 0, scriptURL, xCmdEnv, false /* no throw */ )) { 277 scriptURL = OUString(); 278 } 279 280 return new PackageImpl( 281 this, url, xCmdEnv, scriptURL, 282 dialogURL, bRemoved, identifier); 283 } 284 else if (subType.EqualsIgnoreCaseAscii( 285 "vnd.sun.star.dialog-library")) { 286 return new PackageImpl( 287 this, url, xCmdEnv, 288 OUString() /* no script lib */, 289 dialogURL, 290 bRemoved, identifier); 291 } 292 } 293 } 294 throw lang::IllegalArgumentException( 295 StrUnsupportedMediaType::get() + mediaType, 296 static_cast<OWeakObject *>(this), 297 static_cast<sal_Int16>(-1) ); 298 } 299 300 //############################################################################## 301 302 // Package 303 BackendImpl * BackendImpl::PackageImpl::getMyBackend() const 304 { 305 BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get()); 306 if (NULL == pBackend) 307 { 308 //May throw a DisposedException 309 check(); 310 //We should never get here... 311 throw RuntimeException( 312 OUSTR("Failed to get the BackendImpl"), 313 static_cast<OWeakObject*>(const_cast<PackageImpl *>(this))); 314 } 315 return pBackend; 316 } 317 //______________________________________________________________________________ 318 beans::Optional< beans::Ambiguous<sal_Bool> > 319 BackendImpl::PackageImpl::isRegistered_( 320 ::osl::ResettableMutexGuard &, 321 ::rtl::Reference<AbortChannel> const &, 322 Reference<XCommandEnvironment> const & xCmdEnv ) 323 { 324 (void)xCmdEnv; 325 326 BackendImpl * that = getMyBackend(); 327 Reference< deployment::XPackage > xThisPackage( this ); 328 329 bool registered = that->hasActiveEntry(getURL()); 330 return beans::Optional< beans::Ambiguous<sal_Bool> >( 331 true /* IsPresent */, 332 beans::Ambiguous<sal_Bool>( registered, false /* IsAmbiguous */ ) ); 333 } 334 335 //______________________________________________________________________________ 336 void BackendImpl::PackageImpl::processPackage_( 337 ::osl::ResettableMutexGuard &, 338 bool doRegisterPackage, 339 bool startup, 340 ::rtl::Reference<AbortChannel> const &, 341 Reference<XCommandEnvironment> const & xCmdEnv ) 342 { 343 (void)xCmdEnv; 344 345 BackendImpl * that = getMyBackend(); 346 347 Reference< deployment::XPackage > xThisPackage( this ); 348 Reference<XComponentContext> const & xComponentContext = that->getComponentContext(); 349 350 bool bScript = (m_scriptURL.getLength() > 0); 351 Reference<css::script::XLibraryContainer3> xScriptLibs; 352 353 bool bDialog = (m_dialogURL.getLength() > 0); 354 Reference<css::script::XLibraryContainer3> xDialogLibs; 355 356 bool bRunning = office_is_running(); 357 if( bRunning ) 358 { 359 if( bScript ) 360 { 361 xScriptLibs.set( 362 xComponentContext->getServiceManager()->createInstanceWithContext( 363 OUSTR("com.sun.star.script.ApplicationScriptLibraryContainer"), 364 xComponentContext ), UNO_QUERY_THROW ); 365 } 366 367 if( bDialog ) 368 { 369 xDialogLibs.set( 370 xComponentContext->getServiceManager()->createInstanceWithContext( 371 OUSTR("com.sun.star.script.ApplicationDialogLibraryContainer"), 372 xComponentContext ), UNO_QUERY_THROW ); 373 } 374 } 375 bool bRegistered = getMyBackend()->hasActiveEntry(getURL()); 376 if( !doRegisterPackage ) 377 { 378 //We cannot just call removeLibrary(name) because this could remove a 379 //script which was added by an extension in a different repository. For 380 //example, extension foo is contained in the bundled repository and then 381 //the user adds it it to the user repository. The extension manager will 382 //then register the new script and revoke the script from the bundled 383 //extension. removeLibrary(name) would now remove the script from the 384 //user repository. That is, the script of the newly added user extension does 385 //not work anymore. Therefore we must check if the currently active 386 //script comes in fact from the currently processed extension. 387 388 if (bRegistered) 389 { 390 //we also prevent and live deployment at startup 391 if (!isRemoved() && !startup) 392 { 393 if (bScript && xScriptLibs.is() && xScriptLibs->hasByName(m_name)) 394 { 395 const OUString sScriptUrl = xScriptLibs->getOriginalLibraryLinkURL(m_name); 396 if (sScriptUrl.equals(m_scriptURL)) 397 xScriptLibs->removeLibrary(m_name); 398 } 399 400 if (bDialog && xDialogLibs.is() && xDialogLibs->hasByName(m_dialogName)) 401 { 402 const OUString sDialogUrl = xDialogLibs->getOriginalLibraryLinkURL(m_dialogName); 403 if (sDialogUrl.equals(m_dialogURL)) 404 xDialogLibs->removeLibrary(m_dialogName); 405 } 406 } 407 getMyBackend()->revokeEntryFromDb(getURL()); 408 return; 409 } 410 } 411 if (bRegistered) 412 return; // Already registered 413 414 // Update LibraryContainer 415 bool bScriptSuccess = false; 416 const bool bReadOnly = false; 417 418 bool bDialogSuccess = false; 419 if (!startup) 420 { 421 //If there is a bundled extension, and the user installes the same extension 422 //then the script from the bundled extension must be removed. If this does not work 423 //then live deployment does not work for scripts. 424 if (bScript && xScriptLibs.is()) 425 { 426 bool bCanAdd = true; 427 if (xScriptLibs->hasByName(m_name)) 428 { 429 const OUString sOriginalUrl = xScriptLibs->getOriginalLibraryLinkURL(m_name); 430 //We assume here that library names in extensions are unique, which may not be the case 431 //ToDo: If the script exist in another extension, then both extensions must have the 432 //same id 433 if (sOriginalUrl.match(OUSTR("vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE")) 434 || sOriginalUrl.match(OUSTR("vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE")) 435 || sOriginalUrl.match(OUSTR("vnd.sun.star.expand:$BUNDLED_EXTENSIONS"))) 436 { 437 xScriptLibs->removeLibrary(m_name); 438 bCanAdd = true; 439 } 440 else 441 { 442 bCanAdd = false; 443 } 444 } 445 446 if (bCanAdd) 447 { 448 xScriptLibs->createLibraryLink( m_name, m_scriptURL, bReadOnly ); 449 bScriptSuccess = xScriptLibs->hasByName( m_name ); 450 } 451 } 452 453 454 if (bDialog && xDialogLibs.is()) 455 { 456 bool bCanAdd = true; 457 if (xDialogLibs->hasByName(m_dialogName)) 458 { 459 const OUString sOriginalUrl = xDialogLibs->getOriginalLibraryLinkURL(m_dialogName); 460 //We assume here that library names in extensions are unique, which may not be the case 461 //ToDo: If the script exist in another extension, then both extensions must have the 462 //same id 463 if (sOriginalUrl.match(OUSTR("vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE")) 464 || sOriginalUrl.match(OUSTR("vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE")) 465 || sOriginalUrl.match(OUSTR("vnd.sun.star.expand:$BUNDLED_EXTENSIONS"))) 466 { 467 xDialogLibs->removeLibrary(m_dialogName); 468 bCanAdd = true; 469 } 470 else 471 { 472 bCanAdd = false; 473 } 474 } 475 476 if (bCanAdd) 477 { 478 xDialogLibs->createLibraryLink( m_dialogName, m_dialogURL, bReadOnly ); 479 bDialogSuccess = xDialogLibs->hasByName(m_dialogName); 480 } 481 } 482 } 483 bool bSuccess = bScript || bDialog; // Something must have happened 484 if( bRunning && !startup) 485 if( (bScript && !bScriptSuccess) || (bDialog && !bDialogSuccess) ) 486 bSuccess = false; 487 488 if (bSuccess) 489 getMyBackend()->addDataToDb(getURL()); 490 } 491 492 } // anon namespace 493 494 namespace sdecl = comphelper::service_decl; 495 sdecl::class_<BackendImpl, sdecl::with_args<true> > serviceBI; 496 extern sdecl::ServiceDecl const serviceDecl( 497 serviceBI, 498 "com.sun.star.comp.deployment.script.PackageRegistryBackend", 499 BACKEND_SERVICE_NAME ); 500 501 } // namespace script 502 } // namespace backend 503 } // namespace dp_registry 504 505