1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_extensions.hxx" 26 #include <com/sun/star/xml/xpath/XXPathAPI.hpp> 27 28 #include "updateprotocol.hxx" 29 #include "updatecheckconfig.hxx" 30 31 #ifndef _COM_SUN_STAR_DEPLOYMENT_UPDATEINFORMATINENTRY_HPP_ 32 #include <com/sun/star/deployment/UpdateInformationEntry.hpp> 33 #endif 34 #include <com/sun/star/deployment/XPackageInformationProvider.hpp> 35 36 37 #include <rtl/ref.hxx> 38 #include <rtl/uri.hxx> 39 #include <rtl/strbuf.hxx> 40 #include <rtl/ustrbuf.hxx> 41 #include <rtl/bootstrap.hxx> 42 #include <osl/process.h> 43 44 #include <cppuhelper/implbase1.hxx> 45 46 namespace css = com::sun::star ; 47 namespace container = css::container ; 48 namespace deployment = css::deployment ; 49 namespace lang = css::lang ; 50 namespace uno = css::uno ; 51 namespace task = css::task ; 52 namespace xml = css::xml ; 53 54 #define UNISTRING(s) rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(s)) 55 56 //------------------------------------------------------------------------------ 57 58 static bool 59 getBootstrapData( 60 uno::Sequence< ::rtl::OUString > & rRepositoryList, 61 ::rtl::OUString & rBuildID, 62 ::rtl::OUString & rInstallSetID) 63 { 64 rBuildID = UNISTRING( "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("version") ":ProductBuildid}" ); 65 rtl::Bootstrap::expandMacros( rBuildID ); 66 if ( ! rBuildID.getLength() ) 67 return false; 68 69 rInstallSetID = UNISTRING( "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("version") ":UpdateID}" ); 70 rtl::Bootstrap::expandMacros( rInstallSetID ); 71 if ( ! rInstallSetID.getLength() ) 72 return false; 73 74 rtl::OUString aValue( UNISTRING( "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("version") ":UpdateURL}" ) ); 75 rtl::Bootstrap::expandMacros( aValue ); 76 77 if( aValue.getLength() > 0 ) 78 { 79 rRepositoryList.realloc(1); 80 rRepositoryList[0] = aValue; 81 } 82 83 return true; 84 } 85 86 //------------------------------------------------------------------------------ 87 88 // Returns 'true' if successfully connected to the update server 89 bool 90 checkForUpdates( 91 UpdateInfo& o_rUpdateInfo, 92 uno::Reference< uno::XComponentContext > const & rxContext, 93 uno::Reference< task::XInteractionHandler > const & rxInteractionHandler, 94 const uno::Reference< deployment::XUpdateInformationProvider >& rUpdateInfoProvider) 95 { 96 OSL_TRACE("checking for updates ..\n"); 97 98 ::rtl::OUString myArch; 99 ::rtl::OUString myOS; 100 101 rtl::Bootstrap::get(UNISTRING("_OS"), myOS); 102 rtl::Bootstrap::get(UNISTRING("_ARCH"), myArch); 103 104 uno::Sequence< ::rtl::OUString > aRepositoryList; 105 ::rtl::OUString aBuildID; 106 ::rtl::OUString aInstallSetID; 107 108 if( ! ( getBootstrapData(aRepositoryList, aBuildID, aInstallSetID) && (aRepositoryList.getLength() > 0) ) ) 109 return false; 110 111 if( !rxContext.is() ) 112 throw uno::RuntimeException( 113 UNISTRING( "checkForUpdates: empty component context" ), uno::Reference< uno::XInterface >() ); 114 115 OSL_ASSERT( rxContext->getServiceManager().is() ); 116 117 // XPath implementation 118 uno::Reference< xml::xpath::XXPathAPI > xXPath( 119 rxContext->getServiceManager()->createInstanceWithContext( UNISTRING( "com.sun.star.xml.xpath.XPathAPI" ), rxContext ), 120 uno::UNO_QUERY_THROW); 121 122 xXPath->registerNS( UNISTRING("inst"), UNISTRING("http://installation.openoffice.org/description") ); 123 124 if( rxInteractionHandler.is() ) 125 rUpdateInfoProvider->setInteractionHandler(rxInteractionHandler); 126 127 try 128 { 129 uno::Reference< container::XEnumeration > aUpdateInfoEnumeration = 130 rUpdateInfoProvider->getUpdateInformationEnumeration( aRepositoryList, aInstallSetID ); 131 132 if ( !aUpdateInfoEnumeration.is() ) 133 return false; // something went wrong .. 134 135 rtl::OUStringBuffer aBuffer; 136 aBuffer.appendAscii("/child::inst:description[inst:os=\'"); 137 aBuffer.append( myOS ); 138 aBuffer.appendAscii("\' and inst:arch=\'"); 139 aBuffer.append( myArch ); 140 aBuffer.appendAscii("\' and inst:buildid>"); 141 aBuffer.append( aBuildID ); 142 aBuffer.appendAscii("]"); 143 144 rtl::OUString aXPathExpression = aBuffer.makeStringAndClear(); 145 146 while( aUpdateInfoEnumeration->hasMoreElements() ) 147 { 148 deployment::UpdateInformationEntry aEntry; 149 150 if( aUpdateInfoEnumeration->nextElement() >>= aEntry ) 151 { 152 uno::Reference< xml::dom::XNode > xNode( aEntry.UpdateDocument.get() ); 153 uno::Reference< xml::dom::XNodeList > xNodeList; 154 try { 155 xNodeList = xXPath->selectNodeList(xNode, aXPathExpression 156 + UNISTRING("/inst:update/attribute::src")); 157 } catch (css::xml::xpath::XPathException &) { 158 // ignore 159 } 160 161 /* 162 o_rUpdateInfo.Sources.push_back( DownloadSource(true, 163 UNISTRING("http://openoffice.bouncer.osuosl.org/?product=OpenOffice.org&os=solarissparcwjre&lang=en-US&version=2.2.1") ) ); 164 */ 165 166 // xNodeList may be null if selectNodeList() above threw and was swallowed 167 sal_Int32 i, imax = xNodeList.is() ? xNodeList->getLength() : 0; 168 for( i = 0; i < imax; ++i ) 169 { 170 uno::Reference< xml::dom::XNode > xNode2( xNodeList->item(i) ); 171 172 if( xNode2.is() ) 173 { 174 uno::Reference< xml::dom::XElement > xParent(xNode2->getParentNode(), uno::UNO_QUERY_THROW); 175 rtl::OUString aType = xParent->getAttribute(UNISTRING("type")); 176 bool bIsDirect = ( sal_False == aType.equalsIgnoreAsciiCaseAscii("text/html") ); 177 178 o_rUpdateInfo.Sources.push_back( DownloadSource(bIsDirect, xNode2->getNodeValue()) ); 179 } 180 } 181 182 uno::Reference< xml::dom::XNode > xNode2; 183 try { 184 xNode2 = xXPath->selectSingleNode(xNode, aXPathExpression 185 + UNISTRING("/inst:version/text()")); 186 } catch (css::xml::xpath::XPathException &) { 187 // ignore 188 } 189 190 if( xNode2.is() ) 191 o_rUpdateInfo.Version = xNode2->getNodeValue(); 192 193 try { 194 xNode2 = xXPath->selectSingleNode(xNode, aXPathExpression 195 + UNISTRING("/inst:buildid/text()")); 196 } catch (css::xml::xpath::XPathException &) { 197 // ignore 198 } 199 200 if( xNode2.is() ) 201 o_rUpdateInfo.BuildId = xNode2->getNodeValue(); 202 203 o_rUpdateInfo.Description = aEntry.Description; 204 205 // Release Notes 206 // reset, so a swallowed exception below does not leave us 207 // iterating the previous (sources) node list 208 xNodeList.clear(); 209 try { 210 xNodeList = xXPath->selectNodeList(xNode, aXPathExpression 211 + UNISTRING("/inst:relnote")); 212 } catch (css::xml::xpath::XPathException &) { 213 // ignore 214 } 215 imax = xNodeList.is() ? xNodeList->getLength() : 0; 216 for( i = 0; i < imax; ++i ) 217 { 218 uno::Reference< xml::dom::XElement > xRelNote(xNodeList->item(i), uno::UNO_QUERY); 219 if( xRelNote.is() ) 220 { 221 sal_Int32 pos = xRelNote->getAttribute(UNISTRING("pos")).toInt32(); 222 223 ReleaseNote aRelNote((sal_uInt8) pos, xRelNote->getAttribute(UNISTRING("src"))); 224 225 if( xRelNote->hasAttribute(UNISTRING("src2")) ) 226 { 227 pos = xRelNote->getAttribute(UNISTRING("pos2")).toInt32(); 228 aRelNote.Pos2 = (sal_Int8) pos; 229 aRelNote.URL2 = xRelNote->getAttribute(UNISTRING("src2")); 230 } 231 232 o_rUpdateInfo.ReleaseNotes.push_back(aRelNote); 233 } 234 } 235 /* 236 o_rUpdateInfo.ReleaseNotes.push_back( 237 ReleaseNote(1, UNISTRING("http://qa.openoffice.org/tests/online_update_test.html")) 238 ); 239 */ 240 241 if( o_rUpdateInfo.Sources.size() > 0 ) 242 return true; 243 } 244 } 245 } 246 catch( ... ) 247 { 248 return false; 249 } 250 251 return true; 252 } 253 254 //------------------------------------------------------------------------------ 255 bool storeExtensionUpdateInfos( const uno::Reference< uno::XComponentContext > & rxContext, 256 const uno::Sequence< uno::Sequence< rtl::OUString > > &rUpdateInfos ) 257 { 258 bool bNotify = false; 259 260 if ( rUpdateInfos.hasElements() ) 261 { 262 rtl::Reference< UpdateCheckConfig > aConfig = UpdateCheckConfig::get( rxContext ); 263 264 for ( sal_Int32 i = rUpdateInfos.getLength() - 1; i >= 0; i-- ) 265 { 266 bNotify |= aConfig->storeExtensionVersion( rUpdateInfos[i][0], rUpdateInfos[i][1] ); 267 } 268 } 269 return bNotify; 270 } 271 272 //------------------------------------------------------------------------------ 273 // Returns 'true' if there are updates for any extension 274 275 bool checkForExtensionUpdates( const uno::Reference< uno::XComponentContext > & rxContext ) 276 { 277 uno::Sequence< uno::Sequence< rtl::OUString > > aUpdateList; 278 279 uno::Reference< deployment::XPackageInformationProvider > xInfoProvider; 280 try 281 { 282 uno::Any aValue( rxContext->getValueByName( 283 UNISTRING( "/singletons/com.sun.star.deployment.PackageInformationProvider" ) ) ); 284 OSL_VERIFY( aValue >>= xInfoProvider ); 285 } 286 catch( const uno::Exception& ) 287 { 288 OSL_ENSURE( false, "checkForExtensionUpdates: could not create the PackageInformationProvider!" ); 289 } 290 291 if ( !xInfoProvider.is() ) return false; 292 293 aUpdateList = xInfoProvider->isUpdateAvailable( ::rtl::OUString() ); 294 bool bNotify = storeExtensionUpdateInfos( rxContext, aUpdateList ); 295 296 return bNotify; 297 } 298 299 //------------------------------------------------------------------------------ 300 // Returns 'true' if there are any pending updates for any extension (offline check) 301 302 bool checkForPendingUpdates( const uno::Reference< uno::XComponentContext > & rxContext ) 303 { 304 uno::Sequence< uno::Sequence< rtl::OUString > > aExtensionList; 305 uno::Reference< deployment::XPackageInformationProvider > xInfoProvider; 306 try 307 { 308 uno::Any aValue( rxContext->getValueByName( 309 UNISTRING( "/singletons/com.sun.star.deployment.PackageInformationProvider" ) ) ); 310 OSL_VERIFY( aValue >>= xInfoProvider ); 311 } 312 catch( const uno::Exception& ) 313 { 314 OSL_ENSURE( false, "checkForExtensionUpdates: could not create the PackageInformationProvider!" ); 315 } 316 317 if ( !xInfoProvider.is() ) return false; 318 319 bool bPendingUpdateFound = false; 320 321 aExtensionList = xInfoProvider->getExtensionList(); 322 if ( aExtensionList.hasElements() ) 323 { 324 rtl::Reference< UpdateCheckConfig > aConfig = UpdateCheckConfig::get( rxContext ); 325 326 for ( sal_Int32 i = aExtensionList.getLength() - 1; i >= 0; i-- ) 327 { 328 bPendingUpdateFound = aConfig->checkExtensionVersion( aExtensionList[i][0], aExtensionList[i][1] ); 329 if ( bPendingUpdateFound ) 330 break; 331 } 332 } 333 334 return bPendingUpdateFound; 335 } 336