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 
28 #include "updatecheckconfig.hxx"
29 #include <com/sun/star/beans/PropertyValue.hpp>
30 #include <com/sun/star/beans/XPropertyState.hpp>
31 #include <com/sun/star/beans/XPropertySet.hpp>
32 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
33 
34 #include <osl/security.hxx>
35 #include <osl/time.h>
36 #include <osl/file.hxx>
37 
38 #ifdef WNT
39 #ifdef _MSC_VER
40 #pragma warning(push,1) // disable warnings within system headers
41 #pragma warning(disable: 4917)
42 #endif
43 #include <shlobj.h>
44 #ifdef _MSC_VER
45 #pragma warning(pop)
46 #endif
47 #endif
48 
49 namespace container = com::sun::star::container ;
50 namespace beans = com::sun::star::beans ;
51 namespace lang = com::sun::star::lang ;
52 namespace util = com::sun::star::util ;
53 namespace uno = com::sun::star::uno ;
54 
55 #define UNISTRING(s) rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(s))
56 
57 #define LAST_CHECK              "LastCheck"
58 #define VERSION_FOUND           "UpdateVersionFound"
59 #define UPDATE_VERSION          "UpdateVersion"
60 #define UPDATE_BUILDID          "UpdateBuildId"
61 #define UPDATE_DESCRIPTION      "UpdateDescription"
62 #define DOWNLOAD_URL            "DownloadURL"
63 #define IS_DIRECT_DOWNLOAD      "IsDirectDownload"
64 #define OLD_VERSION             "UpdateFoundFor"
65 #define AUTOCHECK_ENABLED       "AutoCheckEnabled"
66 #define AUTODOWNLOAD_ENABLED    "AutoDownloadEnabled"
67 #define CHECK_INTERVAL          "CheckInterval"
68 #define LOCAL_FILE              "LocalFile"
69 #define DOWNLOAD_SIZE           "DownloadSize"
70 #define DOWNLOAD_PAUSED         "DownloadPaused"
71 #define DOWNLOAD_DESTINATION    "DownloadDestination"
72 #define RELEASE_NOTE            "ReleaseNote"
73 #define EXTENSION_PREFIX        "Extension_"
74 
75 #define PROPERTY_VERSION        UNISTRING("Version")
76 
77 static const sal_Char * const aUpdateEntryProperties[] = {
78     UPDATE_VERSION,
79     UPDATE_BUILDID,
80     UPDATE_DESCRIPTION,
81     DOWNLOAD_URL,
82     IS_DIRECT_DOWNLOAD,
83     RELEASE_NOTE"1",
84     RELEASE_NOTE"2",
85     RELEASE_NOTE"3",
86     RELEASE_NOTE"4",
87     RELEASE_NOTE"5",
88     OLD_VERSION
89 };
90 
91 static const sal_uInt32 nUpdateEntryProperties = sizeof(aUpdateEntryProperties) / sizeof(sal_Char *);
92 
93 //------------------------------------------------------------------------------
94 
~NamedValueByNameAccess()95 NamedValueByNameAccess::~NamedValueByNameAccess()
96 {
97 }
98 
99 //------------------------------------------------------------------------------
100 
101 ::com::sun::star::uno::Any
getValue(const sal_Char * pName)102 NamedValueByNameAccess::getValue(const sal_Char * pName)
103 {
104     const sal_Int32 nLen = m_rValues.getLength();
105     for( sal_Int32 n=0; n < nLen; ++n )
106     {
107         if( m_rValues[n].Name.equalsAscii( pName ) )
108             return m_rValues[n].Value;
109     }
110     return ::com::sun::star::uno::Any();
111 }
112 
113 
114 //------------------------------------------------------------------------------
115 
116 bool
isAutoCheckEnabled() const117 UpdateCheckROModel::isAutoCheckEnabled() const
118 {
119     return sal_True == m_aNameAccess.getValue(AUTOCHECK_ENABLED).get< sal_Bool >();
120 }
121 
122 //------------------------------------------------------------------------------
123 
124 bool
isDownloadPaused() const125 UpdateCheckROModel::isDownloadPaused() const
126 {
127     return sal_True == m_aNameAccess.getValue(DOWNLOAD_PAUSED).get< sal_Bool >();
128 }
129 
130 //------------------------------------------------------------------------------
131 
132 rtl::OUString
getStringValue(const sal_Char * pStr) const133 UpdateCheckROModel::getStringValue(const sal_Char * pStr) const
134 {
135     uno::Any aAny( m_aNameAccess.getValue(pStr) );
136     rtl::OUString aRet;
137 
138     aAny >>= aRet;
139 
140     return aRet;
141 }
142 
143 //------------------------------------------------------------------------------
144 
getLocalFileName() const145 rtl::OUString UpdateCheckROModel::getLocalFileName() const
146 {
147     return getStringValue(LOCAL_FILE);
148 };
149 
150 //------------------------------------------------------------------------------
151 
getDownloadSize() const152 sal_Int64 UpdateCheckROModel::getDownloadSize() const
153 {
154     uno::Any aAny( m_aNameAccess.getValue(DOWNLOAD_SIZE) );
155     sal_Int64 nRet = -1;
156 
157     aAny >>= nRet;
158     return nRet;
159 };
160 
161 //------------------------------------------------------------------------------
162 
163 rtl::OUString
getUpdateEntryVersion() const164 UpdateCheckROModel::getUpdateEntryVersion() const
165 {
166     return getStringValue(OLD_VERSION);
167 }
168 
169 //------------------------------------------------------------------------------
170 
171 void
getUpdateEntry(UpdateInfo & rInfo) const172 UpdateCheckROModel::getUpdateEntry(UpdateInfo& rInfo) const
173 {
174     rInfo.BuildId = getStringValue(UPDATE_BUILDID);
175     rInfo.Version = getStringValue(UPDATE_VERSION);
176     rInfo.Description = getStringValue(UPDATE_DESCRIPTION);
177 
178     sal_Bool isDirectDownload = sal_False;
179     m_aNameAccess.getValue(IS_DIRECT_DOWNLOAD) >>= isDirectDownload;
180 
181     rInfo.Sources.push_back( DownloadSource( isDirectDownload, getStringValue(DOWNLOAD_URL) ) );
182 
183     rtl::OString aStr(RELEASE_NOTE);
184     for(sal_Int32 n=1; n < 6; ++n )
185     {
186         rtl::OUString aUStr = getStringValue( (aStr + rtl::OString::valueOf(n)).getStr());
187         if( aUStr.getLength() > 0 )
188             rInfo.ReleaseNotes.push_back(ReleaseNote((sal_Int8) n, aUStr));
189     }
190 }
191 
192 
193 //------------------------------------------------------------------------------
194 
getDesktopDirectory()195 rtl::OUString UpdateCheckConfig::getDesktopDirectory()
196 {
197     rtl::OUString aRet;
198 
199 #ifdef WNT
200     WCHAR szPath[MAX_PATH];
201 
202     if( ! FAILED( SHGetSpecialFolderPathW( NULL, szPath, CSIDL_DESKTOPDIRECTORY, true ) ) )
203     {
204         aRet = rtl::OUString( reinterpret_cast< sal_Unicode * >(szPath) );
205         osl::FileBase::getFileURLFromSystemPath( aRet, aRet );
206     }
207 #else
208     // This should become a desktop specific setting in some system backend ..
209     rtl::OUString aHomeDir;
210     osl::Security().getHomeDir( aHomeDir );
211     aRet = aHomeDir + rtl::OUString::createFromAscii("/Desktop");
212 
213     // Set path to home directory when there is no /Desktop directory
214     osl::Directory aDocumentsDir( aRet );
215     if( osl::FileBase::E_None != aDocumentsDir.open() )
216         aRet = aHomeDir;
217 #endif
218 
219     return aRet;
220 }
221 
222 //------------------------------------------------------------------------------
223 
getAllUsersDirectory()224 rtl::OUString UpdateCheckConfig::getAllUsersDirectory()
225 {
226     rtl::OUString aRet;
227 
228 #ifdef WNT
229     WCHAR szPath[MAX_PATH];
230 
231     if( ! FAILED( SHGetSpecialFolderPathW( NULL, szPath, CSIDL_COMMON_DOCUMENTS, true ) ) )
232     {
233         aRet = rtl::OUString( reinterpret_cast< sal_Unicode * >(szPath) );
234         osl::FileBase::RC rc;
235         rc = osl::FileBase::getFileURLFromSystemPath( aRet, aRet );
236     }
237 #else
238     osl::FileBase::getTempDirURL(aRet);
239 #endif
240 
241     return aRet;
242 }
243 
244 //------------------------------------------------------------------------------
UpdateCheckConfig(const uno::Reference<container::XNameContainer> & xContainer,const uno::Reference<container::XNameContainer> & xAvailableUpdates,const uno::Reference<container::XNameContainer> & xIgnoredUpdates,const::rtl::Reference<UpdateCheckConfigListener> & rListener)245 UpdateCheckConfig::UpdateCheckConfig( const uno::Reference<container::XNameContainer>& xContainer,
246                                       const uno::Reference<container::XNameContainer>& xAvailableUpdates,
247                                       const uno::Reference<container::XNameContainer>& xIgnoredUpdates,
248                                       const ::rtl::Reference< UpdateCheckConfigListener >& rListener ) :
249     m_xContainer( xContainer ),
250     m_xAvailableUpdates( xAvailableUpdates ),
251     m_xIgnoredUpdates( xIgnoredUpdates ),
252     m_rListener( rListener )
253 {}
254 
255 //------------------------------------------------------------------------------
~UpdateCheckConfig()256 UpdateCheckConfig::~UpdateCheckConfig()
257 {}
258 
259 //------------------------------------------------------------------------------
260 
261 ::rtl::Reference< UpdateCheckConfig >
get(const uno::Reference<uno::XComponentContext> & xContext,const::rtl::Reference<UpdateCheckConfigListener> & rListener)262 UpdateCheckConfig::get(
263     const uno::Reference<uno::XComponentContext>& xContext,
264     const ::rtl::Reference< UpdateCheckConfigListener >& rListener)
265 {
266     if( !xContext.is() )
267         throw uno::RuntimeException(
268             UNISTRING( "UpdateCheckConfig: empty component context" ),
269             uno::Reference< uno::XInterface >() );
270 
271     uno::Reference< lang::XMultiComponentFactory > xServiceManager(xContext->getServiceManager());
272 
273     if( !xServiceManager.is() )
274         throw uno::RuntimeException(
275             UNISTRING( "UpdateCheckConfig: unable to obtain service manager from component context" ),
276             uno::Reference< uno::XInterface >() );
277 
278     uno::Reference< lang::XMultiServiceFactory > xConfigProvider(
279         xServiceManager->createInstanceWithContext( UNISTRING( "com.sun.star.configuration.ConfigurationProvider" ), xContext ),
280         uno::UNO_QUERY_THROW);
281 
282     beans::PropertyValue aProperty;
283     aProperty.Name  = UNISTRING( "nodepath" );
284     aProperty.Value = uno::makeAny( UNISTRING("org.openoffice.Office.Jobs/Jobs/UpdateCheck/Arguments") );
285 
286     uno::Sequence< uno::Any > aArgumentList( 1 );
287     aArgumentList[0] = uno::makeAny( aProperty );
288 
289     uno::Reference< container::XNameContainer > xContainer(
290         xConfigProvider->createInstanceWithArguments(
291             UNISTRING("com.sun.star.configuration.ConfigurationUpdateAccess"), aArgumentList ),
292         uno::UNO_QUERY_THROW );
293 
294     aProperty.Value = uno::makeAny( UNISTRING("/org.openoffice.Office.ExtensionManager/ExtensionUpdateData/IgnoredUpdates") );
295     aArgumentList[0] = uno::makeAny( aProperty );
296     uno::Reference< container::XNameContainer > xIgnoredExt( xConfigProvider->createInstanceWithArguments( UNISTRING("com.sun.star.configuration.ConfigurationUpdateAccess"), aArgumentList ), uno::UNO_QUERY_THROW );
297 
298     aProperty.Value = uno::makeAny( UNISTRING("/org.openoffice.Office.ExtensionManager/ExtensionUpdateData/AvailableUpdates") );
299     aArgumentList[0] = uno::makeAny( aProperty );
300     uno::Reference< container::XNameContainer > xUpdateAvail( xConfigProvider->createInstanceWithArguments( UNISTRING("com.sun.star.configuration.ConfigurationUpdateAccess"), aArgumentList ), uno::UNO_QUERY_THROW );
301 
302     return new UpdateCheckConfig( xContainer, xUpdateAvail, xIgnoredExt, rListener );
303 }
304 
305 //------------------------------------------------------------------------------
306 
307 bool
isAutoCheckEnabled() const308 UpdateCheckConfig::isAutoCheckEnabled() const
309 {
310     sal_Bool nValue = sal_False;
311     const_cast < UpdateCheckConfig *> (this)->getByName( UNISTRING( AUTOCHECK_ENABLED ) ) >>= nValue;
312     return nValue;
313 }
314 
315 //------------------------------------------------------------------------------
316 
317 bool
isAutoDownloadEnabled() const318 UpdateCheckConfig::isAutoDownloadEnabled() const
319 {
320     sal_Bool nValue = sal_False;
321     const_cast < UpdateCheckConfig *> (this)->getByName( UNISTRING( AUTODOWNLOAD_ENABLED ) ) >>= nValue;
322     return nValue;
323 }
324 
325 //------------------------------------------------------------------------------
326 
327 rtl::OUString
getUpdateEntryVersion() const328 UpdateCheckConfig::getUpdateEntryVersion() const
329 {
330     rtl::OUString aValue;
331 
332     // getByName is defined as non const in XNameAccess
333     const_cast < UpdateCheckConfig *> (this)->getByName( UNISTRING( OLD_VERSION ) ) >>= aValue;
334 
335     return aValue;
336 }
337 
338 //------------------------------------------------------------------------------
339 
340 sal_Int64
getLastChecked() const341 UpdateCheckConfig::getLastChecked() const
342 {
343     sal_Int64 nValue = 0;
344 
345     // getByName is defined as non const in XNameAccess
346     const_cast < UpdateCheckConfig *> (this)->getByName( UNISTRING( LAST_CHECK ) ) >>= nValue;
347 
348     return nValue;
349 }
350 
351 //------------------------------------------------------------------------------
352 
353 sal_Int64
getCheckInterval() const354 UpdateCheckConfig::getCheckInterval() const
355 {
356     sal_Int64 nValue = 0;
357 
358     // getByName is defined as non const in XNameAccess
359     const_cast < UpdateCheckConfig *> (this)->getByName( UNISTRING( CHECK_INTERVAL ) ) >>= nValue;
360 
361     return nValue;
362 }
363 
364 //------------------------------------------------------------------------------
365 
366 rtl::OUString
getLocalFileName() const367 UpdateCheckConfig::getLocalFileName() const
368 {
369     rtl::OUString aName = UNISTRING(LOCAL_FILE);
370     rtl::OUString aRet;
371 
372     if( m_xContainer->hasByName(aName) )
373         m_xContainer->getByName(aName) >>= aRet;
374 
375     return aRet;
376 }
377 
378 //------------------------------------------------------------------------------
379 
380 rtl::OUString
getDownloadDestination() const381 UpdateCheckConfig::getDownloadDestination() const
382 {
383     rtl::OUString aName = UNISTRING(DOWNLOAD_DESTINATION);
384     rtl::OUString aRet;
385 
386     const_cast <UpdateCheckConfig *> (this)->getByName(aName) >>= aRet;
387 
388     return aRet;
389 }
390 
391 //------------------------------------------------------------------------------
392 
393 void
storeLocalFileName(const rtl::OUString & rLocalFileName,sal_Int64 nFileSize)394 UpdateCheckConfig::storeLocalFileName(const rtl::OUString& rLocalFileName, sal_Int64 nFileSize)
395 {
396     const sal_uInt8 nItems = 2;
397     const rtl::OUString aNameList[nItems] = { UNISTRING(LOCAL_FILE), UNISTRING(DOWNLOAD_SIZE) };
398     const uno::Any aValueList[nItems] = { uno::makeAny(rLocalFileName), uno::makeAny(nFileSize) };
399 
400     for( sal_uInt8 i=0; i < nItems; ++i )
401     {
402         if( m_xContainer->hasByName(aNameList[i]) )
403             m_xContainer->replaceByName(aNameList[i], aValueList[i]);
404         else
405             m_xContainer->insertByName(aNameList[i], aValueList[i]);
406     }
407 
408     commitChanges();
409 }
410 
411 //------------------------------------------------------------------------------
412 
413 void
clearLocalFileName()414 UpdateCheckConfig::clearLocalFileName()
415 {
416     const sal_uInt8 nItems = 2;
417     const rtl::OUString aNameList[nItems] = { UNISTRING(LOCAL_FILE), UNISTRING(DOWNLOAD_SIZE) };
418 
419     for( sal_uInt8 i=0; i < nItems; ++i )
420     {
421         if( m_xContainer->hasByName(aNameList[i]) )
422             m_xContainer->removeByName(aNameList[i]);
423     }
424 
425     commitChanges();
426 }
427 
428 //------------------------------------------------------------------------------
429 
430 void
storeDownloadPaused(bool paused)431 UpdateCheckConfig::storeDownloadPaused(bool paused)
432 {
433     replaceByName(UNISTRING(DOWNLOAD_PAUSED) , uno::makeAny(paused));
434     commitChanges();
435 }
436 
437 //------------------------------------------------------------------------------
438 
439 void
updateLastChecked()440 UpdateCheckConfig::updateLastChecked()
441 {
442     TimeValue systime;
443     osl_getSystemTime(&systime);
444 
445     sal_Int64 lastCheck = systime.Seconds;
446 
447     replaceByName(UNISTRING(LAST_CHECK), uno::makeAny(lastCheck));
448 }
449 
450 //------------------------------------------------------------------------------
451 
452 void
storeUpdateFound(const UpdateInfo & rInfo,const rtl::OUString & aCurrentBuild)453 UpdateCheckConfig::storeUpdateFound( const UpdateInfo& rInfo, const rtl::OUString& aCurrentBuild)
454 
455 {
456     bool autoDownloadEnabled = isAutoDownloadEnabled();
457 
458     uno::Any aValues[nUpdateEntryProperties] =
459     {
460         uno::makeAny(rInfo.Version),
461         uno::makeAny(rInfo.BuildId),
462         uno::makeAny(rInfo.Description),
463         uno::makeAny(rInfo.Sources[0].URL),
464         uno::makeAny(rInfo.Sources[0].IsDirect ? sal_True : sal_False),
465         uno::makeAny(getReleaseNote(rInfo, 1, autoDownloadEnabled) ),
466         uno::makeAny(getReleaseNote(rInfo, 2, autoDownloadEnabled) ),
467         uno::makeAny(getReleaseNote(rInfo, 3, autoDownloadEnabled) ),
468         uno::makeAny(getReleaseNote(rInfo, 4, autoDownloadEnabled) ),
469         uno::makeAny(getReleaseNote(rInfo, 5, autoDownloadEnabled) ),
470         uno::makeAny(aCurrentBuild)
471     };
472 
473     rtl::OUString aName;
474     for( sal_uInt32 n=0; n < nUpdateEntryProperties; ++n )
475     {
476         aName = rtl::OUString::createFromAscii(aUpdateEntryProperties[n]);
477 
478         if( m_xContainer->hasByName(aName) )
479             m_xContainer->replaceByName(aName, aValues[n]);
480         else
481             m_xContainer->insertByName(aName,aValues[n]);
482     }
483 
484     commitChanges();
485 }
486 
487 //------------------------------------------------------------------------------
488 
489 void
clearUpdateFound()490 UpdateCheckConfig::clearUpdateFound()
491 {
492     rtl::OUString aName;
493 
494     for( sal_uInt32 n=0; n < nUpdateEntryProperties; ++n )
495     {
496         aName = rtl::OUString::createFromAscii(aUpdateEntryProperties[n]);
497 
498         try {
499             if( m_xContainer->hasByName(aName) )
500                 m_xContainer->removeByName(aName);
501         } catch(const lang::WrappedTargetException& ) {
502             // Can not remove value, probably in share layer
503             OSL_ASSERT(false);
504             m_xContainer->replaceByName(aName, uno::makeAny(rtl::OUString()));
505         }
506     }
507 
508     /* As we have removed UpdateVersionFound from the shared configuration
509      * existing entries in the user layer do not have a oor operation and
510      * thus are completly ignored (which also means they can not be removed).
511      */
512 
513     commitChanges();
514 }
515 
516 //------------------------------------------------------------------------------
517 
518 uno::Sequence< rtl::OUString >
getServiceNames()519 UpdateCheckConfig::getServiceNames()
520 {
521     uno::Sequence< rtl::OUString > aServiceList(1);
522     aServiceList[0] = UNISTRING( "com.sun.star.setup.UpdateCheckConfig");
523     return aServiceList;
524 }
525 
526 //------------------------------------------------------------------------------
527 
528 rtl::OUString
getImplName()529 UpdateCheckConfig::getImplName()
530 {
531     return UNISTRING( "vnd.sun.UpdateCheckConfig");
532 }
533 
534 //------------------------------------------------------------------------------
535 
536 uno::Type SAL_CALL
getElementType()537 UpdateCheckConfig::getElementType() throw (uno::RuntimeException)
538 {
539     return m_xContainer->getElementType();
540 }
541 
542 //------------------------------------------------------------------------------
543 
544 sal_Bool SAL_CALL
hasElements()545 UpdateCheckConfig::hasElements() throw (uno::RuntimeException)
546 {
547     return m_xContainer->hasElements();
548 }
549 
550 //------------------------------------------------------------------------------
551 
552 uno::Any SAL_CALL
getByName(const::rtl::OUString & aName)553 UpdateCheckConfig::getByName( const ::rtl::OUString& aName )
554     throw (container::NoSuchElementException, lang::WrappedTargetException,  uno::RuntimeException)
555 {
556     uno::Any aValue = m_xContainer->getByName( aName );
557 
558     // Provide dynamic default value
559     if( aName.equalsAscii(DOWNLOAD_DESTINATION) )
560     {
561         rtl::OUString aStr;
562         aValue >>= aStr;
563 
564         if( aStr.getLength() == 0 )
565             aValue = uno::makeAny(getDesktopDirectory());
566     }
567 
568     return aValue;
569 }
570 
571 //------------------------------------------------------------------------------
572 
573 uno::Sequence< ::rtl::OUString > SAL_CALL
getElementNames()574 UpdateCheckConfig::getElementNames(  ) throw (uno::RuntimeException)
575 {
576     return m_xContainer->getElementNames();
577 }
578 
579 //------------------------------------------------------------------------------
580 
581 sal_Bool SAL_CALL
hasByName(const::rtl::OUString & aName)582 UpdateCheckConfig::hasByName( const ::rtl::OUString& aName ) throw (uno::RuntimeException)
583 {
584     return m_xContainer->hasByName( aName );
585 }
586 
587 //------------------------------------------------------------------------------
588 
589 void SAL_CALL
replaceByName(const::rtl::OUString & aName,const uno::Any & aElement)590 UpdateCheckConfig::replaceByName( const ::rtl::OUString& aName, const uno::Any& aElement )
591     throw (lang::IllegalArgumentException, container::NoSuchElementException,
592            lang::WrappedTargetException, uno::RuntimeException)
593 {
594     return m_xContainer->replaceByName( aName, aElement );
595 }
596 
597 //------------------------------------------------------------------------------
598 // XChangesBatch
599 
600 void SAL_CALL
commitChanges()601 UpdateCheckConfig::commitChanges()
602     throw (lang::WrappedTargetException, uno::RuntimeException)
603 {
604     uno::Reference< util::XChangesBatch > xChangesBatch(m_xContainer, uno::UNO_QUERY);
605     if( xChangesBatch.is() && xChangesBatch->hasPendingChanges() )
606     {
607         util::ChangesSet aChangesSet = xChangesBatch->getPendingChanges();
608         xChangesBatch->commitChanges();
609 
610         if( m_rListener.is() )
611         {
612             const sal_Int32 nChanges = aChangesSet.getLength();
613             rtl::OUString aString;
614 
615             for( sal_Int32 i=0; i<nChanges; ++i )
616             {
617                 aChangesSet[i].Accessor >>= aString;
618 
619                 // FIXME: use non IgnoreAsciiCase version as soon as it becomes available
620                 if( aString.endsWithIgnoreAsciiCaseAsciiL(AUTOCHECK_ENABLED "']", sizeof(AUTOCHECK_ENABLED)+1) )
621                 {
622                     sal_Bool bEnabled = sal_False;
623                     aChangesSet[i].Element >>= bEnabled;
624                     m_rListener->autoCheckStatusChanged(sal_True == bEnabled);
625                 }
626                 // FIXME: use non IgnoreAsciiCase version as soon as it becomes available
627                 else if( aString.endsWithIgnoreAsciiCaseAsciiL(CHECK_INTERVAL "']", sizeof(CHECK_INTERVAL)+1) )
628                 {
629                     m_rListener->autoCheckIntervalChanged();
630                 }
631             }
632         }
633     }
634 
635     xChangesBatch = uno::Reference< util::XChangesBatch > ( m_xAvailableUpdates, uno::UNO_QUERY );
636     if( xChangesBatch.is() && xChangesBatch->hasPendingChanges() )
637     {
638         util::ChangesSet aChangesSet = xChangesBatch->getPendingChanges();
639         xChangesBatch->commitChanges();
640     }
641     xChangesBatch = uno::Reference< util::XChangesBatch > ( m_xIgnoredUpdates, uno::UNO_QUERY );
642     if( xChangesBatch.is() && xChangesBatch->hasPendingChanges() )
643     {
644         util::ChangesSet aChangesSet = xChangesBatch->getPendingChanges();
645         xChangesBatch->commitChanges();
646     }
647 }
648 
649 //------------------------------------------------------------------------------
650 
651 sal_Bool SAL_CALL
hasPendingChanges()652 UpdateCheckConfig::hasPendingChanges(  ) throw (uno::RuntimeException)
653 {
654     uno::Reference< util::XChangesBatch > xChangesBatch(m_xContainer, uno::UNO_QUERY);
655     if( xChangesBatch.is() )
656         return xChangesBatch->hasPendingChanges();
657 
658     return sal_False;
659 }
660 
661 //------------------------------------------------------------------------------
662 
663 uno::Sequence< util::ElementChange > SAL_CALL
getPendingChanges()664 UpdateCheckConfig::getPendingChanges(  ) throw (uno::RuntimeException)
665 {
666     uno::Reference< util::XChangesBatch > xChangesBatch(m_xContainer, uno::UNO_QUERY);
667     if( xChangesBatch.is() )
668         return xChangesBatch->getPendingChanges();
669 
670     return uno::Sequence< util::ElementChange >();
671 }
672 
673 //------------------------------------------------------------------------------
storeExtensionVersion(const rtl::OUString & rExtensionName,const rtl::OUString & rVersion)674 bool UpdateCheckConfig::storeExtensionVersion( const rtl::OUString& rExtensionName,
675                                                const rtl::OUString& rVersion )
676 {
677     bool bNotify = true;
678 
679     if ( m_xAvailableUpdates->hasByName( rExtensionName ) )
680         uno::Reference< beans::XPropertySet >( m_xAvailableUpdates->getByName( rExtensionName ), uno::UNO_QUERY_THROW )->setPropertyValue( PROPERTY_VERSION, uno::Any( rVersion ) );
681     else
682     {
683         uno::Reference< beans::XPropertySet > elem( uno::Reference< lang::XSingleServiceFactory >( m_xAvailableUpdates, uno::UNO_QUERY_THROW )->createInstance(), uno::UNO_QUERY_THROW );
684         elem->setPropertyValue( PROPERTY_VERSION, uno::Any( rVersion ) );
685         m_xAvailableUpdates->insertByName( rExtensionName, uno::Any( elem ) );
686     }
687 
688     if ( m_xIgnoredUpdates->hasByName( rExtensionName ) )
689     {
690         ::rtl::OUString aIgnoredVersion;
691         uno::Any aValue( uno::Reference< beans::XPropertySet >( m_xIgnoredUpdates->getByName( rExtensionName ), uno::UNO_QUERY_THROW )->getPropertyValue( PROPERTY_VERSION ) );
692         aValue >>= aIgnoredVersion;
693         if ( aIgnoredVersion.getLength() == 0 ) // no version means ignore all updates
694             bNotify = false;
695         else if ( aIgnoredVersion == rVersion ) // the user wanted to ignore this update
696             bNotify = false;
697     }
698 
699     commitChanges();
700 
701     return bNotify;
702 }
703 
704 //------------------------------------------------------------------------------
checkExtensionVersion(const rtl::OUString & rExtensionName,const rtl::OUString & rVersion)705 bool UpdateCheckConfig::checkExtensionVersion( const rtl::OUString& rExtensionName,
706                                                const rtl::OUString& rVersion )
707 {
708     if ( m_xAvailableUpdates->hasByName( rExtensionName ) )
709     {
710         ::rtl::OUString aStoredVersion;
711         uno::Any aValue( uno::Reference< beans::XPropertySet >( m_xAvailableUpdates->getByName( rExtensionName ), uno::UNO_QUERY_THROW )->getPropertyValue( PROPERTY_VERSION ) );
712         aValue >>= aStoredVersion;
713 
714         if ( m_xIgnoredUpdates->hasByName( rExtensionName ) )
715         {
716             ::rtl::OUString aIgnoredVersion;
717             uno::Any aValue2( uno::Reference< beans::XPropertySet >( m_xIgnoredUpdates->getByName( rExtensionName ), uno::UNO_QUERY_THROW )->getPropertyValue( PROPERTY_VERSION ) );
718             aValue2 >>= aIgnoredVersion;
719             if ( aIgnoredVersion.getLength() == 0 ) // no version means ignore all updates
720                 return false;
721             else if ( aIgnoredVersion == aStoredVersion ) // the user wanted to ignore this update
722                 return false;
723             // TODO: else delete ignored entry?
724         }
725         if ( isVersionGreater( rVersion, aStoredVersion ) )
726             return true;
727         else
728         {
729             m_xAvailableUpdates->removeByName( rExtensionName );
730             commitChanges();
731         }
732     }
733 
734     return false;
735 }
736 
737 //------------------------------------------------------------------------------
getSubVersion(const rtl::OUString & rVersion,sal_Int32 * nIndex)738 rtl::OUString UpdateCheckConfig::getSubVersion( const rtl::OUString& rVersion,
739                                                 sal_Int32 *nIndex )
740 {
741     while ( *nIndex < rVersion.getLength() && rVersion[*nIndex] == '0')
742     {
743         ++*nIndex;
744     }
745 
746     return rVersion.getToken( 0, '.', *nIndex );
747 }
748 
749 //------------------------------------------------------------------------------
750 // checks if the second version string is greater than the first one
751 
isVersionGreater(const rtl::OUString & rVersion1,const rtl::OUString & rVersion2)752 bool UpdateCheckConfig::isVersionGreater( const rtl::OUString& rVersion1,
753                                           const rtl::OUString& rVersion2 )
754 {
755     for ( sal_Int32 i1 = 0, i2 = 0; i1 >= 0 || i2 >= 0; )
756     {
757         ::rtl::OUString sSub1( getSubVersion( rVersion1, &i1 ) );
758         ::rtl::OUString sSub2( getSubVersion( rVersion2, &i2 ) );
759 
760         if ( sSub1.getLength() < sSub2.getLength() ) {
761             return true;
762         } else if ( sSub1.getLength() > sSub2.getLength() ) {
763             return false;
764         } else if ( sSub1 < sSub2 ) {
765             return true;
766         } else if ( sSub1 > sSub2 ) {
767             return false;
768         }
769     }
770     return false;
771 }
772 
773 //------------------------------------------------------------------------------
774 //------------------------------------------------------------------------------
775 //------------------------------------------------------------------------------
776 
777 rtl::OUString SAL_CALL
getImplementationName()778 UpdateCheckConfig::getImplementationName()  throw (uno::RuntimeException)
779 {
780     return getImplName();
781 }
782 
783 //------------------------------------------------------------------------------
784 
785 sal_Bool SAL_CALL
supportsService(rtl::OUString const & serviceName)786 UpdateCheckConfig::supportsService(rtl::OUString const & serviceName)
787     throw (uno::RuntimeException)
788 {
789     uno::Sequence< rtl::OUString > aServiceNameList = getServiceNames();
790 
791     for( sal_Int32 n=0; n < aServiceNameList.getLength(); n++ )
792         if( aServiceNameList[n].equals(serviceName) )
793             return sal_True;
794 
795     return sal_False;
796 }
797 
798 //------------------------------------------------------------------------------
799 
800 uno::Sequence< rtl::OUString > SAL_CALL
getSupportedServiceNames()801 UpdateCheckConfig::getSupportedServiceNames()  throw (uno::RuntimeException)
802 {
803     return getServiceNames();
804 }
805 
806 
807