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
getBootstrapData(uno::Sequence<::rtl::OUString> & rRepositoryList,::rtl::OUString & rBuildID,::rtl::OUString & rInstallSetID)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
checkForUpdates(UpdateInfo & o_rUpdateInfo,uno::Reference<uno::XComponentContext> const & rxContext,uno::Reference<task::XInteractionHandler> const & rxInteractionHandler,const uno::Reference<deployment::XUpdateInformationProvider> & rUpdateInfoProvider)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 //------------------------------------------------------------------------------
storeExtensionUpdateInfos(const uno::Reference<uno::XComponentContext> & rxContext,const uno::Sequence<uno::Sequence<rtl::OUString>> & rUpdateInfos)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
checkForExtensionUpdates(const uno::Reference<uno::XComponentContext> & rxContext)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
checkForPendingUpdates(const uno::Reference<uno::XComponentContext> & rxContext)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