363adc7b49fb58abe87302e3e7c3c44daaba2d64
[openafs.git] / src / WINNT / afs_setup_utils / afs_setup_utils.cpp
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * INCLUDES _________________________________________________________________\r
12  *\r
13  */\r
14 \r
15 extern "C" {\r
16 #include <afs/param.h>\r
17 #include <afs/stds.h>\r
18 #include <afs/fileutil.h>\r
19 }\r
20 \r
21 #include <windows.h>\r
22 #include <stdio.h>\r
23 #include <time.h>\r
24 #include <assert.h>\r
25 #include <stdlib.h>\r
26 #include <io.h>\r
27 #include <string.h>\r
28 #include <SYS\STAT.H>\r
29 #include <shellapi.h>\r
30 \r
31 #include <WINNT/afsreg.h>\r
32 #include <WINNT/afssw.h>\r
33 #include <WINNT/talocale.h>\r
34 \r
35 #include "resource.h"\r
36 #include "progress_dlg.h"\r
37 #include "sutil.h"\r
38 #include "forceremove.h"\r
39 \r
40 \r
41 /*\r
42  * PROTOTYPES _________________________________________________________________\r
43  *\r
44  */\r
45 static char *GetAppInstallDir(struct APPINFO *pApp, BOOL bRemembered);\r
46 BOOL UninstallCredsTool();\r
47 BOOL ServerSpecificUninstall();\r
48 BOOL ClientSpecificUninstall();\r
49 \r
50 \r
51 \r
52 /*\r
53  * DEFINITIONS _________________________________________________________________\r
54  *\r
55  */\r
56 #define SUCALLCONV  WINAPI\r
57 \r
58 #define UNINSTALL_TEMP_INFO_KEY     "HKEY_LOCAL_MACHINE\\Software\\AfsUninstallTempInfo"\r
59 #define INSTALL_DIR_VALUE_NAME      "InstallDir"\r
60 \r
61 #define AFS_PRESERVED_CFG_INFO_KEY  "HKEY_LOCAL_MACHINE\\Software\\AfsPreservedConfigInfo"\r
62 \r
63 #define MS_SHARED_FILES_KEY         "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion\\SharedDLLs"\r
64 \r
65 // Log file to use when running in silent mode\r
66 #define UNINSTALL_ERROR_LOG_NAME    "\\AfsUninstallErrorLog.txt"\r
67 #define INSTALL_ERROR_LOG_NAME      "\\AfsInstallErrorLog.txt"\r
68 \r
69 #define TARGETDIR                   "<TARGETDIR>"\r
70 #define WINDIR                      "<WINDIR>"\r
71 #define WINSYSDIR                   "<WINSYSDIR>"\r
72 \r
73 #define WIN9X_START_MENU_REG_KEY    "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"\r
74 #define WIN9X_START_MENU_REG_VALUE  "Programs"\r
75     \r
76 #define WINNT_START_MENU_REG_KEY    "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"\r
77 #define WINNT_START_MENU_REG_VALUE  "Common Programs"\r
78 \r
79 #define LOCALE_ID_LEN               4\r
80 \r
81 struct REGVALUE {\r
82     char *pszKey;\r
83     char *pszValue;\r
84 };\r
85 \r
86 \r
87 typedef BOOL (APP_UNINSTALL_FUNC)();\r
88 \r
89 \r
90 \r
91 struct APPINFO {\r
92     char *pszAppName;\r
93 \r
94     // Service Info\r
95     char *pszSvcName;\r
96     char *pszSvcKey;\r
97     char *pszSvcDependOn;\r
98     char *pszSvcDisplayName;\r
99 \r
100     char *pszNetworkProviderOrder;\r
101 \r
102     // Message to use to tell the user that we have to stop the service\r
103     int nServiceShutdownMsgID;\r
104 \r
105     // Message to use for the progress dialog that is shown while\r
106     // waiting for the service to stop.\r
107     int nServiceShutdownProgressMsgID;\r
108 \r
109     // Location in registry of a key we can use to know that the app is installed\r
110     char *pszAppKey;\r
111 \r
112     // Location in registry of this app's install dir\r
113     struct REGVALUE regInstallDir;\r
114 \r
115     // Path Info\r
116     char *pszLocalRoot;     // The root dir below the install dir\r
117     char *pszBinPath;       // Path to remove from the system path\r
118 \r
119     // Generated files and directories to delete.  These are both multistring lists.\r
120     char *pszDirsToDel;     // All files in these dirs will be deleted\r
121     char *pszFilesToDel;    // Use this if you want to delete files but leave the dir.  Wildcards can be used.\r
122 \r
123     // Registry values to remove\r
124     struct REGVALUE *pRegValues;\r
125     struct REGVALUE *pWinNTRegValues;   // Only remove these if running WinNT\r
126     struct REGVALUE *pWin9XRegValues;   // Only remove these if running Win9X\r
127 \r
128     // Start menu entries to delete\r
129     char *pszStartMenuEntries;\r
130 \r
131     // Registry keys to save if a user wants to preserve config info during uninstall\r
132     char *pszRegKeysToPreserve;\r
133     int nPreserveConfigInfoMsgID;\r
134 \r
135     // Uninstall func - used for things specific to this app\r
136     APP_UNINSTALL_FUNC *pUninstallFunc;\r
137 };\r
138 \r
139 \r
140 /*\r
141  * App info structure for the Server product\r
142  */\r
143 struct APPINFO appServer = {\r
144     "AFS Server",\r
145     \r
146     AFSREG_SVR_SVC_NAME,\r
147     AFSREG_SVR_SVC_KEY,\r
148     0,  // No depend on\r
149     AFSREG_SVR_SVC_DISPLAYNAME_DATA,\r
150 \r
151     0,  // No network provider order\r
152 \r
153     IDS_MUST_STOP_SERVER,\r
154     IDS_WAITING_FOR_SERVER_TO_STOP,\r
155 \r
156     AFSREG_SVR_SW_VERSION_KEY,\r
157     \r
158     { AFSREG_SVR_SW_VERSION_KEY, AFSREG_SVR_SW_VERSION_DIR_VALUE },\r
159 \r
160     "\\Server",\r
161     "\\usr\\afs\\bin",\r
162 \r
163     // Dirs to delete\r
164     TARGETDIR"\\Server\\usr\\afs\\bin\\backup\0"\r
165     TARGETDIR"\\Server\\usr\\afs\\bin\0"\r
166     TARGETDIR"\\Server\\usr\\afs\\db\0"\r
167     TARGETDIR"\\Server\\usr\\afs\\logs\0"\r
168     TARGETDIR"\\Server\\usr\\afs\\etc\0"\r
169     TARGETDIR"\\Server\\usr\\afs\\local\0"\r
170     TARGETDIR"\\Server\\usr\\afs\0"\r
171     TARGETDIR"\\Server\\usr\0",\r
172     \r
173     // Files to delete\r
174     TARGETDIR"\\Common\\*.gid\0"\r
175     TARGETDIR"\\Common\\*.fts\0",\r
176 \r
177     0,  // No reg values\r
178     0,  // No NT only reg values\r
179     0,  // No 9x only reg values\r
180 \r
181     "Server\0",\r
182 \r
183     // Config info to preserve\r
184     AFSREG_SVR_SVC_KEY"\0", \r
185     IDS_PRESERVE_SERVER_CONFIG_INFO,\r
186 \r
187     0   // No special uninstall function\r
188 };\r
189 \r
190 // Registry values to remove for the Client\r
191 struct REGVALUE clientRegValues[] = {\r
192     { "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved", "{DC515C27-6CAC-11D1-BAE7-00C04FD140D2}" },\r
193     { 0, 0 }    // This indicates there are no more entries\r
194 };\r
195 \r
196 struct REGVALUE clientWinNTRegValues[] = {\r
197     { "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\File Manager\\AddOns", "AFS Client FME" },\r
198     { 0, 0 }\r
199 };\r
200 \r
201 struct REGVALUE clientWin9XRegValues[] = {\r
202     { "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\NetworkProvider\\Order", "TransarcAFSDaemon" },\r
203     { 0, 0 }\r
204 };\r
205 \r
206 /*\r
207  * App info structure for the Client product\r
208  */\r
209 struct APPINFO appClient = {\r
210     "AFS Client",\r
211     \r
212     AFSREG_CLT_SVC_NAME,\r
213     AFSREG_CLT_SVC_KEY,\r
214     "5250435353004E657462696F730000",\r
215     AFSREG_CLT_SVC_DISPLAYNAME_DATA,\r
216 \r
217     AFSREG_CLT_SVC_NAME,\r
218 \r
219     IDS_MUST_STOP_CLIENT,\r
220     IDS_WAITING_FOR_CLIENT_TO_STOP,\r
221 \r
222     AFSREG_CLT_SW_VERSION_KEY,\r
223 \r
224     { AFSREG_CLT_SW_VERSION_KEY, AFSREG_CLT_SW_VERSION_DIR_VALUE },\r
225 \r
226     "\\Client",\r
227     "\\Program",\r
228 \r
229     // No dirs to delete\r
230     0,\r
231     \r
232     // Files to delete\r
233     TARGETDIR"\\Common\\*.gid\0"\r
234     TARGETDIR"\\Common\\*.fts\0"\r
235     WINDIR"\\..\\AFSCache\0"\r
236     WINDIR"\\afsd.log\0"\r
237     WINDIR"\\afsd.ini\0"\r
238     WINDIR"\\afsdsbmt.ini\0"\r
239     WINDIR"\\afsd_init.log\0",\r
240     \r
241     clientRegValues,\r
242     clientWinNTRegValues,\r
243     clientWin9XRegValues,\r
244 \r
245     // Start menu entries to remove\r
246     "Client\0",\r
247 \r
248     // Config info to preserve\r
249     AFSREG_CLT_SVC_KEY"\0",\r
250     IDS_PRESERVE_CLIENT_CONFIG_INFO,\r
251 \r
252     ClientSpecificUninstall\r
253 };\r
254 \r
255 \r
256 /*\r
257  * App info structure for the Light Client product\r
258  */\r
259 struct APPINFO appLightClient = {\r
260     "AFS Light",\r
261     \r
262     // No service info \r
263     0,\r
264     0,\r
265     0,\r
266     0,\r
267 \r
268     AFSREG_CLT_SVC_NAME,\r
269 \r
270     // No service shutdown messages\r
271     0,\r
272     0,\r
273 \r
274     "HKEY_LOCAL_MACHINE\\SOFTWARE\\TransarcCorporation\\AFS Light Client",\r
275 \r
276     { AFSREG_CLT_SW_VERSION_KEY, AFSREG_CLT_SW_VERSION_DIR_VALUE },\r
277 \r
278     "\\Client",\r
279     "\\Program",\r
280 \r
281     // No dirs to delete\r
282     0,\r
283     \r
284     // Files to delete\r
285     TARGETDIR"\\Common\\*.gid\0"\r
286     TARGETDIR"\\Common\\*.fts\0",\r
287 \r
288     clientRegValues,\r
289     clientWinNTRegValues,\r
290     clientWin9XRegValues,\r
291 \r
292     // Start menu entries to remove\r
293     "Light\0",\r
294 \r
295     // Config info to preserve\r
296     AFSREG_CLT_SVC_KEY"\0",\r
297     IDS_PRESERVE_LIGHT_CLIENT_CONFIG_INFO,\r
298 \r
299     UninstallCredsTool\r
300 };\r
301 \r
302 \r
303 /*\r
304  * App info structure for the Control Center product\r
305  */\r
306 struct APPINFO appControlCenter = {\r
307     "AFS Control Center",\r
308     \r
309     // No service info\r
310     0,\r
311     0,\r
312     0,\r
313     0,\r
314 \r
315     // No network provider order\r
316     0,\r
317 \r
318     // No service shutdown messages    \r
319     0,\r
320     0,\r
321 \r
322     "HKEY_LOCAL_MACHINE\\SOFTWARE\\TransarcCorporation\\AFS Control Center",\r
323     \r
324     { "HKEY_LOCAL_MACHINE\\SOFTWARE\\TransarcCorporation\\AFS Control Center\\CurrentVersion", "PathName" },\r
325 \r
326     "\\Control Center",\r
327     "",\r
328 \r
329     // No dirs to delete\r
330     0,\r
331     \r
332     // Files to delete\r
333     TARGETDIR"\\Common\\*.gid\0"\r
334     TARGETDIR"\\Common\\*.fts\0",\r
335     \r
336     0,  // No reg values\r
337     0,  // No NT only reg values\r
338     0,  // No 9x only reg values\r
339 \r
340     // Start menu entries to remove\r
341     "Control Center\0",\r
342 \r
343     // Config info to preserve\r
344     AFSREG_CLT_SVC_KEY"\0",\r
345     IDS_PRESERVE_CC_CONFIG_INFO,\r
346 \r
347     0   // No uninstall function\r
348 };\r
349 \r
350 \r
351 /*\r
352  * App info structure for the Sys Admin Doc files\r
353  */\r
354 struct APPINFO appDocs = {\r
355     "AFS Supplemental Documentation",\r
356 \r
357     // No service info\r
358     0,\r
359     0,\r
360     0,\r
361     0,\r
362 \r
363     // No network provider order\r
364     0,\r
365 \r
366     // No service shutdown messages    \r
367     0,\r
368     0,\r
369 \r
370     "HKEY_LOCAL_MACHINE\\SOFTWARE\\TransarcCorporation\\AFS Supplemental Documentation",\r
371     \r
372     { "HKEY_LOCAL_MACHINE\\SOFTWARE\\TransarcCorporation\\AFS Supplemental Documentation\\CurrentVersion", "PathName" },\r
373 \r
374     "\\Documentation",\r
375     "",\r
376 \r
377     // No dirs to delete\r
378     0,\r
379     \r
380     // Files to delete\r
381     TARGETDIR"\\Common\\*.gid\0"\r
382     TARGETDIR"\\Common\\*.fts\0",\r
383 \r
384     0,  // No reg values\r
385     0,  // No NT only reg values\r
386     0,  // No 9x only reg values\r
387 \r
388     // Start menu entries to remove\r
389     "Documentation\\AFS for Windows Backup Command Reference.lnk\0Documentation\\AFS Command Reference Manual.lnk\0Documentation\\AFS System Administrator's Guide.lnk\0",\r
390 \r
391     0,  // No config info to preserve\r
392 \r
393     0   // No uninstall function\r
394 };\r
395 \r
396 \r
397 // Shared and in-use files\r
398 struct FILEINFO {\r
399     char *pszName;\r
400     int nUsedBy;\r
401 };\r
402 \r
403 #define SERVER  1\r
404 #define CLIENT  2\r
405 #define LCLIENT 4\r
406 #define CC      8\r
407 #define DOCS    16\r
408 \r
409 \r
410 struct FILEINFO fileInfo[] = {\r
411     { TARGETDIR"\\Common\\afsbosadmin.dll",             SERVER | CC },\r
412     { TARGETDIR"\\Common\\afscfgadmin.dll",             SERVER | CC },\r
413     { TARGETDIR"\\Common\\afsclientadmin.dll",          SERVER | CLIENT | LCLIENT | CC },\r
414     { TARGETDIR"\\Common\\afskasadmin.dll",             SERVER | CC },\r
415     { TARGETDIR"\\Common\\afsptsadmin.dll",             SERVER | CC },\r
416     { TARGETDIR"\\Common\\afsvosadmin.dll",             SERVER | CC },\r
417     { TARGETDIR"\\Common\\afsadminutil.dll",            SERVER | CLIENT | LCLIENT | CC },\r
418     { TARGETDIR"\\Common\\afsrpc.dll",                  SERVER | CLIENT | LCLIENT | CC },\r
419     { TARGETDIR"\\Common\\afsauthent.dll",              SERVER | CLIENT | LCLIENT | CC },\r
420     { TARGETDIR"\\Common\\pthread.dll",                 SERVER | CLIENT | LCLIENT | CC },\r
421     { TARGETDIR"\\Common\\TaAfsAppLib.dll",             SERVER | CLIENT | LCLIENT | CC },\r
422     { TARGETDIR"\\Common\\afsprocmgmt.dll",             SERVER | CLIENT | LCLIENT },\r
423     { TARGETDIR"\\Common\\afs_config.exe",              CLIENT | LCLIENT| CC },\r
424     { TARGETDIR"\\Common\\afseventmsg_????.dll",        SERVER | CLIENT | LCLIENT | CC },\r
425     { TARGETDIR"\\Common\\afslegal_????.dll",           SERVER | CLIENT | LCLIENT | CC },\r
426     { TARGETDIR"\\Common\\afsserver_????.dll",          SERVER | CLIENT | LCLIENT | CC },\r
427     { TARGETDIR"\\Common\\afssvrcfg_????.dll",          SERVER | CLIENT | LCLIENT | CC },\r
428     { TARGETDIR"\\Common\\TaAfsAccountManager_????.dll",SERVER | CLIENT | LCLIENT | CC },\r
429     { TARGETDIR"\\Common\\TaAfsAppLib_????.dll",        SERVER | CLIENT | LCLIENT | CC },\r
430     { TARGETDIR"\\Common\\TaAfsServerManager_????.dll", SERVER | CLIENT | LCLIENT | CC },\r
431     { TARGETDIR"\\Common\\afscreds_????.dll",           SERVER | CLIENT | LCLIENT | CC },\r
432     { TARGETDIR"\\Common\\afs_config_????.dll",         SERVER | CLIENT | LCLIENT | CC },\r
433     { TARGETDIR"\\Common\\afs_cpa_????.dll",            SERVER | CLIENT | LCLIENT | CC },\r
434     { TARGETDIR"\\Common\\afs_shl_ext_????.dll",        SERVER | CLIENT | LCLIENT | CC },\r
435     { TARGETDIR"\\Common\\afs-nt.hlp",                  SERVER | CLIENT | LCLIENT | CC },\r
436     { TARGETDIR"\\Common\\afs-nt.cnt",                  SERVER | CLIENT | LCLIENT | CC },\r
437     { TARGETDIR"\\Common\\taafssvrmgr.cnt",             SERVER | CLIENT | LCLIENT | CC },\r
438     { TARGETDIR"\\Common\\taafssvrmgr.hlp",             SERVER | CLIENT | LCLIENT | CC },\r
439     { TARGETDIR"\\Common\\taafsusrmgr.cnt",             SERVER | CLIENT | LCLIENT | CC },\r
440     { TARGETDIR"\\Common\\taafsusrmgr.hlp",             SERVER | CLIENT | LCLIENT | CC },\r
441     { TARGETDIR"\\Common\\afs-cc.cnt",                  SERVER | CLIENT | LCLIENT | CC },\r
442     { TARGETDIR"\\Common\\afs-cc.hlp",                  SERVER | CLIENT | LCLIENT | CC },\r
443     { TARGETDIR"\\Common\\afs-light.cnt",               SERVER | CLIENT | LCLIENT | CC },\r
444     { TARGETDIR"\\Common\\afs-light.hlp",               SERVER | CLIENT | LCLIENT | CC },\r
445     { TARGETDIR"\\Common\\taafscfg.cnt",                SERVER | CLIENT | LCLIENT | CC },\r
446     { TARGETDIR"\\Common\\taafscfg.hlp",                SERVER | CLIENT | LCLIENT | CC },\r
447     { TARGETDIR"\\Client\\PROGRAM\\afs_shl_ext.dll",    CLIENT | LCLIENT },\r
448     { TARGETDIR"\\Client\\PROGRAM\\libafsconf.dll",     CLIENT | LCLIENT },\r
449     { TARGETDIR"\\Client\\PROGRAM\\afslogon.dll",       CLIENT },\r
450     { TARGETDIR"\\Client\\PROGRAM\\afslog95.dll",       LCLIENT },\r
451     { TARGETDIR"\\Control Center\\TaAfsAdmSvr.exe",     CC },\r
452     { WINSYSDIR"\\afs_cpa.cpl",                         CLIENT | LCLIENT | CC },\r
453     { WINSYSDIR"\\afsserver.cpl",                       SERVER },\r
454     { TARGETDIR"\\Common\\afsdcell.ini",                CLIENT | LCLIENT | CC },\r
455     { TARGETDIR"\\Documentation\\Html\\banner.gif",     SERVER | CLIENT | LCLIENT | CC | DOCS },\r
456     { TARGETDIR"\\Documentation\\Html\\books.gif",      SERVER | CLIENT | LCLIENT | CC | DOCS },\r
457     { TARGETDIR"\\Documentation\\Html\\bot.gif",        SERVER | CLIENT | LCLIENT | CC | DOCS },\r
458     { TARGETDIR"\\Documentation\\Html\\index.gif",      SERVER | CLIENT | LCLIENT | CC | DOCS },\r
459     { TARGETDIR"\\Documentation\\Html\\index.htm",      SERVER | CLIENT | LCLIENT | CC | DOCS },\r
460     { TARGETDIR"\\Documentation\\Html\\next.gif",       SERVER | CLIENT | LCLIENT | CC | DOCS },\r
461     { TARGETDIR"\\Documentation\\Html\\prev.gif",       SERVER | CLIENT | LCLIENT | CC | DOCS },\r
462     { TARGETDIR"\\Documentation\\Html\\toc.gif",        SERVER | CLIENT | LCLIENT | CC | DOCS },\r
463     { TARGETDIR"\\Documentation\\Html\\top.gif",        SERVER | CLIENT | LCLIENT | CC | DOCS },\r
464     { TARGETDIR"\\Documentation\\Html\\ReleaseNotes\\relnotes.htm",\r
465                                                         SERVER | CLIENT | LCLIENT | CC },\r
466     { TARGETDIR"\\Documentation\\Html\\InstallGd\\afsnt35i.htm",\r
467                                                         SERVER | CLIENT | LCLIENT | CC },\r
468     { 0,                                                0 }     // End of list\r
469 };\r
470 \r
471 \r
472 /*\r
473  * VARIABLES _________________________________________________________________\r
474  *\r
475  */\r
476 HINSTANCE hinst;\r
477 \r
478 static HWND hDlg;\r
479 static BOOL bPreserveConfigInfo;\r
480 static BOOL bSilentMode;\r
481 static char *pszInstallDir;\r
482 \r
483 \r
484 /*\r
485  * FUNCTIONS _________________________________________________________________\r
486  *\r
487  */\r
488 \r
489 static BOOL UpgradeClientIntParm(HKEY hKey, char *pszOldParm, char *pszNewParm)\r
490 {\r
491     int nData;\r
492     LONG result = ERROR_SUCCESS;\r
493 \r
494     nData = GetPrivateProfileInt("AFS Client", pszOldParm, -1, "afsd.ini");\r
495     if (nData > -1)\r
496         result = RegSetValueEx(hKey, pszNewParm, 0, REG_DWORD, (BYTE *)&nData, sizeof(nData));\r
497 \r
498     return (result == ERROR_SUCCESS);\r
499 }\r
500 \r
501 static BOOL UpgradeClientStringParm(HKEY hKey, char *pszOldParm, char *pszNewParm)\r
502 {\r
503     char szData[1024];\r
504     LONG result = ERROR_SUCCESS;\r
505 \r
506     GetPrivateProfileString("AFS Client", pszOldParm, "", szData, sizeof(szData), "afsd.ini");\r
507     if (szData[0])\r
508         result = RegSetValueEx(hKey, pszNewParm, 0, REG_SZ, (PBYTE)szData, strlen(szData) + 1);\r
509 \r
510     return (result == ERROR_SUCCESS);\r
511 }\r
512 \r
513 int SUCALLCONV Upgrade34ClientConfigInfo()\r
514 {\r
515     HKEY hKey;\r
516     LONG result;\r
517     int nData;\r
518     \r
519     result = RegOpenKeyAlt(AFSREG_NULL_KEY, AFSREG_CLT_SVC_PARAM_KEY, KEY_WRITE, TRUE, &hKey, 0);\r
520     if (result != ERROR_SUCCESS)\r
521         return -1;\r
522 \r
523     UpgradeClientIntParm(hKey, "CacheSize", "CacheSize");\r
524     UpgradeClientIntParm(hKey, "Stats", "Stats");\r
525     UpgradeClientIntParm(hKey, "LogoffTokenTransfer", "LogoffTokenTransfer");\r
526     UpgradeClientIntParm(hKey, "LogoffTokenTransferTimeout", "LogoffTokenTransferTimeout");\r
527     UpgradeClientIntParm(hKey, "TrapOnPanic", "TrapOnPanic");\r
528     UpgradeClientIntParm(hKey, "TraceBufferSize", "TraceBufferSize");\r
529     UpgradeClientIntParm(hKey, "TraceOnShutdown", "TraceOnShutdown");\r
530     UpgradeClientIntParm(hKey, "ReportSessionStartups", "ReportSessionStartups");\r
531     \r
532     UpgradeClientStringParm(hKey, "MountRoot", "MountRoot");\r
533     UpgradeClientStringParm(hKey, "Cell", "Cell");\r
534 \r
535     /* BlockSize to ChunkSize requires convertion */\r
536     nData = GetPrivateProfileInt("AFS Client", "BlockSize", -1, "afsd.ini");\r
537     if (nData > -1) {\r
538         DWORD chunkSize;\r
539         for (chunkSize = 0; (1 << chunkSize) < nData; chunkSize++);\r
540         (void) RegSetValueEx(hKey, "ChunkSize", 0, REG_DWORD, (BYTE *)&chunkSize, sizeof(chunkSize));\r
541     }\r
542 \r
543     RegCloseKey(hKey);\r
544 \r
545     return 0;\r
546 }\r
547 \r
548 int SUCALLCONV Eradicate34Client()\r
549 {\r
550     if (Client34Eradicate(TRUE) != ERROR_SUCCESS)\r
551         return -1;\r
552 \r
553     return 0;\r
554 }\r
555 \r
556 // This function was written a long time ago by Mike Comer for use by the \r
557 // original DFS Client for NT install program.\r
558 int SUCALLCONV CheckIfAdmin(void)\r
559 {\r
560     HANDLE                  token = INVALID_HANDLE_VALUE;\r
561     PVOID                   buffer = 0;\r
562     DWORD                   bufLength;\r
563     DWORD                   realBufLength;\r
564     TOKEN_PRIMARY_GROUP     *pgroup;\r
565     TOKEN_GROUPS            *groups;\r
566     int                     result = -1;\r
567     DWORD                   groupCount;\r
568     LONG                    status;\r
569     PSID                    AdministratorSID = NULL;\r
570     SID_IDENTIFIER_AUTHORITY    authority = SECURITY_NT_AUTHORITY;\r
571 \r
572     // allocate the SID for the Administrators group\r
573     if (!AllocateAndInitializeSid(&authority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &AdministratorSID)) {\r
574         status = GetLastError();\r
575         goto getout;\r
576     }\r
577 \r
578     // open the process token\r
579     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token)) {\r
580         status = GetLastError();\r
581         token = INVALID_HANDLE_VALUE;\r
582         goto getout;\r
583     }\r
584 \r
585     // check primary group first\r
586     buffer = GlobalAlloc(GMEM_FIXED, sizeof(TOKEN_PRIMARY_GROUP));\r
587     if (!buffer) {\r
588         goto getout;\r
589     }\r
590 \r
591     bufLength = sizeof(TOKEN_PRIMARY_GROUP);\r
592     while(1) {\r
593         if (!GetTokenInformation(token, TokenPrimaryGroup, buffer, bufLength, &realBufLength)) {\r
594             if (realBufLength > bufLength) {\r
595                 // not enough space\r
596                 GlobalFree(buffer);\r
597                 bufLength = realBufLength;\r
598                 buffer = GlobalAlloc(GMEM_FIXED, realBufLength);\r
599                 if (!buffer) {\r
600                     goto getout;\r
601                 }\r
602                 continue;\r
603             }\r
604 \r
605             goto getout;\r
606         }\r
607         break;\r
608     }\r
609 \r
610     pgroup = (TOKEN_PRIMARY_GROUP *)buffer;\r
611     if (EqualSid(pgroup->PrimaryGroup, AdministratorSID)) {\r
612         result = 0;\r
613     } else {\r
614         // okay, try the secondary groups\r
615         while(1) {\r
616             if (!GetTokenInformation(token, TokenGroups, buffer, bufLength, &realBufLength)) {\r
617                 if (realBufLength > bufLength) {\r
618                     // not enough space\r
619                     GlobalFree(buffer);\r
620                     bufLength = realBufLength;\r
621                     buffer = GlobalAlloc(GMEM_FIXED, realBufLength);\r
622                     if (!buffer) {\r
623                         goto getout;\r
624                     }\r
625                     continue;\r
626                 }\r
627 \r
628                 // a real error\r
629                 goto getout;\r
630             }\r
631             break;\r
632         }\r
633 \r
634         // we have the list of groups here.  Process them:\r
635         groups = (TOKEN_GROUPS *)buffer;\r
636         for(groupCount = 0; groupCount < groups->GroupCount; groupCount++) {\r
637             if (EqualSid(groups->Groups[groupCount].Sid, AdministratorSID)) {\r
638                 result = 0;\r
639                 break;\r
640             }\r
641         }\r
642     }\r
643 \r
644 getout:\r
645 \r
646     if (token != INVALID_HANDLE_VALUE) {\r
647         CloseHandle(token);\r
648     }\r
649 \r
650     if (buffer) {\r
651         GlobalFree(buffer);\r
652     }\r
653 \r
654     if (AdministratorSID) {\r
655         FreeSid(AdministratorSID);\r
656     }\r
657 \r
658     return result;\r
659 }\r
660 \r
661 static void SetSharedFileRefCount(char *pszFile, int nRefCount)\r
662 {\r
663     LONG result;\r
664     HKEY hKey;\r
665     \r
666     result = RegOpenKeyAlt(AFSREG_NULL_KEY, MS_SHARED_FILES_KEY, KEY_WRITE, FALSE, &hKey, 0);\r
667     if (result != ERROR_SUCCESS)\r
668         return;\r
669     \r
670     if (nRefCount <= 0)\r
671         RegDeleteValue(hKey, pszFile);\r
672     else\r
673         RegSetValueEx(hKey, pszFile, 0, REG_DWORD, (BYTE *)&nRefCount, sizeof(int));    \r
674     \r
675     RegCloseKey(hKey);\r
676 }\r
677 \r
678 static char *GetTimeStamp()\r
679 {\r
680     char szTime[64], szDate[64];\r
681     static char szTimeDate[128];\r
682 \r
683     _strtime(szTime);\r
684     _strdate(szDate);\r
685 \r
686     sprintf(szTimeDate, "[%s %s] ", szTime, szDate);\r
687     \r
688     return szTimeDate;\r
689 }\r
690 \r
691 int SUCALLCONV WriteToInstallErrorLog(char *pszMsg)\r
692 {\r
693     static BOOL bWritten = FALSE;\r
694     FILE *fp;\r
695 \r
696     // On the first write, recreate the file    \r
697     fp = fopen(INSTALL_ERROR_LOG_NAME, bWritten ? "a" : "w");\r
698     if (!fp)\r
699         return -1;\r
700         \r
701     fprintf(fp, "%s%s\r\n", GetTimeStamp(), pszMsg);\r
702     \r
703     fclose(fp);\r
704     \r
705     bWritten = TRUE;\r
706     \r
707     return 0;\r
708 }\r
709 \r
710 static void WriteToUninstallErrorLog(char *pszMsg)\r
711 {\r
712     static BOOL bWritten = FALSE;\r
713     FILE *fp;\r
714 \r
715     // On the first write, recreate the file    \r
716     fp = fopen(UNINSTALL_ERROR_LOG_NAME, bWritten ? "a" : "w");\r
717     if (!fp)\r
718         return;\r
719         \r
720     fprintf(fp, "%s%s\r\n", GetTimeStamp(), pszMsg);\r
721     \r
722     fclose(fp);\r
723     \r
724     bWritten = TRUE;\r
725 }\r
726 \r
727 static char *LoadResString(UINT uID)\r
728 {\r
729     static char str[256];\r
730     GetString (str, uID);\r
731     return str;\r
732 }\r
733 \r
734 static void ShowError(UINT nResID, LONG nError)\r
735 {\r
736     char szErr[256];\r
737     char szPrompt[256];\r
738     char szMsg[256];\r
739     char szTitle[256];\r
740     char *psz;\r
741 \r
742     psz = LoadResString(nResID);\r
743     if (psz)\r
744         strcpy(szErr, psz);\r
745     else\r
746         sprintf(szErr, "unknown error msg (Msg ID = %d)", nResID);\r
747     \r
748     psz = LoadResString(IDS_INSTALLATION_FAILURE);\r
749     strcpy(szPrompt, psz ? psz : "An error has occurred:  %s (Last Error = %ld).");\r
750 \r
751     sprintf(szMsg, szPrompt, szErr, nError);\r
752 \r
753     psz = LoadResString(IDS_TITLE);\r
754     strcpy(szTitle, psz ? psz : "AFS");\r
755 \r
756     if (bSilentMode)\r
757         WriteToUninstallErrorLog(szMsg);\r
758     else\r
759         MessageBox(hDlg, szMsg, szTitle, MB_OK);\r
760 }\r
761 \r
762 static int ShowMsg(UINT nResID, int nType)\r
763 {\r
764     char szTitle[256];\r
765     char *psz;\r
766 \r
767     psz = LoadResString(IDS_TITLE);\r
768     strcpy(szTitle, psz ? psz : "AFS");\r
769 \r
770     return MessageBox(hDlg, LoadResString(nResID), szTitle, nType);\r
771 }\r
772 \r
773 static char *GetAppInstallDir(struct APPINFO *pApp, BOOL bRemembered)\r
774 {\r
775     HKEY hKey;\r
776     LONG nResult;\r
777     DWORD dwType;\r
778     static char szInstallDir[256];\r
779     DWORD dwSize;\r
780     char *pszKey;\r
781     char *pszValue;\r
782 \r
783     pszKey = bRemembered ? UNINSTALL_TEMP_INFO_KEY : pApp->regInstallDir.pszKey;\r
784     pszValue = bRemembered ? INSTALL_DIR_VALUE_NAME : pApp->regInstallDir.pszValue;\r
785 \r
786     dwSize = sizeof(szInstallDir);\r
787 \r
788     nResult = RegOpenKeyAlt(AFSREG_NULL_KEY, pszKey, KEY_READ, FALSE, &hKey, 0);\r
789     if (nResult == ERROR_SUCCESS) {\r
790         nResult = RegQueryValueEx(hKey, pszValue, 0, &dwType, (PBYTE)szInstallDir, &dwSize);\r
791         RegCloseKey(hKey);\r
792     }\r
793 \r
794     if (nResult != ERROR_SUCCESS) {\r
795         ShowError(IDS_CANT_DETERMINE_APP_PATH, nResult);\r
796         return 0;\r
797     }\r
798 \r
799     FilepathNormalizeEx(szInstallDir, FPN_BACK_SLASHES);\r
800 \r
801     return szInstallDir;\r
802 }\r
803 \r
804 static BOOL DoesRegKeyExist(char *pszKey)\r
805 {\r
806     HKEY hKey;\r
807     LONG nResult;\r
808 \r
809     nResult = RegOpenKeyAlt(AFSREG_NULL_KEY, pszKey, KEY_READ, FALSE, &hKey, 0);\r
810     if (nResult == ERROR_SUCCESS) {\r
811         RegCloseKey(hKey);\r
812         return TRUE;\r
813     }\r
814 \r
815     return FALSE;\r
816 }\r
817 \r
818 static BOOL IsAppInstalled(struct APPINFO *pApp)\r
819 {\r
820     return DoesRegKeyExist(pApp->pszAppKey);\r
821 }\r
822 \r
823 static void BuildShortPath(char *pszShortPath, UINT nShortPathLen, char *pszInstallDir, char *pszPath)\r
824 {\r
825     strncpy(pszShortPath, pszInstallDir, nShortPathLen);\r
826     strncat(pszShortPath, pszPath, nShortPathLen);\r
827     \r
828     GetShortPathName(pszShortPath, pszShortPath, nShortPathLen);\r
829 }\r
830 \r
831 static BOOL IsWin95()\r
832 {\r
833     OSVERSIONINFO versionInformation;\r
834 \r
835     versionInformation.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);\r
836     \r
837     GetVersionEx(&versionInformation);\r
838     \r
839     if ((versionInformation.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) &&\r
840         (versionInformation.dwMinorVersion == 0))\r
841         return TRUE;\r
842         \r
843     return FALSE;\r
844 }\r
845 \r
846 int IsWin98()\r
847 {\r
848     OSVERSIONINFO versionInformation;\r
849 \r
850     versionInformation.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);\r
851     \r
852     GetVersionEx(&versionInformation);\r
853     \r
854     if ((versionInformation.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) &&\r
855         (versionInformation.dwMinorVersion == 10))\r
856         return 0;\r
857         \r
858     return -1;\r
859 }\r
860 \r
861 static BOOL IsServiceInstalled(char *pszServiceKey)\r
862 {\r
863     HKEY hKey;\r
864 \r
865     if (RegOpenKeyAlt(0, pszServiceKey, KEY_READ, FALSE, &hKey, 0) == ERROR_SUCCESS) {\r
866         RegCloseKey(hKey);\r
867         return TRUE;\r
868     }\r
869 \r
870     return FALSE;\r
871 }\r
872 \r
873 // If this fails in anyway we just return.  No error is displayed.\r
874 static void MakeSureServiceDoesNotExist(char *pszName)\r
875 {\r
876     SC_HANDLE hServer = 0, hSCM = 0;\r
877     SERVICE_STATUS status;\r
878 \r
879     hSCM = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);\r
880     if (hSCM) {\r
881         hServer = OpenService(hSCM, pszName, SERVICE_ALL_ACCESS | DELETE);\r
882         if (hServer) {\r
883             if (QueryServiceStatus(hServer, &status)) {\r
884                 if (status.dwCurrentState != SERVICE_STOPPED) {\r
885                     if (!ControlService(hServer, SERVICE_CONTROL_STOP, &status)) {\r
886                         CloseServiceHandle(hServer);\r
887                         CloseServiceHandle(hSCM);\r
888                         return;\r
889                     }\r
890                 }\r
891             }\r
892             \r
893             // Try to delete even if status query fails\r
894             DeleteService(hServer);\r
895         }\r
896     }\r
897 \r
898     if (hServer)\r
899         CloseServiceHandle(hServer);\r
900     if (hSCM)\r
901         CloseServiceHandle(hSCM);\r
902 }\r
903 \r
904 static int InstallService(char *pszName, char *pszDependOn, char *pszDisplayName, char *pszServicePath, BOOL bInteractive)\r
905 {\r
906     SC_HANDLE hServer = 0, hSCM;\r
907     BOOL bRestoreOldConfig = FALSE;\r
908 \r
909     hSCM = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);\r
910     if (!hSCM) {\r
911         ShowError(IDS_SCM_OPEN_FAILED, GetLastError());\r
912         return -1;\r
913     }\r
914 \r
915 /*  This code is not used, but it could be handy in the future so I am keeping it here.\r
916 \r
917     // If the service exists, then we (most probably) are in the middle of an upgrade or reinstall.\r
918     bRestoreOldConfig = IsServiceInstalled(pszName);\r
919 \r
920     if (bRestoreOldConfig) {\r
921         hServer = OpenService(hSCM, pszName, SERVICE_ALL_ACCESS);\r
922         if (!hServer || !ChangeServiceConfig(hServer, SERVICE_NO_CHANGE, SERVICE_AUTO_START, SERVICE_NO_CHANGE, 0, 0, 0, 0, 0, 0, 0)) {\r
923             ShowError(IDS_RESTORE_OF_PREVIOUS_CONFIG_FAILED, GetLastError());\r
924             bRestoreOldConfig = FALSE;\r
925             // Fall through to service creation below\r
926         }\r
927     } \r
928 */\r
929     \r
930     if (!bRestoreOldConfig) {\r
931         DWORD dwServiceType;\r
932 \r
933         // If the service already exists, the create call will fail.  This can\r
934         // happen if uninstall failed (which is not infrequent).  Making sure the\r
935         // service does not exist makes it easier for a user to install over top of\r
936         // a previously failed uninstall.\r
937         MakeSureServiceDoesNotExist(pszName);\r
938 \r
939         dwServiceType = SERVICE_WIN32_OWN_PROCESS;\r
940         if (bInteractive)\r
941             dwServiceType |= SERVICE_INTERACTIVE_PROCESS;\r
942     \r
943         hServer = CreateService(hSCM, pszName, pszDisplayName,\r
944             SERVICE_ALL_ACCESS, dwServiceType, SERVICE_AUTO_START, \r
945             SERVICE_ERROR_NORMAL, pszServicePath, 0, 0, "RPCSS\0Netbios\0\0", 0, 0);\r
946     \r
947         if (!hServer)\r
948             ShowError(IDS_SERVICE_CREATE_FAILED, GetLastError());\r
949     }\r
950 \r
951     if (hServer)\r
952         CloseServiceHandle(hServer);\r
953 \r
954     CloseServiceHandle(hSCM);\r
955 \r
956     return 0;\r
957 }\r
958 \r
959 int SUCALLCONV InstallServerService(char *pszServicePath)\r
960 {\r
961     return InstallService(appServer.pszSvcName, 0, appServer.pszSvcDisplayName, pszServicePath, TRUE);\r
962 }\r
963 \r
964 int SUCALLCONV InstallClientService(char *pszServicePath)\r
965 {\r
966     return InstallService(appClient.pszSvcName, appClient.pszSvcDependOn, appClient.pszSvcDisplayName, pszServicePath, FALSE);\r
967 }\r
968 \r
969 static int UninstallService(struct APPINFO *pAppInfo)\r
970 {\r
971     SC_HANDLE hServer, hSCM;\r
972     SERVICE_STATUS status;\r
973     BOOL bOk;\r
974     BOOL bServer = FALSE;\r
975     BOOL bShowingProgressDlg = FALSE;\r
976 \r
977     hSCM = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);\r
978     if (!hSCM) {\r
979         ShowError(IDS_SCM_OPEN_FAILED, GetLastError());\r
980         return -1;\r
981     }\r
982     \r
983     hServer = OpenService(hSCM, pAppInfo->pszSvcName, SERVICE_ALL_ACCESS | DELETE);\r
984     if (!hServer) {\r
985         ShowError(IDS_SERVICE_OPEN_FAILED, GetLastError());\r
986         CloseServiceHandle(hSCM);\r
987         return -1;\r
988     }\r
989 \r
990     if (!QueryServiceStatus(hServer, &status)) {\r
991         ShowError(IDS_SERVICE_QUERY_FAILED, GetLastError());\r
992         CloseServiceHandle(hServer);\r
993         CloseServiceHandle(hSCM);\r
994         return -1;\r
995     }\r
996 \r
997     if (status.dwCurrentState != SERVICE_STOPPED) {\r
998         if (pAppInfo->nServiceShutdownMsgID) {\r
999             if (!bSilentMode && (ShowMsg(pAppInfo->nServiceShutdownMsgID, MB_YESNO | MB_ICONQUESTION) == IDNO)) {\r
1000                 CloseServiceHandle(hServer);\r
1001                 CloseServiceHandle(hSCM);\r
1002                 return 1;\r
1003             }\r
1004         }\r
1005 \r
1006         if (!bSilentMode)\r
1007             bShowingProgressDlg = ShowProgressDialog(LoadResString(pAppInfo->nServiceShutdownProgressMsgID));\r
1008 \r
1009         if (!ControlService(hServer, SERVICE_CONTROL_STOP, &status)) {\r
1010             if (bShowingProgressDlg)\r
1011                 HideProgressDialog();\r
1012             ShowError(IDS_SERVICE_STOP_FAILED, GetLastError());\r
1013             CloseServiceHandle(hServer);\r
1014             CloseServiceHandle(hSCM);\r
1015             return -1;\r
1016         }\r
1017     }\r
1018 \r
1019     // Wait for the service to stop\r
1020     while (status.dwCurrentState != SERVICE_STOPPED) {\r
1021         // I stopped waiting on dwWaitHint because it seemed the wait hint was too long.\r
1022         // The service would be stopped but we'd still be asleep for a long time yet.\r
1023         Sleep(5000);    //status.dwWaitHint);\r
1024 \r
1025         if (!QueryServiceStatus(hServer, &status)) {\r
1026             if (bShowingProgressDlg)\r
1027                 HideProgressDialog();\r
1028             ShowError(IDS_SERVICE_QUERY_FAILED, GetLastError());\r
1029             CloseServiceHandle(hServer);\r
1030             CloseServiceHandle(hSCM);\r
1031             return -1;\r
1032         }\r
1033     }\r
1034 \r
1035     // The service has been stopped\r
1036     if (bShowingProgressDlg)\r
1037         HideProgressDialog();\r
1038 \r
1039     // This code to disable the service may be of use some day so I am keeping it here.\r
1040     // bOk = ChangeServiceConfig(hServer, SERVICE_NO_CHANGE, SERVICE_DISABLED, SERVICE_NO_CHANGE, 0, 0, 0, 0, 0, 0, 0); \r
1041 \r
1042     bOk = DeleteService(hServer);\r
1043 \r
1044     if (!bOk)\r
1045         ShowError(IDS_SERVICE_DELETE_FAILED, GetLastError());\r
1046 \r
1047     CloseServiceHandle(hServer);\r
1048     CloseServiceHandle(hSCM);\r
1049 \r
1050     return (bOk ? 0 : -1);\r
1051 }\r
1052 \r
1053 int SUCALLCONV AddToNetworkProviderOrder(char *pszWhatToAdd)\r
1054 {\r
1055     return AddToProviderOrder(pszWhatToAdd) ? 0 : -1;\r
1056 }\r
1057 \r
1058 static int RemoveFromNetworkProviderOrder(char *pszWhatToDel)\r
1059 {\r
1060     return RemoveFromProviderOrder(pszWhatToDel) ? 0 : -1;\r
1061 }\r
1062 \r
1063 int SUCALLCONV AddToPath(char *pszPath)\r
1064 {\r
1065     return AddToSystemPath(pszPath) ? 0 : -1;\r
1066 }\r
1067 \r
1068 static int RemoveFromPath(char *pszPath)\r
1069 {\r
1070     return RemoveFromSystemPath(pszPath) ? 0 : -1;\r
1071 }\r
1072 \r
1073 static void RemoveFiles(char *pszFileSpec)\r
1074 {\r
1075     struct _finddata_t fileinfo;\r
1076     long hSearch;\r
1077     char szDel[MAX_PATH];\r
1078     char szDir[MAX_PATH];\r
1079     char *p;\r
1080 \r
1081     strcpy(szDir, pszFileSpec);\r
1082     p = strrchr(szDir, '\\');\r
1083     if (p)\r
1084         *p = 0;\r
1085     \r
1086     hSearch = _findfirst(pszFileSpec, &fileinfo);\r
1087     if (hSearch == -1)\r
1088         return;\r
1089 \r
1090     while (1) {\r
1091         if ((strcmp(fileinfo.name, ".") != 0) && (strcmp(fileinfo.name, "..") != 0)) {\r
1092             sprintf(szDel, "%s\\%s", szDir, fileinfo.name);\r
1093             DeleteFile(szDel);\r
1094         }\r
1095 \r
1096         if (_findnext(hSearch, &fileinfo) == -1)\r
1097             break;\r
1098     }\r
1099 \r
1100     _findclose(hSearch);\r
1101 }\r
1102 \r
1103 static void RemoveDir(char *pszDir)\r
1104 {\r
1105     char szFileSpec[MAX_PATH];\r
1106 \r
1107     sprintf(szFileSpec, "%s\\*.*", pszDir);\r
1108 \r
1109     RemoveFiles(szFileSpec);\r
1110     RemoveDirectory(pszDir);\r
1111 }\r
1112 \r
1113 static void RemoveRegValues(struct REGVALUE *pRegValues)\r
1114 {\r
1115     struct REGVALUE *pCurValue;\r
1116     HKEY hKey;\r
1117     LONG nResult;\r
1118 \r
1119     if (!pRegValues)\r
1120         return;\r
1121 \r
1122     for (pCurValue = pRegValues; pCurValue->pszKey; pCurValue++) {\r
1123         nResult = RegOpenKeyAlt(AFSREG_NULL_KEY, pCurValue->pszKey, KEY_ALL_ACCESS, FALSE, &hKey, 0);\r
1124 \r
1125         if (nResult == ERROR_SUCCESS) {\r
1126             nResult = RegDeleteValue(hKey, pCurValue->pszValue);\r
1127             RegCloseKey(hKey);\r
1128         }\r
1129 \r
1130         if (nResult != ERROR_SUCCESS)\r
1131             ShowError(IDS_REG_DELETE_VALUE_ERROR, nResult);\r
1132     }\r
1133 }\r
1134 \r
1135 static BOOL UninstallCredsTool()\r
1136 {\r
1137     int nResult = WinExec("afscreds /uninstall", SW_HIDE);\r
1138 \r
1139     if (nResult <= 31) {\r
1140         if (nResult != ERROR_FILE_NOT_FOUND)\r
1141             ShowError(IDS_CANT_UNINSTALL_AFSCREDS, nResult);\r
1142     }\r
1143 \r
1144     // Always return true.  We don't want the uninstall to completely fail just\r
1145     // because the creds tool didn't uninstall.\r
1146     return TRUE;\r
1147 }\r
1148 \r
1149 \r
1150 static char *GetTempDir()\r
1151 {\r
1152     DWORD result;\r
1153     static char szTempDir[MAX_PATH];\r
1154 \r
1155     result = GetTempPath(sizeof(szTempDir) - 1, szTempDir);\r
1156     if (result == 0)\r
1157         return "\\";\r
1158         \r
1159     return szTempDir;\r
1160 }\r
1161 \r
1162 static char *GetRootInstallDir()\r
1163 {\r
1164     char *psz;\r
1165     static char szRootInstallDir[MAX_PATH] = "";\r
1166 \r
1167     if (szRootInstallDir[0] == 0) {\r
1168         strcpy(szRootInstallDir, pszInstallDir);\r
1169     \r
1170         // Strip off the app specific part of the install dir\r
1171         psz = strrchr(szRootInstallDir, '\\');\r
1172         if (psz)\r
1173             *psz = 0;\r
1174     }\r
1175 \r
1176     return szRootInstallDir;\r
1177 }\r
1178 \r
1179 static BOOL ClientSpecificUninstall()\r
1180 {\r
1181     int nChoice;\r
1182 \r
1183     // This function needs to do two things.  First it needs to see if the server is\r
1184     // installed, and if it is, ask the user if they really want to uninstall the\r
1185     // client given that the server needs the client.  Second, if we are uninstalling\r
1186     // the client, we need to uninstall the creds tool.\r
1187 \r
1188     if (!bSilentMode) {\r
1189         if (IsAppInstalled(&appServer)) {\r
1190             nChoice = ShowMsg(IDS_CLIENT_NEEDED_BY_SERVER, MB_ICONQUESTION | MB_YESNO);\r
1191             if (nChoice == IDNO)\r
1192                 return FALSE;       // Cancel the uninstall\r
1193         }\r
1194     }\r
1195     \r
1196     UninstallCredsTool();\r
1197 \r
1198     return TRUE;\r
1199 }\r
1200 \r
1201 static struct APPINFO *GetApp()\r
1202 {\r
1203 #ifdef SERVER_UNINST\r
1204     return &appServer;\r
1205 #elif CLIENT_UNINST\r
1206     return &appClient;\r
1207 #elif CC_UNINST\r
1208     return &appControlCenter;\r
1209 #elif LIGHT_CLIENT_UNINST\r
1210     return &appLightClient;\r
1211 #elif DOCS_UNINST\r
1212     return &appDocs;\r
1213 #else\r
1214     return 0;\r
1215 #endif;\r
1216 }\r
1217 \r
1218 static void RememberInstallDir(char *pszInstallDir)\r
1219 {\r
1220     HKEY hKey;\r
1221 \r
1222     // We remember the install dir so that when the UninstUninitialize function is called\r
1223     // by the InstallShield uninstaller, we can find out where we were installed to.  We\r
1224     // have to do this because by the time that function is called, the registry values\r
1225     // created at install time are already gone.  We need to be able to find out where we\r
1226     // were installed so we can clean up anything IS couldn't uninstall.  If this fails in \r
1227     // any way then we don't care.  The only consequence is that some junk might be left on\r
1228     // the users' system after an uninstall.\r
1229     \r
1230     LONG result = RegOpenKeyAlt(AFSREG_NULL_KEY, UNINSTALL_TEMP_INFO_KEY, KEY_WRITE, TRUE, &hKey, 0);\r
1231     if (result != ERROR_SUCCESS)\r
1232         return;\r
1233 \r
1234     RegSetValueEx(hKey, INSTALL_DIR_VALUE_NAME, 0, REG_SZ, (PBYTE)pszInstallDir, strlen(pszInstallDir) + 1);    \r
1235 \r
1236     RegCloseKey(hKey);\r
1237 }\r
1238 \r
1239 int SUCALLCONV SetSilentMode()\r
1240 {\r
1241     bSilentMode = TRUE;\r
1242 \r
1243     return 0;\r
1244 }\r
1245 \r
1246 static char *GetWinDir()\r
1247 {\r
1248     static char szWinDir[MAX_PATH] = "";\r
1249 \r
1250     if (!szWinDir[0]) \r
1251         GetWindowsDirectory(szWinDir, sizeof(szWinDir));\r
1252     \r
1253     return szWinDir;\r
1254 }\r
1255 \r
1256 static char *GetWinSysDir()\r
1257 {\r
1258     static char szWinSysDir[MAX_PATH] = "";\r
1259 \r
1260     if (!szWinSysDir[0])\r
1261         GetSystemDirectory(szWinSysDir, sizeof(szWinSysDir));\r
1262     \r
1263     return szWinSysDir;\r
1264\r
1265 \r
1266 static char *GetLocaleID()\r
1267 {\r
1268     static char szID[25] = "";\r
1269 \r
1270     if (szID[0] == 0) {\r
1271         LCID dwID = GetSystemDefaultLCID();\r
1272         \r
1273          // Nuke the high word.  It contains a sort ID.\r
1274         dwID &= 0x0000FFFF;\r
1275         \r
1276         // Convert locale ID to a string\r
1277         itoa(dwID, szID, 10);\r
1278 \r
1279         // This thing should never be more than LOCALE_ID_LEN characters long.\r
1280         szID[LOCALE_ID_LEN] = 0;\r
1281     }\r
1282 \r
1283     return szID;\r
1284 }\r
1285 \r
1286 static char *ExpandPath(char *pszFile)\r
1287 {\r
1288     static char szPath[MAX_PATH];\r
1289     char *psz;\r
1290 \r
1291     szPath[0] = 0;\r
1292 \r
1293     // Convert a path containing TARGETDIR, WINDIR, or WINSYSDIR to a \r
1294     // real path in the file system.  One of these MUST be the start of\r
1295     // the file path passed in.  Also convert the string ???? to an\r
1296     // actual locale number.\r
1297     if (strncmp(pszFile, TARGETDIR, strlen(TARGETDIR)) == 0)\r
1298         strcpy(szPath, GetRootInstallDir());\r
1299     else if (strncmp(pszFile, WINDIR, strlen(WINDIR)) == 0)\r
1300         strcpy(szPath, GetWinDir());\r
1301     else if (strncmp(pszFile, WINSYSDIR, strlen(WINSYSDIR)) == 0)\r
1302         strcpy(szPath, GetWinSysDir());\r
1303     \r
1304     if (szPath[0]) {    \r
1305         psz = strchr(pszFile, '\\');\r
1306         if (psz)\r
1307             strcat(szPath, psz);\r
1308     } else\r
1309         strcpy(szPath, pszFile);\r
1310 \r
1311     // Is this a language dll?\r
1312     psz = strstr(szPath, "????.");\r
1313     \r
1314     // If it is, replace ???? with the locale number\r
1315     if (psz)\r
1316         strncpy(psz, GetLocaleID(), LOCALE_ID_LEN);\r
1317 \r
1318     return szPath;\r
1319 }\r
1320 \r
1321 static BOOL FileNeededByOtherApp(struct APPINFO *pApp, struct FILEINFO *pFileInfo)\r
1322 {\r
1323     // If the file is used by the server, the app being uninstalled is not the server, and\r
1324     // the server is installed, then this file is used by another app.\r
1325     if (!IsWinNT()) {\r
1326         if ((pFileInfo->nUsedBy & LCLIENT) && (pApp != &appLightClient) && IsAppInstalled(&appLightClient))\r
1327             return TRUE;\r
1328         return FALSE;\r
1329     }\r
1330 \r
1331     if ((pFileInfo->nUsedBy & SERVER) && (pApp != &appServer) && IsAppInstalled(&appServer))\r
1332         return TRUE;\r
1333 \r
1334     if ((pFileInfo->nUsedBy & CLIENT) && (pApp != &appClient) && IsAppInstalled(&appClient))\r
1335         return TRUE;\r
1336 \r
1337     if ((pFileInfo->nUsedBy & CC) && (pApp != &appControlCenter) && IsAppInstalled(&appControlCenter))\r
1338         return TRUE;\r
1339     \r
1340     return FALSE;\r
1341 }\r
1342 \r
1343 static void DeleteInUseFiles(struct APPINFO *pAppInfo, struct FILEINFO *pFileInfo)\r
1344 {\r
1345     char szSrcPath[MAX_PATH];\r
1346     char szDestPath[MAX_PATH];\r
1347     char szTempDir[MAX_PATH];\r
1348     int ii;\r
1349 \r
1350     // If some app's file has been loaded before the app is uninstalled, then\r
1351     // when an uninstall is attempted, the application and all of the dlls that\r
1352     // its uses will be in use and IS will not be able to delete them.  Normally this\r
1353     // is not a problem because IS will tell the user to reboot to finish the uninstall.\r
1354     // However, we must support the ability to perform a silent uninstall followed\r
1355     // immediatly by an install of the same product to the same directories.  If we let\r
1356     // IS handle the uninstall of these files, this is not possible.  The reason is that\r
1357     // when IS fails to remove these in use files, it marks them for deletion after the\r
1358     // next reboot, which is fine.  Unfortunately, it leaves them in the dirs they were\r
1359     // installed to.  So if we don't immediately reboot and perform an install to the\r
1360     // same dirs, once a reboot is performed, those files get deleted and we have a \r
1361     // broken installation.\r
1362 \r
1363     // What we will do to fix all of this, is when the client is uninstalled, but\r
1364     // before IS does anything, we will move the in use files and associated dlls\r
1365     // into the temp dir and mark them for delete after a reboot.  Then an install\r
1366     // that follows will succeed.\r
1367 \r
1368     // Delete the files that may be in use.  If they are we actually move\r
1369     // them to the temp dir and mark them for deletion after the next reboot.\r
1370     for (ii = 0; pFileInfo[ii].pszName != 0; ii++) {\r
1371         // Get the source path\r
1372         strcpy(szSrcPath, ExpandPath(pFileInfo[ii].pszName));\r
1373 \r
1374         // Only delete the file if it is not used by some other app\r
1375         if (FileNeededByOtherApp(pAppInfo, &pFileInfo[ii]))\r
1376             continue;\r
1377 \r
1378         // If the file doesn't exist then go on to the next file.\r
1379         if (_access(szSrcPath, 0) != 0)\r
1380             continue;\r
1381             \r
1382         // See if we can do a regular delete of the file\r
1383         if (DeleteFile(szSrcPath)) {\r
1384             SetSharedFileRefCount(szSrcPath, 0);\r
1385             continue;\r
1386         }\r
1387 \r
1388         // Get a temp dir that is on the same drive as the src path.\r
1389         // We can't move an in use file to a different drive.\r
1390         strcpy(szTempDir, GetTempDir());\r
1391         if (szTempDir[0] != szSrcPath[0]) {\r
1392             // Get the drive, colon, and slash of the src path\r
1393             strncpy(szTempDir, szSrcPath, 3);\r
1394             szTempDir[3] = 0;\r
1395         }\r
1396         \r
1397         // Get the dest path - we will rename the file during the move\r
1398         GetTempFileName(szTempDir, "AFS", 0, szDestPath);\r
1399 \r
1400         // Move from source to dest, marking the file for deletion after a reboot\r
1401         if (IsWin95()) {\r
1402             if (MoveFile(szSrcPath, szDestPath)) {            \r
1403                 WritePrivateProfileString("rename", szSrcPath, szDestPath, "wininit.ini");\r
1404                 SetSharedFileRefCount(szSrcPath, 0);\r
1405             }\r
1406         } else {    // WinNT or Win98\r
1407             if (MoveFileEx(szSrcPath, szDestPath, MOVEFILE_REPLACE_EXISTING)) {\r
1408                 SetFileAttributes(szDestPath, FILE_ATTRIBUTE_NORMAL);\r
1409                 MoveFileEx(szDestPath, 0, MOVEFILE_DELAY_UNTIL_REBOOT);\r
1410                 SetSharedFileRefCount(szSrcPath, 0);\r
1411             }\r
1412         }\r
1413     }\r
1414 }\r
1415 \r
1416 // Delete a directory and all its files and subdirectories - Yee haaa!\r
1417 static void RemoveDirectoryTree(char *pszDir)\r
1418 {\r
1419     HANDLE hFind;\r
1420     WIN32_FIND_DATA findFileData;\r
1421     char szSpec[MAX_PATH];\r
1422     char szSubFileOrDir[MAX_PATH];\r
1423     BOOL bContinue;\r
1424 \r
1425     sprintf(szSpec, "%s\\*.*", pszDir);\r
1426     \r
1427     // First delete the contents of the dir\r
1428     hFind = FindFirstFile(szSpec, &findFileData);\r
1429     bContinue = (hFind != INVALID_HANDLE_VALUE);\r
1430     \r
1431     while (bContinue) {\r
1432         if ((strcmp(findFileData.cFileName, ".") != 0) && (strcmp(findFileData.cFileName, "..") != 0)) {\r
1433             sprintf(szSubFileOrDir, "%s\\%s", pszDir, findFileData.cFileName);\r
1434             \r
1435             if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)\r
1436                 RemoveDirectoryTree(szSubFileOrDir);\r
1437             else\r
1438                 DeleteFile(szSubFileOrDir);\r
1439         }\r
1440 \r
1441         bContinue = FindNextFile(hFind, &findFileData);\r
1442     }\r
1443 \r
1444     FindClose(hFind);\r
1445         \r
1446     // Now remove the dir\r
1447     RemoveDirectory(pszDir);\r
1448\r
1449 \r
1450 static char *GetStartMenuRoot()\r
1451 {\r
1452     HKEY hKey;\r
1453     LONG nResult;\r
1454     DWORD dwType;\r
1455     DWORD dwSize;\r
1456     char *pszKey;\r
1457     char *pszValue;\r
1458 \r
1459     static char szStartMenuRoot[MAX_PATH] = "";\r
1460 \r
1461     if (szStartMenuRoot[0] == 0) {\r
1462         dwSize = sizeof(szStartMenuRoot);\r
1463     \r
1464         if (IsWinNT()) {\r
1465             pszKey = WINNT_START_MENU_REG_KEY;\r
1466             pszValue = WINNT_START_MENU_REG_VALUE;\r
1467         } else {\r
1468             pszKey = WIN9X_START_MENU_REG_KEY;\r
1469             pszValue = WIN9X_START_MENU_REG_VALUE;\r
1470         }\r
1471         \r
1472         nResult = RegOpenKeyAlt(AFSREG_NULL_KEY, pszKey, KEY_READ, FALSE, &hKey, 0);\r
1473         if (nResult == ERROR_SUCCESS) {\r
1474             nResult = RegQueryValueEx(hKey, pszValue, 0, &dwType, (PBYTE)szStartMenuRoot, &dwSize);\r
1475             RegCloseKey(hKey);\r
1476         }\r
1477 \r
1478         if (nResult != ERROR_SUCCESS)\r
1479             return 0;\r
1480     }\r
1481 \r
1482     FilepathNormalizeEx(szStartMenuRoot, FPN_BACK_SLASHES);\r
1483 \r
1484     return szStartMenuRoot;\r
1485 }\r
1486 \r
1487 static char *GetAfsStartMenuRoot()\r
1488 {\r
1489     static char szAfsStartMenuRoot[MAX_PATH] = "";\r
1490     char *pszStartMenuRoot;\r
1491     \r
1492     if (szAfsStartMenuRoot[0] == 0) {    \r
1493         pszStartMenuRoot = GetStartMenuRoot();\r
1494         if (!pszStartMenuRoot)\r
1495             return 0;\r
1496 \r
1497         if (bSilentMode)\r
1498             sprintf(szAfsStartMenuRoot, "%s\\IBM WebSphere\\Performance Pack\\AFS", pszStartMenuRoot );\r
1499         else\r
1500             sprintf(szAfsStartMenuRoot, "%s\\IBM AFS", pszStartMenuRoot );\r
1501     }\r
1502 \r
1503     return szAfsStartMenuRoot;\r
1504 }\r
1505 \r
1506 static BOOL IsADir(char *pszName)\r
1507 {\r
1508     struct _stat statbuf;\r
1509 \r
1510     if (_stat(pszName, &statbuf) < 0)\r
1511         return FALSE;\r
1512 \r
1513     return statbuf.st_mode & _S_IFDIR;\r
1514 }\r
1515 \r
1516 static void DeleteStartMenuEntries(char *pszEntries)\r
1517 {\r
1518     char szStartMenuPath[MAX_PATH];\r
1519     char *pszAfsStartMenuRoot;\r
1520     char *pszCurEntry;\r
1521 \r
1522     pszAfsStartMenuRoot = GetAfsStartMenuRoot();\r
1523 \r
1524     if (!pszAfsStartMenuRoot)\r
1525         return;\r
1526         \r
1527     for (pszCurEntry = pszEntries; *pszCurEntry; pszCurEntry += strlen(pszCurEntry) + 1) {\r
1528         sprintf(szStartMenuPath, "%s\\%s", pszAfsStartMenuRoot, pszCurEntry);\r
1529         if (IsADir(szStartMenuPath))\r
1530             RemoveDirectoryTree(szStartMenuPath);\r
1531         else\r
1532             DeleteFile(szStartMenuPath);\r
1533     }\r
1534 }\r
1535 \r
1536 static void RefreshStartMenu()\r
1537 {\r
1538     char *pszAfsStartMenuRoot;\r
1539     char szTemp[MAX_PATH];\r
1540     \r
1541     pszAfsStartMenuRoot = GetAfsStartMenuRoot();\r
1542     if (!pszAfsStartMenuRoot)\r
1543         return;\r
1544 \r
1545     sprintf(szTemp, "%s - Refresh Attempt", pszAfsStartMenuRoot);\r
1546         \r
1547     // Deleting items from below the root level of the start menu does not \r
1548     // cause it to refresh.  In order that users can see changes without\r
1549     // rebooting we will temporarily rename our root most entry, which \r
1550     // does cause a refresh of the start menu.\r
1551     MoveFileEx(pszAfsStartMenuRoot, szTemp, MOVEFILE_REPLACE_EXISTING);\r
1552     MoveFileEx(szTemp, pszAfsStartMenuRoot, MOVEFILE_REPLACE_EXISTING);\r
1553 }\r
1554 \r
1555 static BOOL PreserveConfigInfo(struct APPINFO *pApp)\r
1556 {\r
1557     char *pszRegKey;\r
1558     char szDestKey[256];\r
1559     LONG result;\r
1560 \r
1561     bPreserveConfigInfo = TRUE;\r
1562 \r
1563     // If not in silent mode, ask user if they want to preserve the cfg info\r
1564     if (!bSilentMode) {\r
1565         int nChoice = ShowMsg(pApp->nPreserveConfigInfoMsgID, MB_ICONQUESTION | MB_YESNOCANCEL);\r
1566         if (nChoice == IDCANCEL)\r
1567             return FALSE;                   // Cancel the uninstall\r
1568         else if (nChoice == IDNO) {     \r
1569             bPreserveConfigInfo = FALSE;    // User doesn't want to preserve the config info\r
1570             return TRUE;\r
1571         }\r
1572     }\r
1573 \r
1574     // Copy each reg key (and all of its subkeys and values) to another place in the registry.\r
1575     for (pszRegKey = pApp->pszRegKeysToPreserve; *pszRegKey; pszRegKey += strlen(pszRegKey) + 1) {\r
1576         if (!DoesRegKeyExist(pszRegKey))\r
1577             continue;\r
1578 \r
1579         // Create the destination path for the copy\r
1580         sprintf(szDestKey, "%s\\%s\\%s", AFS_PRESERVED_CFG_INFO_KEY, pApp->pszAppName, pszRegKey);\r
1581 \r
1582         // Try to copy it\r
1583         result = RegDupKeyAlt(pszRegKey, szDestKey);\r
1584 \r
1585         if ((result != ERROR_SUCCESS) && (result != ERROR_FILE_NOT_FOUND)) {\r
1586             // If the copy failed, then delete any copies that succeeded\r
1587             sprintf(szDestKey, "%s\\%s", AFS_PRESERVED_CFG_INFO_KEY, pApp->pszAppName);\r
1588             RegDeleteEntryAlt(szDestKey, REGENTRY_KEY);\r
1589                 goto done;\r
1590         }\r
1591     }\r
1592 \r
1593         // Remember the integrated login setting if this app supports that and it was turned on\r
1594         if (pApp->pszNetworkProviderOrder) {\r
1595                 // Was integerated login turned on?\r
1596                 BOOL bOn, bOk;\r
1597                 bOk = InNetworkProviderOrder(pApp->pszNetworkProviderOrder, &bOn);\r
1598                 if (bOk && bOn) {\r
1599                         HKEY hKey;\r
1600                         sprintf(szDestKey, "%s\\%s\\IntegratedLogin", AFS_PRESERVED_CFG_INFO_KEY, pApp->pszAppName);\r
1601                         result = RegOpenKeyAlt(AFSREG_NULL_KEY, szDestKey, KEY_WRITE, TRUE, &hKey, 0);\r
1602                         // The existance of the key is a flag indicating that integrated login was turned on\r
1603                         RegCloseKey(hKey);\r
1604                 }\r
1605         }\r
1606         \r
1607 done:\r
1608         if ((result == ERROR_SUCCESS) || bSilentMode)\r
1609             return TRUE;    // Continue with uninstall\r
1610 \r
1611     // Report the error and ask the user if they want to continue the uninstall\r
1612     return (ShowMsg(IDS_SAVE_OF_CONFIG_INFO_FAILED, MB_ICONEXCLAMATION | MB_YESNO) == IDYES);                   \r
1613 }\r
1614 \r
1615 int SUCALLCONV RestoreConfigInfo(int nApp)\r
1616 {\r
1617     char *pszRegKey;\r
1618     char szSrcKey[256];\r
1619     struct APPINFO *pApp = 0;\r
1620     BOOL bError = FALSE;\r
1621     LONG result;\r
1622 \r
1623     switch (nApp) {\r
1624         case SERVER:    pApp = &appServer;          break;\r
1625         case CLIENT:    pApp = &appClient;          break;\r
1626         case LCLIENT:   pApp = &appLightClient;     break;\r
1627         case CC:        pApp = &appControlCenter;   break;\r
1628     }\r
1629     \r
1630     if (!pApp)\r
1631         return -1;\r
1632         \r
1633     // Copy each reg key (and all of its subkeys and values) back to its original place in the registry.\r
1634     for (pszRegKey = pApp->pszRegKeysToPreserve; *pszRegKey; pszRegKey += strlen(pszRegKey) + 1) {\r
1635         // Create the source path for the copy\r
1636         sprintf(szSrcKey, "%s\\%s\\%s", AFS_PRESERVED_CFG_INFO_KEY, pApp->pszAppName, pszRegKey);\r
1637 \r
1638         if (!DoesRegKeyExist(szSrcKey))\r
1639             continue;\r
1640 \r
1641         // Try to restore as many of the keys as possible.  Report any errors at the end.\r
1642 \r
1643         // Try to copy it\r
1644         result = RegDupKeyAlt(szSrcKey, pszRegKey);\r
1645         if ((result != ERROR_SUCCESS) && (result != ERROR_FILE_NOT_FOUND))\r
1646             bError = TRUE;\r
1647     }\r
1648 \r
1649         // Restore integrated login if this app was using it\r
1650         if (pApp->pszNetworkProviderOrder) {\r
1651                 // Check if integrated login was turned on.  The IntegratedLogin key is a flag\r
1652                 // telling us that it was on.  If the key does not exist, integrated login was\r
1653                 // not on.\r
1654                 sprintf(szSrcKey, "%s\\%s\\IntegratedLogin", AFS_PRESERVED_CFG_INFO_KEY, pApp->pszAppName);\r
1655                 if (DoesRegKeyExist(szSrcKey)) {\r
1656                         if (!AddToProviderOrder(pApp->pszNetworkProviderOrder))\r
1657                                 bError = TRUE;\r
1658                 }\r
1659         }\r
1660 \r
1661     // Remove our saved copies of the config info\r
1662     sprintf(szSrcKey, "%s\\%s", AFS_PRESERVED_CFG_INFO_KEY, pApp->pszAppName);\r
1663     RegDeleteEntryAlt(szSrcKey, REGENTRY_KEY);\r
1664             \r
1665     if (bError)\r
1666         ShowError(IDS_RESTORE_OF_PREVIOUS_CONFIG_FAILED, 0);\r
1667 \r
1668     return TRUE;\r
1669 }\r
1670 \r
1671 static BOOL DoSubKeysExist(char *pszKey)\r
1672 {\r
1673     LONG result;\r
1674     HKEY hKey;\r
1675     char *pszSubKeys = 0;\r
1676     BOOL bExist;\r
1677     \r
1678     result = RegOpenKeyAlt(AFSREG_NULL_KEY, pszKey, KEY_READ, FALSE, &hKey, 0);\r
1679     if (result != ERROR_SUCCESS)\r
1680         return FALSE;\r
1681         \r
1682     result = RegEnumKeyAlt(hKey,  &pszSubKeys);\r
1683     RegCloseKey(hKey);\r
1684     \r
1685     if (result != ERROR_SUCCESS)\r
1686         return FALSE;\r
1687    \r
1688     if (pszSubKeys) {\r
1689         bExist = TRUE;\r
1690         free(pszSubKeys);\r
1691     } else\r
1692         bExist = FALSE;    \r
1693 \r
1694     return bExist;\r
1695 }\r
1696 \r
1697 /*\r
1698  * The following definitions are taken from richedit.h:\r
1699  *\r
1700  */\r
1701 \r
1702 #define EM_SETBKGNDCOLOR                (WM_USER + 67) // from Richedit.h\r
1703 #define EM_STREAMIN                             (WM_USER + 73) // from Richedit.h\r
1704 #define SF_RTF                          0x0002\r
1705 \r
1706 typedef DWORD (CALLBACK *EDITSTREAMCALLBACK)(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb);\r
1707 \r
1708 typedef struct _editstream {\r
1709         DWORD dwCookie;         /* user value passed to callback as first parameter */\r
1710         DWORD dwError;          /* last error */\r
1711         EDITSTREAMCALLBACK pfnCallback;\r
1712 } EDITSTREAM;\r
1713 \r
1714 /*\r
1715  *\r
1716  */\r
1717 \r
1718 DWORD CALLBACK License_StreamText (DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)\r
1719 {\r
1720    LPTSTR psz = (LPTSTR)dwCookie;\r
1721    LONG cchAvail = lstrlen(psz);\r
1722    if ((*pcb = min(cchAvail, cb)) != 0) {\r
1723       memcpy (pbBuff, psz, *pcb);\r
1724       memmove (psz, &psz[*pcb], cchAvail - *pcb + 1);\r
1725    }\r
1726    return 0;\r
1727 }\r
1728 \r
1729 \r
1730 void License_OnInitDialog (HWND hDlg, LPTSTR pszFile)\r
1731 {\r
1732     // Open the license file and shove its text in our RichEdit control\r
1733     //\r
1734     HANDLE hFile;\r
1735     if ((hFile = CreateFile (pszFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE) {\r
1736 \r
1737         size_t cbText;\r
1738         if ((cbText = GetFileSize (hFile, NULL)) != 0) {\r
1739 \r
1740             LPTSTR abText = (LPTSTR)GlobalAlloc (GMEM_FIXED, cbText + 3);\r
1741 \r
1742             DWORD cbRead;\r
1743             if (ReadFile (hFile, abText, cbText, &cbRead, NULL)) {\r
1744                 abText[ cbRead ] = 0;\r
1745 \r
1746                 EDITSTREAM Stream;\r
1747                 memset (&Stream, 0x00, sizeof(Stream));\r
1748                 Stream.dwCookie = (DWORD)abText;\r
1749                 Stream.pfnCallback = License_StreamText;\r
1750 \r
1751                 SendDlgItemMessage (hDlg, IDC_TEXT, EM_STREAMIN, SF_RTF, (LPARAM)&Stream);\r
1752             }\r
1753 \r
1754             GlobalFree (abText);\r
1755         }\r
1756 \r
1757         CloseHandle (hFile);\r
1758     }\r
1759 \r
1760     // Make the control's background be gray\r
1761     //\r
1762     SendDlgItemMessage (hDlg, IDC_TEXT, EM_SETBKGNDCOLOR, FALSE, (LPARAM)GetSysColor(COLOR_BTNFACE));\r
1763 }\r
1764 \r
1765 BOOL CALLBACK License_DlgProc (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)\r
1766 {\r
1767     switch (msg) {\r
1768         case WM_INITDIALOG:\r
1769             SetWindowLong (hDlg, DWL_USER, lp);\r
1770             License_OnInitDialog (hDlg, (LPTSTR)lp);\r
1771             break;\r
1772 \r
1773         case WM_COMMAND:\r
1774             switch (LOWORD(wp)) {\r
1775                 case IDCANCEL:\r
1776                 case IDOK:\r
1777                     EndDialog (hDlg, LOWORD(wp));\r
1778                     break;\r
1779 \r
1780                 case IDC_PRINT:\r
1781                     TCHAR szDir[ MAX_PATH ];\r
1782                     GetCurrentDirectory (MAX_PATH, szDir);\r
1783                     ShellExecute (hDlg, TEXT("print"), (LPTSTR)GetWindowLong (hDlg, DWL_USER), NULL, szDir, SW_HIDE);\r
1784                     break;\r
1785             }\r
1786             break;\r
1787     }\r
1788     return FALSE;\r
1789 }\r
1790 \r
1791 BOOL FindAfsInstallationPathByComponent (LPTSTR pszInstallationPath, LPTSTR pszComponent)\r
1792 {\r
1793     *pszInstallationPath = 0;\r
1794 \r
1795     TCHAR szRegPath[ MAX_PATH ];\r
1796     wsprintf (szRegPath, TEXT("Software\\TransarcCorporation\\%s\\CurrentVersion"), pszComponent);\r
1797 \r
1798     HKEY hk;\r
1799     if (RegOpenKey (HKEY_LOCAL_MACHINE, szRegPath, &hk) == 0) {\r
1800         DWORD dwType = REG_SZ;\r
1801         DWORD dwSize = MAX_PATH;\r
1802 \r
1803         if (RegQueryValueEx (hk, TEXT("PathName"), NULL, &dwType, (PBYTE)pszInstallationPath, &dwSize) == 0) {\r
1804             *(LPTSTR)FindBaseFileName (pszInstallationPath) = TEXT('\0');\r
1805 \r
1806             if (pszInstallationPath[0] && (pszInstallationPath[ lstrlen(pszInstallationPath)-1 ] == TEXT('\\')))\r
1807             pszInstallationPath[ lstrlen(pszInstallationPath)-1 ] = TEXT('\0');\r
1808         }\r
1809 \r
1810         RegCloseKey (hk);\r
1811     }\r
1812 \r
1813     return !!*pszInstallationPath;\r
1814 }\r
1815 \r
1816 BOOL FindAfsInstallationPath (LPTSTR pszInstallationPath)\r
1817 {\r
1818    if (FindAfsInstallationPathByComponent (pszInstallationPath, TEXT("AFS Client")))\r
1819       return TRUE;\r
1820    if (FindAfsInstallationPathByComponent (pszInstallationPath, TEXT("AFS Control Center")))\r
1821       return TRUE;\r
1822    if (FindAfsInstallationPathByComponent (pszInstallationPath, TEXT("AFS Server")))\r
1823       return TRUE;\r
1824    if (FindAfsInstallationPathByComponent (pszInstallationPath, TEXT("AFS Supplemental Documentation")))\r
1825       return TRUE;\r
1826    return FALSE;\r
1827 }\r
1828 \r
1829 HINSTANCE LoadRichTextControl (void)\r
1830 {\r
1831     HINSTANCE hInst;\r
1832     if ((hInst = LoadLibrary ("riched20.dll")) != NULL)\r
1833         return hInst;\r
1834     if ((hInst = LoadLibrary ("riched32.dll")) != NULL)\r
1835         return hInst;\r
1836     if ((hInst = LoadLibrary ("riched.dll")) != NULL)\r
1837         return hInst;\r
1838     if ((hInst = LoadLibrary ("richedit.dll")) != NULL)\r
1839         return hInst;\r
1840     return NULL;\r
1841 }\r
1842 \r
1843 int SUCALLCONV ShowLicense (char *pszTarget, char *pszSource)\r
1844 {\r
1845     // If the license already lives on this user's machine, don't show\r
1846     // it again. This only has to be done if the user has never\r
1847     // accepted the license agreement before (it's part of the setup\r
1848     // program, so it gets installed if they've accepted it).\r
1849     //\r
1850     // We were handed a relative path of the form:\r
1851     //    Documentation/html/license.rtf\r
1852     //\r
1853     // We'll need to find the AFS installation directory, in order to\r
1854     // find that Documentation subtree.\r
1855     //\r
1856     BOOL fShowLicense = TRUE;\r
1857 \r
1858     TCHAR szInstallationPath[ MAX_PATH ];\r
1859     if (FindAfsInstallationPath (szInstallationPath)) {\r
1860         TCHAR szLicensePath[ MAX_PATH ];\r
1861         wsprintf (szLicensePath, TEXT("%s\\%s"), szInstallationPath, pszTarget);\r
1862 \r
1863         if (GetFileAttributes (szLicensePath) != (DWORD)-1) {\r
1864             fShowLicense = FALSE;\r
1865         }\r
1866     }\r
1867 \r
1868     // Before we can show the license file, we have to prepare the RichEdit\r
1869     // control. That means loading the appropriate library and calling its\r
1870     // initialization functions.\r
1871     //\r
1872     HINSTANCE hRichEdit;\r
1873     if ((hRichEdit = LoadRichTextControl()) != NULL) {\r
1874 \r
1875         // If we must show the license, do so now. This is a modal dialog,\r
1876         // so we'll know whether or not the user accepts the license.\r
1877         //\r
1878         if (ModalDialogParam (IDD_LICENSE, GetActiveWindow(), License_DlgProc, (LPARAM)pszSource) == IDCANCEL) {\r
1879             // The user rejected the license; fail setup\r
1880             return FALSE;\r
1881         }\r
1882 \r
1883         FreeLibrary (hRichEdit);\r
1884     }\r
1885 \r
1886     // The user accepted the license, so we can continue with Setup.\r
1887     // The license file is installed as part of Setup.\r
1888     return TRUE;\r
1889 }\r
1890 \r
1891 int SUCALLCONV UninstInitialize(HWND hIS, HINSTANCE hIS5, long Reserved)\r
1892 {\r
1893     char szPath[MAX_PATH];\r
1894     struct APPINFO *pAppInfo;\r
1895     char *pszFile = 0;\r
1896     char *pszSubDir = 0;\r
1897 \r
1898     hDlg = hIS;\r
1899 \r
1900     bSilentMode = !IsWindowVisible(hIS);\r
1901 \r
1902     // Which app are we uninstalling?\r
1903     pAppInfo = GetApp();\r
1904     if (!pAppInfo) {\r
1905         ShowError(IDS_CANT_DETERMINE_PRODUCT, 0);\r
1906         return -1;\r
1907     }\r
1908 \r
1909     // Get the app's install dir\r
1910     pszInstallDir = GetAppInstallDir(pAppInfo, FALSE);\r
1911     if (!pszInstallDir)\r
1912         return -1;\r
1913 \r
1914     // If this app has a custom uninstall func, call it here\r
1915     if (pAppInfo->pUninstallFunc)\r
1916         if (!pAppInfo->pUninstallFunc())\r
1917             return -1;\r
1918 \r
1919     if (pAppInfo->pszRegKeysToPreserve)\r
1920         if (!PreserveConfigInfo(pAppInfo))\r
1921             return -1;\r
1922 \r
1923     // Unconfigure the service, if there is one for this app\r
1924     if (pAppInfo->pszSvcKey) {\r
1925         if (IsServiceInstalled(pAppInfo->pszSvcKey))\r
1926             if (UninstallService(pAppInfo) == 1)\r
1927                 return -1;\r
1928     }\r
1929 \r
1930     RememberInstallDir(pszInstallDir);\r
1931 \r
1932     DeleteInUseFiles(pAppInfo, fileInfo);\r
1933 \r
1934     // Remove the app's bin path from the system path\r
1935     if (pAppInfo->pszBinPath) {\r
1936         BuildShortPath(szPath, sizeof(szPath), pszInstallDir, pAppInfo->pszBinPath);\r
1937         RemoveFromPath(szPath);\r
1938     }\r
1939 \r
1940     // Remove entry from NetworkProvider\Order key in registry\r
1941     if (pAppInfo->pszNetworkProviderOrder)\r
1942         RemoveFromNetworkProviderOrder(pAppInfo->pszNetworkProviderOrder);\r
1943 \r
1944     // Remove any generated subdirectories\r
1945     if (!bPreserveConfigInfo && pAppInfo->pszDirsToDel) {\r
1946         for (pszSubDir = pAppInfo->pszDirsToDel; *pszSubDir; pszSubDir += strlen(pszSubDir) + 1)\r
1947             RemoveDir(ExpandPath(pszSubDir));\r
1948     }\r
1949 \r
1950     // Remove any generated files\r
1951     if (!bPreserveConfigInfo && pAppInfo->pszFilesToDel) {\r
1952         for (pszFile = pAppInfo->pszFilesToDel; *pszFile; pszFile += strlen(pszFile) + 1)\r
1953             RemoveFiles(ExpandPath(pszFile));\r
1954     }\r
1955 \r
1956     // Remove any registry values that IS can't handle\r
1957     RemoveRegValues(pAppInfo->pRegValues);\r
1958     if (IsWinNT())\r
1959         RemoveRegValues(pAppInfo->pWinNTRegValues);\r
1960     else    \r
1961         RemoveRegValues(pAppInfo->pWin9XRegValues);\r
1962 \r
1963     // Remove the start menu entries for this app\r
1964     if (pAppInfo->pszStartMenuEntries) {\r
1965         DeleteStartMenuEntries(pAppInfo->pszStartMenuEntries);\r
1966         RefreshStartMenu();\r
1967     }\r
1968 \r
1969     // Remove the install dir\r
1970     RemoveDirectory(pszInstallDir);\r
1971 \r
1972     return 0;\r
1973 }\r
1974 \r
1975 void SUCALLCONV UninstUnInitialize(HWND hIS, HINSTANCE hIS5, long Reserved)\r
1976 {\r
1977     char *pszInstallDir;\r
1978     char szDirPath[MAX_PATH];\r
1979     char *psz;\r
1980     struct APPINFO *pAppInfo;\r
1981 \r
1982     // If we just uninstalled the last AFS app, then do some cleanup.\r
1983     if (IsAppInstalled(&appServer) || IsAppInstalled(&appClient) ||\r
1984         IsAppInstalled(&appControlCenter) || IsAppInstalled(&appLightClient) ||\r
1985         IsAppInstalled(&appDocs))\r
1986     {\r
1987         return;\r
1988     }\r
1989 \r
1990     bSilentMode = !IsWindowVisible(hIS);\r
1991     \r
1992     // Which app did we just uninstall?\r
1993     pAppInfo = GetApp();\r
1994     if (!pAppInfo) {\r
1995         ShowError(IDS_CANT_DETERMINE_PRODUCT, 0);\r
1996         return;\r
1997     }\r
1998 \r
1999     // Get the app's install dir\r
2000     pszInstallDir = GetAppInstallDir(pAppInfo, TRUE);\r
2001     if (!pszInstallDir)\r
2002         return;\r
2003 \r
2004     // Remove the reg key we used to remember the app install dir\r
2005     RegDeleteEntryAlt(UNINSTALL_TEMP_INFO_KEY, REGENTRY_KEY);\r
2006 \r
2007     // Try to remove the reg key used to store config info, but only\r
2008     // if there are no app config info sub keys present.\r
2009     if (!DoSubKeysExist(AFS_PRESERVED_CFG_INFO_KEY))\r
2010         RegDeleteEntryAlt(AFS_PRESERVED_CFG_INFO_KEY, REGENTRY_KEY);\r
2011 \r
2012     // Remove the install dir\r
2013     RemoveDirectory(pszInstallDir);\r
2014 \r
2015     // Attempt to remove the install root and common directories.  The are \r
2016     // shared and so no single app knows to delete them.\r
2017 \r
2018     // Strip off the app specific part of the install dir\r
2019     psz = strrchr(pszInstallDir, '\\');\r
2020     if (psz)\r
2021         *psz = 0;\r
2022 \r
2023     sprintf(szDirPath, "%s\\%s", pszInstallDir, "Common");\r
2024     RemoveDirectory(szDirPath);\r
2025 \r
2026     // Remove the Common directory from the system path\r
2027     RemoveFromPath(szDirPath);\r
2028 \r
2029     // Remove all of the documentation dirs\r
2030     sprintf(szDirPath, "%s\\%s", pszInstallDir, "Documentation");\r
2031     RemoveDirectoryTree(szDirPath);\r
2032 \r
2033     // Ok, up to this point we have been removing files we know we\r
2034     // created.  However, after this point we are into the path\r
2035     // that the user chose for our install root.  The default for\r
2036     // this is IBM/Afs, but they could have chosen anything,\r
2037     // including a dir or dirs that have other products in them.\r
2038     // We will check to see if it is IBM\AFS and if it is then we \r
2039     // will attempt to remove them.\r
2040     \r
2041     // Back up a level and look for AFS\r
2042     psz = strrchr(pszInstallDir, '\\');\r
2043     if (psz) {\r
2044         if (stricmp(psz + 1, "AFS") == 0) {\r
2045             RemoveDirectory(pszInstallDir);\r
2046             *psz = 0;\r
2047         }\r
2048     }\r
2049 \r
2050     // Back up a level and look for IBM\r
2051     psz = strrchr(pszInstallDir, '\\');\r
2052     if (psz) {\r
2053         if (stricmp(psz + 1, "IBM") == 0) {\r
2054             RemoveDirectory(pszInstallDir);\r
2055             *psz = 0;\r
2056         }\r
2057     }\r
2058 \r
2059     // Remove the root afs start menu entry\r
2060     psz = GetStartMenuRoot();\r
2061     if (psz) {\r
2062         if (bSilentMode) {\r
2063             // Remove everything under our branch\r
2064             sprintf(szDirPath, "%s\\IBM WebSphere\\Performance Pack\\AFS", psz);\r
2065             RemoveDirectoryTree(szDirPath);\r
2066             \r
2067             // Remove the IBM stuff only if the dirs are empty\r
2068             sprintf(szDirPath, "%s\\IBM WebSphere\\Performance Pack", psz);\r
2069             if (RemoveDirectory(szDirPath)) {\r
2070                 sprintf(szDirPath, "%s\\IBM WebSphere", psz);\r
2071                 RemoveDirectory(szDirPath);\r
2072             }\r
2073         } else {\r
2074             sprintf(szDirPath, "%s\\IBM AFS", psz);\r
2075             RemoveDirectoryTree(szDirPath);\r
2076         }\r
2077     }\r
2078 }\r
2079 \r
2080 BOOLEAN _stdcall DllEntryPoint(HANDLE dll, DWORD reason, PVOID reserved)\r
2081 {\r
2082     if (reason == DLL_PROCESS_ATTACH) {\r
2083         hinst = (HINSTANCE)dll;\r
2084         TaLocale_LoadCorrespondingModuleByName (hinst, "afs_setup_utils.dll");\r
2085     }\r
2086 \r
2087     return TRUE;\r
2088 }\r
2089 \r
2090 extern "C" int WINAPI Test (HINSTANCE hInst, HINSTANCE hPrev, LPSTR psz, int nCmdShow)\r
2091 {\r
2092    ShowLicense ("TEST", "\\\\fury\\afssetup\\license\\ja_JP.rtf");\r
2093    return 0;\r
2094 }\r
2095 \r
2096 \r