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