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_extensions.hxx"
30 
31 #include <memory>
32 
33 #include "updatecheck.hxx"
34 #include "updatecheckconfig.hxx"
35 #include "updatehdl.hxx"
36 #include "updateprotocol.hxx"
37 
38 #include <cppuhelper/implbase3.hxx>
39 #include <cppuhelper/implementationentry.hxx>
40 
41 #include "com/sun/star/frame/XDesktop.hpp"
42 #include "com/sun/star/frame/XTerminateListener.hpp"
43 #include <com/sun/star/task/XJob.hpp>
44 
45 namespace beans = com::sun::star::beans ;
46 namespace frame = com::sun::star::frame ;
47 namespace lang = com::sun::star::lang ;
48 namespace task = com::sun::star::task ;
49 namespace uno = com::sun::star::uno ;
50 
51 #define UNISTRING(s) rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(s))
52 
53 namespace
54 {
55 
56 class InitUpdateCheckJobThread : public osl::Thread
57 {
58 public:
59     InitUpdateCheckJobThread( const uno::Reference< uno::XComponentContext > &xContext,
60                               const uno::Sequence< beans::NamedValue > &xParameters,
61                               bool bShowDialog );
62 
63     virtual void SAL_CALL run();
64 
65     void    setTerminating();
66 
67 private:
68     osl::Condition m_aCondition;
69     uno::Reference<uno::XComponentContext> m_xContext;
70     uno::Sequence<beans::NamedValue> m_xParameters;
71     bool m_bShowDialog;
72     bool m_bTerminating;
73 };
74 
75 class UpdateCheckJob :
76     public ::cppu::WeakImplHelper3< task::XJob, lang::XServiceInfo, frame::XTerminateListener >
77 {
78     virtual ~UpdateCheckJob();
79 
80 public:
81 
82     UpdateCheckJob(const uno::Reference<uno::XComponentContext>& xContext);
83 
84     static uno::Sequence< rtl::OUString > getServiceNames();
85     static rtl::OUString getImplName();
86 
87     // Allows runtime exceptions to be thrown by const methods
88     inline SAL_CALL operator uno::Reference< uno::XInterface > () const
89         { return const_cast< cppu::OWeakObject * > (static_cast< cppu::OWeakObject const * > (this)); };
90 
91     // XJob
92     virtual uno::Any SAL_CALL execute(const uno::Sequence<beans::NamedValue>&)
93         throw (lang::IllegalArgumentException, uno::Exception);
94 
95     // XServiceInfo
96     virtual rtl::OUString SAL_CALL getImplementationName()
97         throw (uno::RuntimeException);
98     virtual sal_Bool SAL_CALL supportsService(rtl::OUString const & serviceName)
99         throw (uno::RuntimeException);
100     virtual uno::Sequence< rtl::OUString > SAL_CALL getSupportedServiceNames()
101         throw (uno::RuntimeException);
102 
103     // XEventListener
104     virtual void SAL_CALL disposing( ::com::sun::star::lang::EventObject const & evt )
105         throw (::com::sun::star::uno::RuntimeException);
106 
107     // XTerminateListener
108     virtual void SAL_CALL queryTermination( lang::EventObject const & evt )
109         throw ( frame::TerminationVetoException, uno::RuntimeException );
110     virtual void SAL_CALL notifyTermination( lang::EventObject const & evt )
111         throw ( uno::RuntimeException );
112 
113 private:
114     uno::Reference<uno::XComponentContext>  m_xContext;
115     uno::Reference< frame::XDesktop >       m_xDesktop;
116     std::auto_ptr< InitUpdateCheckJobThread > m_pInitThread;
117 
118     void handleExtensionUpdates( const uno::Sequence< beans::NamedValue > &rListProp );
119 };
120 
121 //------------------------------------------------------------------------------
122 //------------------------------------------------------------------------------
123 //------------------------------------------------------------------------------
124 InitUpdateCheckJobThread::InitUpdateCheckJobThread(
125             const uno::Reference< uno::XComponentContext > &xContext,
126             const uno::Sequence< beans::NamedValue > &xParameters,
127             bool bShowDialog ) :
128     m_xContext( xContext ),
129     m_xParameters( xParameters ),
130     m_bShowDialog( bShowDialog ),
131     m_bTerminating( false )
132 {
133     create();
134 }
135 
136 //------------------------------------------------------------------------------
137 void SAL_CALL InitUpdateCheckJobThread::run()
138 {
139     if (!m_bShowDialog) {
140         TimeValue tv = { 25, 0 };
141         m_aCondition.wait( &tv );
142         if ( m_bTerminating )
143             return;
144     }
145 
146     rtl::Reference< UpdateCheck > aController( UpdateCheck::get() );
147     aController->initialize( m_xParameters, m_xContext );
148 
149     if ( m_bShowDialog )
150         aController->showDialog( true );
151 }
152 
153 void InitUpdateCheckJobThread::setTerminating() {
154     m_bTerminating = true;
155     m_aCondition.set();
156 }
157 
158 //------------------------------------------------------------------------------
159 //------------------------------------------------------------------------------
160 //------------------------------------------------------------------------------
161 
162 UpdateCheckJob::UpdateCheckJob( const uno::Reference<uno::XComponentContext>& xContext ) :
163     m_xContext(xContext)
164 {
165     m_xDesktop.set( xContext->getServiceManager()->createInstanceWithContext( UNISTRING("com.sun.star.frame.Desktop"), xContext ), uno::UNO_QUERY );
166     if ( m_xDesktop.is() )
167         m_xDesktop->addTerminateListener( this );
168 }
169 
170 //------------------------------------------------------------------------------
171 
172 UpdateCheckJob::~UpdateCheckJob()
173 {
174 }
175 
176 //------------------------------------------------------------------------------
177 
178 uno::Sequence< rtl::OUString >
179 UpdateCheckJob::getServiceNames()
180 {
181     uno::Sequence< rtl::OUString > aServiceList(1);
182     aServiceList[0] = UNISTRING( "com.sun.star.setup.UpdateCheck");
183     return aServiceList;
184 };
185 
186 //------------------------------------------------------------------------------
187 
188 rtl::OUString
189 UpdateCheckJob::getImplName()
190 {
191     return UNISTRING( "vnd.sun.UpdateCheck");
192 }
193 
194 
195 //------------------------------------------------------------------------------
196 
197 uno::Any
198 UpdateCheckJob::execute(const uno::Sequence<beans::NamedValue>& namedValues)
199     throw (lang::IllegalArgumentException, uno::Exception)
200 {
201     for ( sal_Int32 n=namedValues.getLength(); n-- > 0; )
202     {
203         if ( namedValues[ n ].Name.equalsAscii( "DynamicData" ) )
204         {
205             uno::Sequence<beans::NamedValue> aListProp;
206             if ( namedValues[n].Value >>= aListProp )
207             {
208                 for ( sal_Int32 i=aListProp.getLength(); i-- > 0; )
209                 {
210                     if ( aListProp[ i ].Name.equalsAscii( "updateList" ) )
211                     {
212                         handleExtensionUpdates( aListProp );
213                         return uno::Any();
214                     }
215                 }
216             }
217         }
218     }
219 
220     uno::Sequence<beans::NamedValue> aConfig =
221         getValue< uno::Sequence<beans::NamedValue> > (namedValues, "JobConfig");
222 
223     /* Determine the way we got invoked here -
224      * see Developers Guide Chapter "4.7.2 Jobs" to understand the magic
225      */
226 
227     uno::Sequence<beans::NamedValue> aEnvironment =
228         getValue< uno::Sequence<beans::NamedValue> > (namedValues, "Environment");
229 
230     rtl::OUString aEventName = getValue< rtl::OUString > (aEnvironment, "EventName");
231 
232     m_pInitThread.reset(
233         new InitUpdateCheckJobThread(
234             m_xContext, aConfig,
235             !aEventName.equalsAscii("onFirstVisibleTask")));
236 
237     return uno::Any();
238 }
239 
240 //------------------------------------------------------------------------------
241 void UpdateCheckJob::handleExtensionUpdates( const uno::Sequence< beans::NamedValue > &rListProp )
242 {
243     try {
244         uno::Sequence< uno::Sequence< rtl::OUString > > aList =
245             getValue< uno::Sequence< uno::Sequence< rtl::OUString > > > ( rListProp, "updateList" );
246         bool bPrepareOnly = getValue< bool > ( rListProp, "prepareOnly" );
247 
248         // we will first store any new found updates and then check, if there are any
249         // pending updates.
250         storeExtensionUpdateInfos( m_xContext, aList );
251 
252         if ( bPrepareOnly )
253             return;
254 
255         bool bHasUpdates = checkForPendingUpdates( m_xContext );
256 
257         rtl::Reference<UpdateCheck> aController( UpdateCheck::get() );
258         if ( ! aController.is() )
259             return;
260 
261         aController->setHasExtensionUpdates( bHasUpdates );
262 
263         if ( ! aController->hasOfficeUpdate() )
264         {
265             if ( bHasUpdates )
266                 aController->setUIState( UPDATESTATE_EXT_UPD_AVAIL, true );
267             else
268                 aController->setUIState( UPDATESTATE_NO_UPDATE_AVAIL, true );
269         }
270     }
271     catch( const uno::Exception& e )
272     {
273          OSL_TRACE( "Caught exception: %s\n thread terminated.\n",
274             rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr());
275     }
276 }
277 
278 //------------------------------------------------------------------------------
279 
280 rtl::OUString SAL_CALL
281 UpdateCheckJob::getImplementationName() throw (uno::RuntimeException)
282 {
283     return getImplName();
284 }
285 
286 //------------------------------------------------------------------------------
287 
288 uno::Sequence< rtl::OUString > SAL_CALL
289 UpdateCheckJob::getSupportedServiceNames() throw (uno::RuntimeException)
290 {
291     return getServiceNames();
292 }
293 
294 //------------------------------------------------------------------------------
295 
296 sal_Bool SAL_CALL
297 UpdateCheckJob::supportsService( rtl::OUString const & serviceName ) throw (uno::RuntimeException)
298 {
299     uno::Sequence< rtl::OUString > aServiceNameList = getServiceNames();
300 
301     for( sal_Int32 n=0; n < aServiceNameList.getLength(); n++ )
302         if( aServiceNameList[n].equals(serviceName) )
303             return sal_True;
304 
305     return sal_False;
306 }
307 
308 //------------------------------------------------------------------------------
309 // XEventListener
310 void SAL_CALL UpdateCheckJob::disposing( lang::EventObject const & rEvt )
311     throw ( uno::RuntimeException )
312 {
313     bool shutDown = ( rEvt.Source == m_xDesktop );
314 
315     if ( shutDown && m_xDesktop.is() )
316     {
317         m_xDesktop->removeTerminateListener( this );
318         m_xDesktop.clear();
319     }
320 }
321 
322 //------------------------------------------------------------------------------
323 // XTerminateListener
324 void SAL_CALL UpdateCheckJob::queryTermination( lang::EventObject const & )
325     throw ( frame::TerminationVetoException, uno::RuntimeException )
326 {
327 }
328 
329 //------------------------------------------------------------------------------
330 void SAL_CALL UpdateCheckJob::notifyTermination( lang::EventObject const & )
331     throw ( uno::RuntimeException )
332 {
333     if ( m_pInitThread.get() != 0 )
334     {
335         m_pInitThread->setTerminating();
336         m_pInitThread->join();
337     }
338 }
339 
340 } // anonymous namespace
341 
342 //------------------------------------------------------------------------------
343 
344 static uno::Reference<uno::XInterface> SAL_CALL
345 createJobInstance(const uno::Reference<uno::XComponentContext>& xContext)
346 {
347     return *new UpdateCheckJob(xContext);
348 }
349 
350 //------------------------------------------------------------------------------
351 
352 static uno::Reference<uno::XInterface> SAL_CALL
353 createConfigInstance(const uno::Reference<uno::XComponentContext>& xContext)
354 {
355     return *UpdateCheckConfig::get(xContext, *UpdateCheck::get());
356 }
357 
358 //------------------------------------------------------------------------------
359 
360 static const cppu::ImplementationEntry kImplementations_entries[] =
361 {
362     {
363         createJobInstance,
364         UpdateCheckJob::getImplName,
365         UpdateCheckJob::getServiceNames,
366         cppu::createSingleComponentFactory,
367         NULL,
368         0
369     },
370     {
371         createConfigInstance,
372         UpdateCheckConfig::getImplName,
373         UpdateCheckConfig::getServiceNames,
374         cppu::createSingleComponentFactory,
375         NULL,
376         0
377     },
378 	{ NULL, NULL, NULL, NULL, NULL, 0 }
379 } ;
380 
381 //------------------------------------------------------------------------------
382 
383 extern "C" void SAL_CALL
384 component_getImplementationEnvironment( const sal_Char **aEnvTypeName, uno_Environment **)
385 {
386     *aEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME ;
387 }
388 
389 //------------------------------------------------------------------------------
390 
391 extern "C" void *
392 component_getFactory(const sal_Char *pszImplementationName, void *pServiceManager, void *pRegistryKey)
393 {
394     return cppu::component_getFactoryHelper(
395         pszImplementationName,
396         pServiceManager,
397         pRegistryKey,
398         kImplementations_entries) ;
399 }
400