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 #undef UNICODE
29 #undef _UNICODE
30 
31 #define _WIN32_WINDOWS 0x0410
32 
33 #ifdef _MSC_VER
34 #pragma warning(push, 1) /* disable warnings within system headers */
35 #endif
36 #define WIN32_LEAN_AND_MEAN
37 #include <windows.h>
38 #include <msiquery.h>
39 #ifdef _MSC_VER
40 #pragma warning(pop)
41 #endif
42 
43 #include <malloc.h>
44 #include <assert.h>
45 
46 #include <tchar.h>
47 #include <string>
48 #include <systools/win32/uwinapi.h>
49 
50 #include <../tools/seterror.hxx>
51 
52 using namespace std;
53 
54 namespace
55 {
56     string GetMsiProperty(MSIHANDLE handle, const string& sProperty)
57     {
58         string  result;
59         TCHAR   szDummy[1] = TEXT("");
60         DWORD   nChars = 0;
61 
62         if (MsiGetProperty(handle, sProperty.c_str(), szDummy, &nChars) == ERROR_MORE_DATA)
63         {
64             DWORD nBytes = ++nChars * sizeof(TCHAR);
65             LPTSTR buffer = reinterpret_cast<LPTSTR>(_alloca(nBytes));
66             ZeroMemory( buffer, nBytes );
67             MsiGetProperty(handle, sProperty.c_str(), buffer, &nChars);
68             result = buffer;
69         }
70         return result;
71     }
72 
73     inline bool IsSetMsiProperty(MSIHANDLE handle, const string& sProperty)
74     {
75         return (GetMsiProperty(handle, sProperty).length() > 0);
76     }
77 
78     inline void UnsetMsiProperty(MSIHANDLE handle, const string& sProperty)
79     {
80         MsiSetProperty(handle, sProperty.c_str(), NULL);
81     }
82 
83     inline void SetMsiProperty(MSIHANDLE handle, const string& sProperty, const string&)
84     {
85         MsiSetProperty(handle, sProperty.c_str(), TEXT("1"));
86     }
87 } // namespace
88 
89 extern "C" UINT __stdcall GetUserInstallMode(MSIHANDLE handle)
90 {
91     string sOfficeInstallPath = GetMsiProperty(handle, TEXT("INSTALLLOCATION"));
92 
93     // MessageBox(NULL, sOfficeInstallPath.c_str(), "DEBUG", MB_OK);
94 
95     // unsetting all properties
96 
97     UnsetMsiProperty( handle, TEXT("INVALIDDIRECTORY") );
98     UnsetMsiProperty( handle, TEXT("ISWRONGPRODUCT") );
99     UnsetMsiProperty( handle, TEXT("PATCHISOLDER") );
100     UnsetMsiProperty( handle, TEXT("ALLUSERS") );
101 
102     // 1. Searching for "ProductCode" in setup.ini
103 
104     string sSetupiniPath = sOfficeInstallPath + TEXT("program\\setup.ini");
105 
106     TCHAR szValue[32767];
107 
108     GetPrivateProfileString(
109         TEXT("Bootstrap"),
110         TEXT("ProductCode"),
111         TEXT("INVALIDDIRECTORY"),
112         szValue,
113         elementsof(szValue),
114         sSetupiniPath.c_str()
115         );
116 
117     if ( !_tcsicmp( szValue, TEXT("INVALIDDIRECTORY") ) )
118     {
119     	// No setup.ini or no "ProductCode" in setup.ini. This is an invalid directory.
120         SetMsiProperty( handle, TEXT("INVALIDDIRECTORY"), TEXT("YES") );
121         // MessageBox(NULL, "INVALIDDIRECTORY set, no setup.ini or ProductCode in setup.ini.", "DEBUG", MB_OK);
122         SetMsiErrorCode( MSI_ERROR_INVALIDDIRECTORY );
123         return ERROR_SUCCESS;
124     }
125 
126     // 2. Comparing first three characters of "PRODUCTMAJOR" from property table and "buildid" from InfoFile
127 
128     szValue[0] = '\0';
129 
130     GetPrivateProfileString(
131         TEXT("Bootstrap"),
132         TEXT("buildid"),
133         TEXT("ISWRONGPRODUCT"),
134         szValue,
135         elementsof(szValue),
136         sSetupiniPath.c_str()
137         );
138 
139     if ( !_tcsicmp( szValue, TEXT("ISWRONGPRODUCT") ) )
140     {
141         SetMsiProperty( handle, TEXT("ISWRONGPRODUCT"), TEXT("YES") );
142         // MessageBox(NULL, "ISWRONGPRODUCT 1 set after searching buildid", "DEBUG", MB_OK);
143         SetMsiErrorCode( MSI_ERROR_ISWRONGPRODUCT );
144         return ERROR_SUCCESS;
145     }
146 
147     string ProductMajor = GetMsiProperty(handle, TEXT("PRODUCTMAJOR"));
148 
149     // Comparing the first three characters, for example "680"
150     // If not equal, this version is not suited for patch or language pack
151 
152     if (_tcsnicmp(ProductMajor.c_str(), szValue, 3))
153     {
154         SetMsiProperty( handle, TEXT("ISWRONGPRODUCT"), TEXT("YES") );
155         // MessageBox(NULL, "ISWRONGPRODUCT 2 set after searching PRODUCTMAJOR", "DEBUG", MB_OK);
156         SetMsiErrorCode( MSI_ERROR_ISWRONGPRODUCT );
157         return ERROR_SUCCESS;
158     }
159 
160     // 3. Only for patch: Comparing "PRODUCTMINOR from property table and "ProductMinor" from InfoFile
161 
162     string isPatch = GetMsiProperty(handle, TEXT("ISPATCH"));
163 
164     if (isPatch=="1")
165     {
166         string ProductMinor = GetMsiProperty(handle, TEXT("PRODUCTBUILDID"));
167         int PatchProductMinor = atoi(ProductMinor.c_str());
168 
169         szValue[0] = '\0';
170 
171         GetPrivateProfileString(
172             TEXT("Bootstrap"),
173             TEXT("ProductBuildid"),
174             TEXT("8918"),
175             szValue,
176             elementsof(szValue),
177             sSetupiniPath.c_str()
178             );
179 
180         int InstalledProductMinor = atoi(szValue);
181 
182         if ( InstalledProductMinor >= PatchProductMinor )
183         {
184             SetMsiProperty( handle, TEXT("PATCHISOLDER"), TEXT("YES") );
185             // MessageBox(NULL, "PATCHISOLDER set", "DEBUG", MB_OK);
186             SetMsiErrorCode( MSI_ERROR_PATCHISOLDER );
187             return ERROR_SUCCESS;
188         }
189     }
190 
191     // 4. Setting property ALLUSERS with value from "setup.ini"
192 
193     szValue[0] = '\0';
194 
195     GetPrivateProfileString(
196         TEXT("Bootstrap"),
197         TEXT("ALLUSERS"),
198         TEXT(""),
199         szValue,
200         elementsof(szValue),
201         sSetupiniPath.c_str()
202         );
203 
204     if ( szValue[0] )
205     {
206         SetMsiProperty( handle, TEXT("ALLUSERS"), szValue );
207         // MessageBox(NULL, "ALLUSERS set", "DEBUG", MB_OK);
208     }
209 
210     return ERROR_SUCCESS;
211 }
212