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 sal_Int32 i, imax = xNodeList->getLength();
167 for( i = 0; i < imax; ++i )
168 {
169 uno::Reference< xml::dom::XNode > xNode2( xNodeList->item(i) );
170
171 if( xNode2.is() )
172 {
173 uno::Reference< xml::dom::XElement > xParent(xNode2->getParentNode(), uno::UNO_QUERY_THROW);
174 rtl::OUString aType = xParent->getAttribute(UNISTRING("type"));
175 bool bIsDirect = ( sal_False == aType.equalsIgnoreAsciiCaseAscii("text/html") );
176
177 o_rUpdateInfo.Sources.push_back( DownloadSource(bIsDirect, xNode2->getNodeValue()) );
178 }
179 }
180
181 uno::Reference< xml::dom::XNode > xNode2;
182 try {
183 xNode2 = xXPath->selectSingleNode(xNode, aXPathExpression
184 + UNISTRING("/inst:version/text()"));
185 } catch (css::xml::xpath::XPathException &) {
186 // ignore
187 }
188
189 if( xNode2.is() )
190 o_rUpdateInfo.Version = xNode2->getNodeValue();
191
192 try {
193 xNode2 = xXPath->selectSingleNode(xNode, aXPathExpression
194 + UNISTRING("/inst:buildid/text()"));
195 } catch (css::xml::xpath::XPathException &) {
196 // ignore
197 }
198
199 if( xNode2.is() )
200 o_rUpdateInfo.BuildId = xNode2->getNodeValue();
201
202 o_rUpdateInfo.Description = aEntry.Description;
203
204 // Release Notes
205 try {
206 xNodeList = xXPath->selectNodeList(xNode, aXPathExpression
207 + UNISTRING("/inst:relnote"));
208 } catch (css::xml::xpath::XPathException &) {
209 // ignore
210 }
211 imax = xNodeList->getLength();
212 for( i = 0; i < imax; ++i )
213 {
214 uno::Reference< xml::dom::XElement > xRelNote(xNodeList->item(i), uno::UNO_QUERY);
215 if( xRelNote.is() )
216 {
217 sal_Int32 pos = xRelNote->getAttribute(UNISTRING("pos")).toInt32();
218
219 ReleaseNote aRelNote((sal_uInt8) pos, xRelNote->getAttribute(UNISTRING("src")));
220
221 if( xRelNote->hasAttribute(UNISTRING("src2")) )
222 {
223 pos = xRelNote->getAttribute(UNISTRING("pos2")).toInt32();
224 aRelNote.Pos2 = (sal_Int8) pos;
225 aRelNote.URL2 = xRelNote->getAttribute(UNISTRING("src2"));
226 }
227
228 o_rUpdateInfo.ReleaseNotes.push_back(aRelNote);
229 }
230 }
231 /*
232 o_rUpdateInfo.ReleaseNotes.push_back(
233 ReleaseNote(1, UNISTRING("http://qa.openoffice.org/tests/online_update_test.html"))
234 );
235 */
236
237 if( o_rUpdateInfo.Sources.size() > 0 )
238 return true;
239 }
240 }
241 }
242 catch( ... )
243 {
244 return false;
245 }
246
247 return true;
248 }
249
250 //------------------------------------------------------------------------------
storeExtensionUpdateInfos(const uno::Reference<uno::XComponentContext> & rxContext,const uno::Sequence<uno::Sequence<rtl::OUString>> & rUpdateInfos)251 bool storeExtensionUpdateInfos( const uno::Reference< uno::XComponentContext > & rxContext,
252 const uno::Sequence< uno::Sequence< rtl::OUString > > &rUpdateInfos )
253 {
254 bool bNotify = false;
255
256 if ( rUpdateInfos.hasElements() )
257 {
258 rtl::Reference< UpdateCheckConfig > aConfig = UpdateCheckConfig::get( rxContext );
259
260 for ( sal_Int32 i = rUpdateInfos.getLength() - 1; i >= 0; i-- )
261 {
262 bNotify |= aConfig->storeExtensionVersion( rUpdateInfos[i][0], rUpdateInfos[i][1] );
263 }
264 }
265 return bNotify;
266 }
267
268 //------------------------------------------------------------------------------
269 // Returns 'true' if there are updates for any extension
270
checkForExtensionUpdates(const uno::Reference<uno::XComponentContext> & rxContext)271 bool checkForExtensionUpdates( const uno::Reference< uno::XComponentContext > & rxContext )
272 {
273 uno::Sequence< uno::Sequence< rtl::OUString > > aUpdateList;
274
275 uno::Reference< deployment::XPackageInformationProvider > xInfoProvider;
276 try
277 {
278 uno::Any aValue( rxContext->getValueByName(
279 UNISTRING( "/singletons/com.sun.star.deployment.PackageInformationProvider" ) ) );
280 OSL_VERIFY( aValue >>= xInfoProvider );
281 }
282 catch( const uno::Exception& )
283 {
284 OSL_ENSURE( false, "checkForExtensionUpdates: could not create the PackageInformationProvider!" );
285 }
286
287 if ( !xInfoProvider.is() ) return false;
288
289 aUpdateList = xInfoProvider->isUpdateAvailable( ::rtl::OUString() );
290 bool bNotify = storeExtensionUpdateInfos( rxContext, aUpdateList );
291
292 return bNotify;
293 }
294
295 //------------------------------------------------------------------------------
296 // Returns 'true' if there are any pending updates for any extension (offline check)
297
checkForPendingUpdates(const uno::Reference<uno::XComponentContext> & rxContext)298 bool checkForPendingUpdates( const uno::Reference< uno::XComponentContext > & rxContext )
299 {
300 uno::Sequence< uno::Sequence< rtl::OUString > > aExtensionList;
301 uno::Reference< deployment::XPackageInformationProvider > xInfoProvider;
302 try
303 {
304 uno::Any aValue( rxContext->getValueByName(
305 UNISTRING( "/singletons/com.sun.star.deployment.PackageInformationProvider" ) ) );
306 OSL_VERIFY( aValue >>= xInfoProvider );
307 }
308 catch( const uno::Exception& )
309 {
310 OSL_ENSURE( false, "checkForExtensionUpdates: could not create the PackageInformationProvider!" );
311 }
312
313 if ( !xInfoProvider.is() ) return false;
314
315 bool bPendingUpdateFound = false;
316
317 aExtensionList = xInfoProvider->getExtensionList();
318 if ( aExtensionList.hasElements() )
319 {
320 rtl::Reference< UpdateCheckConfig > aConfig = UpdateCheckConfig::get( rxContext );
321
322 for ( sal_Int32 i = aExtensionList.getLength() - 1; i >= 0; i-- )
323 {
324 bPendingUpdateFound = aConfig->checkExtensionVersion( aExtensionList[i][0], aExtensionList[i][1] );
325 if ( bPendingUpdateFound )
326 break;
327 }
328 }
329
330 return bPendingUpdateFound;
331 }
332