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