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 // MARKER(update_precomp.py): autogen include statement, do not remove
24 #include "precompiled_desktop.hxx"
25 
26 #include <osl/file.hxx>
27 #include <rtl/bootstrap.hxx>
28 #include <rtl/ustring.hxx>
29 #include <tools/datetime.hxx>
30 #include <unotools/configmgr.hxx>
31 
32 #include <comphelper/processfactory.hxx>
33 #include <com/sun/star/beans/XPropertySet.hpp>
34 #include <com/sun/star/beans/NamedValue.hpp>
35 #include <com/sun/star/util/XChangesBatch.hpp>
36 
37 #include "app.hxx"
38 
39 using ::rtl::OUString;
40 using namespace ::desktop;
41 using namespace ::com::sun::star;
42 using namespace ::com::sun::star::beans;
43 
44 static const OUString sConfigSrvc( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.configuration.ConfigurationProvider" ) );
45 static const OUString sAccessSrvc( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.configuration.ConfigurationUpdateAccess" ) );
46 
47 /* Path of the license. */
48 OUString Desktop::GetLicensePath()
49 {
50     // license file name
51     static const char *szLicensePath = "/share/readme";
52 #if defined(WNT) || defined(OS2)
53     static const char *szWNTLicenseName = "/license";
54     static const char *szWNTLicenseExt = ".txt";
55 #else
56     static const char *szUNXLicenseName = "/LICENSE";
57     static const char *szUNXLicenseExt = "";
58 #endif
59     static OUString aLicensePath;
60 
61     if (aLicensePath.getLength() > 0)
62         return aLicensePath;
63 
64     OUString aBaseInstallPath(RTL_CONSTASCII_USTRINGPARAM("$OOO_BASE_DIR"));
65     rtl::Bootstrap::expandMacros(aBaseInstallPath);
66 
67     // determine the filename of the license to show
68     OUString  aLangString;
69     ::com::sun::star::lang::Locale aLocale;
70     OString aMgrName = OString("dkt");
71 
72     AllSettings aSettings(Application::GetSettings());
73     aLocale = aSettings.GetUILocale();
74     ResMgr* pLocalResMgr = ResMgr::SearchCreateResMgr( aMgrName.getStr(), aLocale);
75 
76     aLangString = aLocale.Language;
77     if ( aLocale.Country.getLength() != 0 )
78     {
79         aLangString += OUString::createFromAscii("-");
80         aLangString += aLocale.Country;
81         if ( aLocale.Variant.getLength() != 0 )
82         {
83             aLangString += OUString::createFromAscii("-");
84             aLangString += aLocale.Variant;
85         }
86     }
87 #if defined(WNT) || defined(OS2)
88     aLicensePath =
89         aBaseInstallPath + OUString::createFromAscii(szLicensePath)
90         + OUString::createFromAscii(szWNTLicenseName)
91         + OUString::createFromAscii("_")
92         + aLangString
93         + OUString::createFromAscii(szWNTLicenseExt);
94 #else
95     aLicensePath =
96         aBaseInstallPath + OUString::createFromAscii(szLicensePath)
97         + OUString::createFromAscii(szUNXLicenseName)
98         + OUString::createFromAscii("_")
99         + aLangString
100         + OUString::createFromAscii(szUNXLicenseExt);
101 #endif
102     delete pLocalResMgr;
103     return aLicensePath;
104 }
105 
106 /* Check if we need to accept license. */
107 sal_Bool Desktop::LicenseNeedsAcceptance()
108 {
109     // permissive licences like ALv2 don't need end user license approval
110     return sal_False;
111 }
112 
113 /* Local function - get access to the configuration */
114 static Reference< XPropertySet > impl_getConfigurationAccess( const OUString& rPath )
115 {
116     Reference < XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory();
117 
118     // get configuration provider
119     Reference< XMultiServiceFactory > xConfigProvider = Reference< XMultiServiceFactory >(
120             xFactory->createInstance( sConfigSrvc ), UNO_QUERY_THROW );
121 
122     Sequence< Any > aArgs( 1 );
123     NamedValue aValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "NodePath" ) ), makeAny( rPath ) );
124     aArgs[0] <<= aValue;
125     return Reference< XPropertySet >(
126             xConfigProvider->createInstanceWithArguments( sAccessSrvc, aArgs ), UNO_QUERY_THROW );
127 }
128 
129 /* Local function - was the wizard completed already? */
130 static sal_Bool impl_isFirstStart()
131 {
132     try {
133         Reference< XPropertySet > xPSet = impl_getConfigurationAccess( OUString( RTL_CONSTASCII_USTRINGPARAM( "org.openoffice.Setup/Office" ) ) );
134 
135         Any result = xPSet->getPropertyValue(OUString::createFromAscii("FirstStartWizardCompleted"));
136         sal_Bool bCompleted = sal_False;
137         if ((result >>= bCompleted) && bCompleted)
138             return sal_False;  // wizard was already completed
139         else
140             return sal_True;
141     } catch (const Exception&)
142     {
143         return sal_True;
144     }
145 }
146 
147 /* Local function - convert oslDateTime to tools DateTime */
148 static DateTime impl_oslDateTimeToDateTime(const oslDateTime& aDateTime)
149 {
150     return DateTime(
151         Date(aDateTime.Day, aDateTime.Month, aDateTime.Year),
152         Time(aDateTime.Hours, aDateTime.Minutes, aDateTime.Seconds));
153 }
154 
155 /* Local function - get DateTime from a string */
156 static sal_Bool impl_parseDateTime(const OUString& aString, DateTime& aDateTime)
157 {
158     // take apart a canonical literal xsd:dateTime string
159     //CCYY-MM-DDThh:mm:ss(Z)
160 
161     OUString aDateTimeString = aString.trim();
162 
163     // check length
164     if (aDateTimeString.getLength() < 19 || aDateTimeString.getLength() > 20)
165         return sal_False;
166 
167     sal_Int32 nDateLength = 10;
168     sal_Int32 nTimeLength = 8;
169 
170     OUString aDateTimeSep = OUString::createFromAscii("T");
171     OUString aDateSep = OUString::createFromAscii("-");
172     OUString aTimeSep = OUString::createFromAscii(":");
173     OUString aUTCString = OUString::createFromAscii("Z");
174 
175     OUString aDateString = aDateTimeString.copy(0, nDateLength);
176     OUString aTimeString = aDateTimeString.copy(nDateLength+1, nTimeLength);
177 
178     sal_Int32 nIndex = 0;
179     sal_Int32 nYear = aDateString.getToken(0, '-', nIndex).toInt32();
180     sal_Int32 nMonth = aDateString.getToken(0, '-', nIndex).toInt32();
181     sal_Int32 nDay = aDateString.getToken(0, '-', nIndex).toInt32();
182     nIndex = 0;
183     sal_Int32 nHour = aTimeString.getToken(0, ':', nIndex).toInt32();
184     sal_Int32 nMinute = aTimeString.getToken(0, ':', nIndex).toInt32();
185     sal_Int32 nSecond = aTimeString.getToken(0, ':', nIndex).toInt32();
186 
187     Date tmpDate((sal_uInt16)nDay, (sal_uInt16)nMonth, (sal_uInt16)nYear);
188     Time tmpTime(nHour, nMinute, nSecond);
189     DateTime tmpDateTime(tmpDate, tmpTime);
190     if (aString.indexOf(aUTCString) < 0)
191         tmpDateTime.ConvertToUTC();
192 
193     aDateTime = tmpDateTime;
194     return sal_True;
195 }
196 
197 /* Local function - was the license accepted already? */
198 static sal_Bool impl_isLicenseAccepted()
199 {
200     // If no license will be shown ... it must not be accepted.
201     // So it was accepted "hardly" by the outside installer.
202     // But if the configuration entry "HideEula" will be removed afterwards ..
203     // we have to show the licese page again and user has to accept it here .-)
204     if ( ! Desktop::LicenseNeedsAcceptance() )
205         return sal_True;
206 
207     try
208     {
209         Reference< XPropertySet > xPSet = impl_getConfigurationAccess( OUString( RTL_CONSTASCII_USTRINGPARAM( "org.openoffice.Setup/Office" ) ) );
210 
211         Any result = xPSet->getPropertyValue(OUString::createFromAscii("LicenseAcceptDate"));
212 
213         OUString aAcceptDate;
214         if (result >>= aAcceptDate)
215         {
216             // compare to date of license file
217             OUString aLicenseURL = Desktop::GetLicensePath();
218             osl::DirectoryItem aDirItem;
219             if (osl::DirectoryItem::get(aLicenseURL, aDirItem) != osl::FileBase::E_None)
220                 return sal_False;
221             osl::FileStatus aStatus(FileStatusMask_All);
222             if (aDirItem.getFileStatus(aStatus) != osl::FileBase::E_None)
223                 return sal_False;
224             TimeValue aTimeVal = aStatus.getModifyTime();
225             oslDateTime aDateTimeVal;
226             if (!osl_getDateTimeFromTimeValue(&aTimeVal, &aDateTimeVal))
227                 return sal_False;
228 
229             // compare dates
230             DateTime aLicenseDateTime = impl_oslDateTimeToDateTime(aDateTimeVal);
231             DateTime aAcceptDateTime;
232             if (!impl_parseDateTime(aAcceptDate, aAcceptDateTime))
233                 return sal_False;
234 
235             if ( aAcceptDateTime > aLicenseDateTime )
236                 return sal_True;
237         }
238         return sal_False;
239     } catch (const Exception&)
240     {
241         return sal_False;
242     }
243 }
244 
245 /* Check if we need the first start wizard. */
246 sal_Bool Desktop::IsFirstStartWizardNeeded()
247 {
248     return impl_isFirstStart() || !impl_isLicenseAccepted();
249 }
250 
251 void Desktop::FinishFirstStart()
252 {
253 #if 0 // most platforms no longer benefit from the quickstarter, TODO: are the other benefits worth it?
254 #ifndef OS2 // cannot enable quickstart on first startup, see shutdownicon.cxx comments.
255         EnableQuickstart();
256 #endif
257 #endif
258 
259     try {
260         Reference < XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory();
261         // get configuration provider
262         Reference< XMultiServiceFactory > theConfigProvider = Reference< XMultiServiceFactory >(
263         xFactory->createInstance(sConfigSrvc), UNO_QUERY_THROW);
264         Sequence< Any > theArgs(1);
265         NamedValue v(OUString::createFromAscii("NodePath"),
266             makeAny(OUString::createFromAscii("org.openoffice.Setup/Office")));
267         theArgs[0] <<= v;
268         Reference< XPropertySet > pset = Reference< XPropertySet >(
269             theConfigProvider->createInstanceWithArguments(sAccessSrvc, theArgs), UNO_QUERY_THROW);
270         pset->setPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM("FirstStartWizardCompleted")), makeAny(sal_True));
271         Reference< util::XChangesBatch >(pset, UNO_QUERY_THROW)->commitChanges();
272     } catch (const uno::Exception&) {
273         // ignore the exception as it is not critical enough to prevent office from starting
274     }
275 }
276 
277 void Desktop::EnableQuickstart()
278 {
279     sal_Bool bQuickstart( sal_True );
280     sal_Bool bAutostart( sal_True );
281     Sequence< Any > aSeq( 2 );
282     aSeq[0] <<= bQuickstart;
283     aSeq[1] <<= bAutostart;
284 
285     Reference < XInitialization > xQuickstart( ::comphelper::getProcessServiceFactory()->createInstance(
286         OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.office.Quickstart"))), UNO_QUERY );
287     if ( xQuickstart.is() )
288         xQuickstart->initialize( aSeq );
289 }
290 
291 void Desktop::DoRestartActionsIfNecessary( sal_Bool bQuickStart )
292 {
293     if ( bQuickStart )
294     {
295         try
296         {
297             Reference< XPropertySet > xPSet = impl_getConfigurationAccess( OUString( RTL_CONSTASCII_USTRINGPARAM( "org.openoffice.Setup/Office" ) ) );
298 
299             OUString sPropName( RTL_CONSTASCII_USTRINGPARAM( "OfficeRestartInProgress" ) );
300             Any aRestart = xPSet->getPropertyValue( sPropName );
301             sal_Bool bRestart = sal_False;
302             if ( ( aRestart >>= bRestart ) && bRestart )
303             {
304                 xPSet->setPropertyValue( sPropName, makeAny( sal_False ) );
305                 Reference< util::XChangesBatch >( xPSet, UNO_QUERY_THROW )->commitChanges();
306 
307                 Sequence< Any > aSeq( 2 );
308                 aSeq[0] <<= sal_True;
309                 aSeq[1] <<= sal_True;
310 
311                 Reference < XInitialization > xQuickstart( ::comphelper::getProcessServiceFactory()->createInstance(
312                     OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.office.Quickstart" ) ) ),UNO_QUERY_THROW );
313                 xQuickstart->initialize( aSeq );
314             }
315         }
316         catch( uno::Exception& )
317         {
318             // this is no critical operation so it should not prevent office from starting
319         }
320     }
321 }
322 
323 void Desktop::SetRestartState()
324 {
325     try
326     {
327         Reference< XPropertySet > xPSet = impl_getConfigurationAccess( OUString( RTL_CONSTASCII_USTRINGPARAM( "org.openoffice.Setup/Office" ) ) );
328         OUString sPropName( RTL_CONSTASCII_USTRINGPARAM( "OfficeRestartInProgress" ) );
329         xPSet->setPropertyValue( sPropName, makeAny( sal_True ) );
330         Reference< util::XChangesBatch >( xPSet, UNO_QUERY_THROW )->commitChanges();
331     }
332     catch( uno::Exception& )
333     {
334         // this is no critical operation, ignore the exception
335     }
336 
337 }
338