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