Initial IBM OpenAFS 1.0 tree
[openafs.git] / src / WINNT / afssvrcfg / afscfg.cpp
1 /*
2  * Copyright (C) 1998  Transarc Corporation.
3  * All rights reserved.
4  *
5  */
6
7
8 /*
9  * INCLUDES _________________________________________________________________
10  *
11  */
12
13 extern "C" {
14 #include <afs/param.h>
15 #include <afs/stds.h>
16 }
17
18 #include "afscfg.h"
19 #include "resource.h"
20 #include "graphics.h"
21 #include <string.h>
22 #include "get_cur_config.h"
23 #include "partition_utils.h"
24 extern "C" {
25 #include <afs\dirpath.h>
26 #include <afs\afs_clientAdmin.h>
27 }
28
29
30 /*
31  * DEFINITIONS _________________________________________________________________
32  *
33  */
34
35
36 /*
37  * PROTOTYPES _________________________________________________________________
38  *
39  */
40 static void SetConfigDefaults();
41 static void RunCfgTool();
42 static void RunWizard();
43 static void CloseLibHandles(BOOL bExiting = FALSE);
44
45 void RegisterWizardHelp();
46 void RegisterConfigToolHelp();
47
48 // These are the prototypes for the dialog procs of each wizard page.
49 BOOL CALLBACK IntroPageDlgProc(HWND hRHS, UINT msg, WPARAM wp, LPARAM lp);
50 BOOL CALLBACK InfoPageDlgProc(HWND hwndDlg, UINT msg, WPARAM wp, LPARAM lp);
51 BOOL CALLBACK InfoPage2DlgProc(HWND hRHS, UINT msg, WPARAM wp, LPARAM lp);
52 BOOL CALLBACK FileServerPageDlgProc(HWND hwndDlg, UINT msg, WPARAM wp, LPARAM lp);
53 BOOL CALLBACK DBServerPageDlgProc(HWND hwndDlg, UINT msg, WPARAM wp, LPARAM lp);
54 BOOL CALLBACK BackupPageDlgProc(HWND hwndDlg, UINT msg, WPARAM wp, LPARAM lp);
55 BOOL CALLBACK PartitionPageDlgProc(HWND hwndDlg, UINT msg, WPARAM wp, LPARAM lp);
56 BOOL CALLBACK RootAfsPageDlgProc(HWND hwndDlg, UINT msg, WPARAM wp, LPARAM lp);
57 BOOL CALLBACK ReplicationPageDlgProc(HWND hwndDlg, UINT msg, WPARAM wp, LPARAM lp);
58 BOOL CALLBACK SysControlPageDlgProc(HWND hwndDlg, UINT msg, WPARAM wp, LPARAM lp);
59 BOOL CALLBACK ConfigServerPageDlgProc(HWND hwndDlg, UINT msg, WPARAM wp, LPARAM lp);
60
61
62 static WIZARD_STATE g_aStates[] = {
63     { sidSTEP_ONE,              IDD_INTRO_PAGE,                                 (DLGPROC)IntroPageDlgProc, 0 },
64     { sidSTEP_TWO,              IDD_INFO_PAGE,                                  (DLGPROC)InfoPageDlgProc, 0 },
65     { sidSTEP_THREE,    IDD_INFO_PAGE2_FIRST_SERVER,    (DLGPROC)InfoPage2DlgProc, 0 },
66         { sidSTEP_FOUR,         IDD_INFO_PAGE2_NOT_FIRST_SERVER,(DLGPROC)InfoPage2DlgProc, 0 },
67     { sidSTEP_FIVE,             IDD_FILE_SERVER_PAGE,                   (DLGPROC)FileServerPageDlgProc, 0 },
68     { sidSTEP_SIX,              IDD_DB_SERVER_PAGE,                             (DLGPROC)DBServerPageDlgProc, 0 },
69         { sidSTEP_SEVEN,        IDD_BACKUP_SERVER_PAGE,                 (DLGPROC)BackupPageDlgProc, 0 },
70     { sidSTEP_EIGHT,    IDD_PARTITION_PAGE,                             (DLGPROC)PartitionPageDlgProc, 0 },
71         { sidSTEP_NINE,         IDD_ROOT_VOLUMES_PAGE,                  (DLGPROC)RootAfsPageDlgProc, 0 },
72         { sidSTEP_TEN,          IDD_REPLICATION_PAGE,                   (DLGPROC)ReplicationPageDlgProc, 0 },
73         { sidSTEP_ELEVEN,       IDD_SYS_CONTROL_PAGE,                   (DLGPROC)SysControlPageDlgProc, 0 },
74         { sidSTEP_TWELVE,       IDD_CONFIG_SERVER_PAGE,                 (DLGPROC)ConfigServerPageDlgProc, 0 }
75 };
76
77 size_t g_nNumStates = sizeof(g_aStates) / sizeof(g_aStates[0]);
78
79
80 // Res ID's of text descriptions of each state
81 UINT g_StateDesc[] = {
82         IDS_INTRO_PAGE,
83         IDS_INFO_PAGE,
84         IDS_INFO_PAGE2,
85         IDS_INFO_PAGE2,
86         IDS_FS_PAGE,
87         IDS_DB_PAGE,
88         IDS_BK_PAGE,
89         IDS_PARTITION_PAGE,
90         IDS_ROOT_AFS_PAGE,
91         IDS_REP_PAGE,
92         IDS_SC_PAGE,
93         IDS_CONFIG_PAGE
94 };
95
96
97
98 /*
99  * EXPORTED VARIABLES _________________________________________________________________
100  *
101  */
102 LPWIZARD g_pWiz = NULL;
103 LPPROPSHEET g_pSheet = NULL;
104
105 CFG_DATA g_CfgData;
106
107 void *g_hToken = 0;
108 void *g_hCell = 0;
109 void *g_hClient = 0;
110 void *g_hServer = 0;
111
112 static void *hClientCell = 0;
113
114 LOGFILE g_LogFile;
115
116
117
118 /*
119  * EXPORTED FUNCTIONS _________________________________________________________________
120  *
121  */
122 int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrev, LPSTR pszCmdLineA, int nCmdShow)
123 {
124         afs_status_t nStatus;
125
126         TaLocale_LoadCorrespondingModule (hInst);
127
128         // Tell the applib our application's name
129         TCHAR szAppName[cchRESOURCE];
130         AfsAppLib_SetAppName(GetResString(GetAppTitleID(), szAppName));
131
132         // Open the admin libraries
133         int nResult = afsclient_Init(&nStatus);
134         if (!nResult) {
135                 ShowError(0, nStatus, IDS_CANT_INIT_ADMIN_LIBS);
136                 return 0;
137         }
138
139         // Open the log file
140         char szLogPath[MAX_PATH];
141         sprintf(szLogPath, "%s\\%s", AFSDIR_SERVER_LOGS_DIRPATH, LOG_FILE_NAME);
142         if (!g_LogFile.Open(szLogPath))
143                 ShowError(0, 0, IDS_CANT_OPEN_LOG_FILE);
144
145         // Register the help file with the applib's help system
146         AfsAppLib_RegisterHelpFile(TEXT("TaAfsCfg.hlp"));
147
148     /* Start up sockets */
149     WSADATA WSAjunk;
150     WSAStartup(0x0101, &WSAjunk);
151
152         memset(&g_CfgData, 0, sizeof(CFG_DATA));
153
154         // Get this machine's local name
155         char szLocalName[sizeof(g_CfgData.szLocalName) / sizeof(TCHAR)];
156     if (gethostname(szLocalName, sizeof(szLocalName)) != 0) {
157                 ShowError(GetFocus(), WSAGetLastError(), IDS_ERROR_LOCAL_HOST_NAME);
158                 return 0;
159         }
160     CopyAnsiToString(g_CfgData.szLocalName, szLocalName);
161
162         // Turn the local name into a host name
163     struct hostent *pHostEnt = gethostbyname(szLocalName);
164     if (!pHostEnt) {
165                 ShowError(GetFocus(), WSAGetLastError(), IDS_ERROR_HOST_NAME);
166                 return 0;
167         }
168     CopyAnsiToString(g_CfgData.szHostname, pHostEnt->h_name, sizeof(g_CfgData.szHostname));
169
170         RegisterFastListClass();
171
172         // Get current config status
173         BOOL bCanceled = FALSE;
174         DWORD dwStatus = GetCurrentConfig(NULL, bCanceled);
175         if (dwStatus || bCanceled) {
176                 if (!bCanceled)
177                 ShowError(GetFocus(), dwStatus, IDS_CONFIG_CHECK_FAILED);
178                 return 0;
179         }
180
181     // Check the version of the client.  It must be at least 35.
182     if (g_CfgData.nClientVersion < 35) {
183         int nMajor, nMinor;
184         nMajor = g_CfgData.nClientVersion / 10;
185         nMinor = g_CfgData.nClientVersion - (nMajor * 10);
186         g_LogFile.Write("The version of the AFS Client on this machine (%d.%d) is too old to run the server.  The Client must be at least version 3.5.\r\n", nMajor, nMinor);
187                 ErrorDialog(0, IDS_ERROR_CLIENT_VERSION);
188         return 0;
189     }
190
191         // Run the appropriate interface
192         if ((strstr(_strlwr(pszCmdLineA), "wizard") != 0))
193                 RunWizard();
194         else
195                 RunCfgTool();
196
197         FreePartitionTable();
198
199         // Disconnect from the config and admin libraries
200         CloseLibHandles(TRUE);
201
202         return 0;
203 }
204
205 /*
206  *      This is a dialog proc that is shared by all of the wizard pages.  It
207  *      handles things that are common to all of them.  Each page also has its
208  *      own dialog proc.
209  */
210 BOOL CALLBACK WizStep_Common_DlgProc(HWND hRHS, UINT msg, WPARAM wp, LPARAM lp)
211 {
212         // Get the dialog's resource ID
213         int nIDD = GetWindowLong(hRHS, GWL_ID);
214         
215         if (AfsAppLib_HandleHelp(nIDD, hRHS, msg, wp, lp))
216                 return TRUE;
217         
218         switch (msg) {
219                 case WM_INITDIALOG:     MakeBold(hRHS, IDC_TITLE);
220                                                         RedrawGraphic();
221                                                         break;
222
223                 case WM_COMMAND:
224                         switch (LOWORD(wp)) {
225                                 case IDCANCEL:
226                                         QueryCancelWiz();
227                                         return TRUE;
228                         }
229                         break;
230         }
231
232         return FALSE;
233 }
234
235 BOOL QueryCancelWiz()
236 {
237         int nChoice = Message(MB_YESNO, IDS_WIZARD_APP_TITLE, IDS_CANCEL_DESC);
238         if (nChoice == IDYES) {
239                 g_LogFile.Write("User has chosen to cancel the program.\r\n");
240                 if (g_pWiz)
241                         g_pWiz->Show(FALSE);
242                 return TRUE;
243         }
244
245         return FALSE;
246 }
247
248
249 /*
250  *  Accessor functions for the g_CfgData variable.  There are versions
251  *  for both TCHARs and char *'s.
252  */
253 TCHAR GetDeviceName()           { return g_CfgData.chDeviceName; }
254 LPTSTR GetPartitionName()       { return g_CfgData.szPartitionName; }
255 LPTSTR GetHostName()            { return g_CfgData.szHostname; }
256 LPTSTR GetSysControlMachine()   { return g_CfgData.szSysControlMachine; }
257 LPTSTR GetCellName()            { return g_CfgData.szCellName; }
258 LPTSTR GetServerPW()            { return g_CfgData.szServerPW; }
259 LPTSTR GetAdminName()           { return g_CfgData.szAdminName; }
260 LPTSTR GetAdminPW()             { return g_CfgData.szAdminPW; }
261 LPTSTR GetAdminUID()            { return g_CfgData.szAdminUID; }
262 LPTSTR GetLocalName()           { return g_CfgData.szLocalName; }
263 LPTSTR GetHostname()            { return g_CfgData.szHostname; }
264 LPTSTR GetCellServDbHostname()  { return g_CfgData.szCellServDbHostname; }
265 LPTSTR GetClientCellName()      { return g_CfgData.szClientCellName; }
266 LPTSTR GetSalvageLogFileName()  { return g_CfgData.szSalvageLogFileName; }
267
268 LPTSTR GetClientNetbiosName()
269 {
270     static TCHAR szValue[MAX_MACHINE_NAME_LEN + 1];
271
272     lstrcpy(szValue, g_CfgData.szLocalName);
273
274     szValue[11] = TEXT('\0');
275
276     for (LPTSTR pch = szValue; *pch != TEXT('\0'); pch++) {
277         if (*pch == TEXT('.')) {
278             *pch = TEXT('\0');
279             break;
280         }
281     }
282     lstrcat(szValue, TEXT("-AFS"));
283
284     return szValue;
285 }
286
287 char GetDeviceNameA()
288 {
289     static char szValueA[2];
290
291     TCHAR devName[2] = TEXT("X");
292     devName[0] = g_CfgData.chDeviceName;
293
294     CopyStringToAnsi(szValueA, devName);
295
296     return szValueA[0];
297 }
298
299 char *GetPartitionNameA()
300 {
301     static char szValueA[MAX_PARTITION_NAME_LEN + 1];
302
303     CopyStringToAnsi(szValueA, g_CfgData.szPartitionName);
304
305     return szValueA;
306 }
307
308 char *GetSysControlMachineA()
309 {
310     static char szValueA[MAX_MACHINE_NAME_LEN + 1];
311
312     CopyStringToAnsi(szValueA, g_CfgData.szSysControlMachine);
313
314     return szValueA;
315 }
316
317 char *GetCellNameA()
318 {
319     static char szValueA[MAX_CELL_NAME_LEN + 1];
320
321     CopyStringToAnsi(szValueA, g_CfgData.szCellName);
322
323     return szValueA;
324 }
325
326 char *GetServerPWA()
327 {
328     static char szValueA[MAX_SERVER_PW_LEN + 1];
329
330     CopyStringToAnsi(szValueA, g_CfgData.szServerPW);
331
332     return szValueA;
333 }
334
335 char *GetAdminNameA()
336 {
337     static char szValueA[MAX_ADMIN_NAME_LEN + 1];
338
339     CopyStringToAnsi(szValueA, g_CfgData.szAdminName);
340
341     return szValueA;
342 }
343
344 char *GetAdminPWA()
345 {
346     static char szValueA[MAX_ADMIN_PW_LEN + 1];
347
348     CopyStringToAnsi(szValueA, g_CfgData.szAdminPW);
349
350     return szValueA;
351 }
352
353 char *GetAdminUIDA()
354 {
355     static char szValueA[MAX_UID_LEN + 1];
356
357     CopyStringToAnsi(szValueA, g_CfgData.szAdminUID);
358
359     return szValueA;
360 }
361
362 char *GetLocalNameA()
363 {
364     static char szValueA[MAX_MACHINE_NAME_LEN + 1];
365
366     CopyStringToAnsi(szValueA, g_CfgData.szLocalName);
367
368     return szValueA;
369 }
370
371 char *GetHostnameA()
372 {
373     static char szValueA[MAX_MACHINE_NAME_LEN + 1];
374
375     CopyStringToAnsi(szValueA, g_CfgData.szHostname);
376
377     return szValueA;
378 }
379
380 char *GetCellServDbHostnameA()
381 {
382     static char szValueA[MAX_MACHINE_NAME_LEN + 1];
383
384     CopyStringToAnsi(szValueA, g_CfgData.szCellServDbHostname);
385
386     return szValueA;
387 }
388
389 char *GetClientCellNameA()
390 {
391     static char szValueA[MAX_CELL_NAME_LEN + 1];
392
393     CopyStringToAnsi(szValueA, g_CfgData.szClientCellName);
394
395     return szValueA;
396 }
397
398 char *GetClientNetbiosNameA()
399 {
400     static char szValueA[MAX_MACHINE_NAME_LEN + 1];
401     char *dotp;
402
403     CopyStringToAnsi(szValueA, g_CfgData.szLocalName);
404
405     szValueA[11] = '\0';
406
407     if ((dotp = strchr(szValueA, '.')) != NULL) {
408         *dotp = '\0';
409     }
410     strcat(szValueA, "-AFS");
411
412     return szValueA;
413 }
414
415 char *GetSalvageLogFileNameA()
416 {
417     static char szValueA[_MAX_PATH];
418
419     CopyStringToAnsi(szValueA, g_CfgData.szSalvageLogFileName);
420
421     return szValueA;
422 }
423
424
425 BOOL GetLibHandles(afs_status_t *pStatus)
426 {
427         ASSERT(g_CfgData.szHostname[0]);
428
429         int nResult;
430         
431         // ************************* NOTE ********************************
432         // * You MUST have already determined whether or not the host
433         // * and client config info is valid before calling this function.
434         // ***************************************************************
435
436         // This function can be called at any time to get handles to the cell and
437         // the config library.  It will try to get the most powerful handle to the
438         // cell that it can, and then use that to open the config library.  If the
439         // libraries are already open, it will close them first.  Two handles to
440         // the config library will be opened, one to the server to be configured,
441         // and one to the client machine we are configuring from.  
442         
443         // There are two types of cell handles, NULL and Standard.  A null handle
444         // can make calls to any server except DB servers.  We need this primarily
445         // to talk to the bos server to determine the machine's current configuration,
446         // and to configure the client information if it is not already.  A standard 
447         // handle can talk to any server.  Standard handles can be either authenticated 
448         // or unauthenticated.
449
450         // Close all current handles
451         CloseLibHandles();
452
453         g_LogFile.Write("Getting handles to the cell and the config library.\r\n");
454
455     if (!hClientCell) {
456         // Start by getting a null cell handle and using it to open the client
457         // connection to the config library.
458         g_LogFile.Write("Opening a NULL cell handle to use with the client config library handle.\r\n");
459         nResult = afsclient_NullCellOpen(&hClientCell, pStatus);
460         if (!nResult) {
461             g_LogFile.Write("Failed to open a NULL cell handle: %lx.\r\n", (unsigned long)*pStatus);
462                 return FALSE;
463         }
464     
465         // Get the client handle.  We never need a better handle than this
466         // for the client, and so this handle will never be upgraded.
467         g_LogFile.Write("Getting config handle for the client.\r\n");
468         if (!cfg_HostOpen(hClientCell, GetHostnameA(), &g_hClient, pStatus)) {
469             g_LogFile.Write("Failed to get config handle:  %lx.\r\n", (unsigned long)*pStatus);
470                 return FALSE;
471         }
472     }
473
474         // Now we need to get the most powerful cell handle that we can and use it
475         // to open the config library for the server.
476
477         // If the client info is valid and we know what cell the server should be in,
478         // and the client has that cell in its CellServDB, then we can get a Standard cell
479         // handle.  However there is an exception: if this is the first server in the 
480         // cell then there may not yet be an authentication server to talk to.  In that
481         // case we use a null cell handle.
482     if (g_CfgData.bValidClientInfo &&   // Client config is valid
483         g_CfgData.szCellName[0] &&      // We have a cell name
484         (!g_CfgData.bFirstServer || g_CfgData.bAuthServerRunning))  // Auth server is running
485     {
486                 g_LogFile.Write("Opening a non-NULL cell handle to use with the server config library handle.\r\n");
487
488         // Do we have the user info necessary to authenticate?
489         BOOL bHaveUserInfo = g_CfgData.szAdminName[0] && g_CfgData.szAdminPW[0];
490
491                 // Open a standard cell handle.  szAdminName and szAdminPW will either be NULL, or
492                 // if they have been entered by the user, will be the admin name and password strings.
493                 if ((!g_CfgData.bFirstServer || g_CfgData.bAdminPrincipalCreated) && bHaveUserInfo) {
494                         g_LogFile.Write("Getting tokens in cell %s for user '%s'.\r\n", GetCellNameA(), GetAdminNameA());
495                         nResult = afsclient_TokenGetNew(GetCellNameA(), GetAdminNameA(), GetAdminPWA(), &g_hToken, pStatus);
496                 } else {
497                         g_LogFile.Write("Getting unauthenticated tokens for cell '%s'.\r\n", GetCellNameA());
498                         nResult = afsclient_TokenGetNew(GetCellNameA(), "", "", &g_hToken, pStatus);
499                 }
500
501                 if (!nResult) {
502                         g_LogFile.Write("Failed to get tokens for the specified cell:  %lx.\r\n", (unsigned long)*pStatus);
503                         return FALSE;
504                 }
505
506                 // If the admin name and password are NULL, then this will be an unauthenticated
507                 // connection to the cell.
508                 g_LogFile.Write("Getting cell handle for cell %s.\r\n", GetCellNameA());
509                 nResult = afsclient_CellOpen(GetCellNameA(), g_hToken, &g_hCell, pStatus);
510                 if (!nResult) {
511             g_LogFile.Write("Failed to open the cell:  %lx.\r\n", (unsigned long)*pStatus);
512                         return FALSE;
513                 }
514         } else {
515         g_LogFile.Write("Opening a NULL cell handle to use with the server config library handle.\r\n");
516         nResult = afsclient_NullCellOpen(&g_hCell, pStatus);
517         if (!nResult) {
518             g_LogFile.Write("Failed to open a NULL cell handle:  %lx.\r\n", (unsigned long)*pStatus);
519                 return FALSE;
520         }
521     }
522
523         // Get the server handle
524         g_LogFile.Write("Getting config library handle for the server.\r\n");
525         if (!cfg_HostOpen(g_hCell, GetHostnameA(), &g_hServer, pStatus)) {
526         g_LogFile.Write("Failed to get config library handle for the server:  %lx.\r\n", (unsigned long)*pStatus);
527                 return FALSE;
528         }
529
530         return TRUE;
531 }
532
533 BOOL GetHandles(HWND hParentDlg)
534 {
535     afs_status_t nStatus;
536
537     if (!GetLibHandles(&nStatus)) {
538         ShowError(hParentDlg, nStatus, IDS_GET_TOKENS_ERROR);
539         g_CfgData.szAdminPW[0] = 0;
540         return FALSE;
541     }
542
543     return TRUE;
544 }
545
546
547 /*
548  * Static FUNCTIONS _________________________________________________________________
549  *
550  */
551 static void CloseLibHandles(BOOL bExiting)
552 {
553      afs_status_t nStatus;
554
555         // We will close them in the reverse order of their creation.
556
557         if (g_hServer) {
558                 cfg_HostClose(g_hServer, &nStatus);
559                 g_hServer = 0;
560         }
561
562         if (g_hCell) {
563                 afsclient_CellClose(g_hCell, &nStatus);
564                 g_hCell = 0;
565         }
566
567         if (g_hToken) {
568                 afsclient_TokenClose(g_hToken, &nStatus);
569                 g_hToken = 0;
570         }
571
572     // Only close the client cfg and cell handles if we are exiting.
573         if (bExiting) {
574         if (g_hClient) {
575                 cfg_HostClose(g_hClient, &nStatus);
576                 g_hClient = 0;
577         }
578
579         if (hClientCell) {
580                 afsclient_CellClose(hClientCell, &nStatus);
581                 hClientCell = 0;
582         }
583     }
584 }
585
586 static void SetConfigDefaults()
587 {
588         if (g_CfgData.bWizard) {
589                 if (g_CfgData.configFS == CS_NULL)
590                         g_CfgData.configFS = CS_CONFIGURE;
591
592                 if (g_CfgData.configDB == CS_NULL)
593                         g_CfgData.configDB = CS_CONFIGURE;
594                 
595                 if (g_CfgData.configBak == CS_NULL)
596                         g_CfgData.configBak = CS_CONFIGURE;
597
598                 if (g_CfgData.configPartition == CS_NULL)
599                         g_CfgData.configPartition = CS_CONFIGURE;
600
601                 if (g_CfgData.configRootVolumes == CS_NULL)
602                         g_CfgData.configRootVolumes = CS_CONFIGURE;
603
604                 if (g_CfgData.configRep == CS_NULL)
605                         g_CfgData.configRep = CS_CONFIGURE;
606
607                 if (g_CfgData.configSCS == CS_NULL)
608                         g_CfgData.configSCS = CS_DONT_CONFIGURE;
609
610                 if (g_CfgData.configSCC == CS_NULL)
611                         g_CfgData.configSCC = CS_DONT_CONFIGURE;
612         }
613
614         lstrcpy(g_CfgData.szAdminName, TEXT("admin"));
615         lstrcpy(g_CfgData.szAdminUID, TEXT("0"));
616
617         g_CfgData.bUseNextUid = TRUE;
618 }
619
620         
621 // Prototypes for each property page's dialog proc
622 BOOL CALLBACK PartitionsPageDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
623 BOOL CALLBACK ServicesPageDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
624
625 static void RunCfgTool()
626 {
627         // If the client info is invalid, then the config tool cannot run.  Inform the user and
628         // ask if they want to run the wizard instead.
629         if (!g_CfgData.bValidClientInfo) {
630                 int nChoice = MsgBox(0, IDS_NEED_CLIENT_INFO, GetAppTitleID(), MB_YESNO | MB_ICONSTOP);
631                 if (nChoice == IDYES)
632                         RunWizard();
633                 return;
634         }
635
636         // If the server info is invalid, then the config tool cannot run.  The Wizard must be run
637         // to initially configure the server.  Inform the user and ask if they want to run the wizard instead.
638         if (!g_CfgData.bValidServerInfo) {
639                 int nChoice = MsgBox(0, IDS_NEED_SERVER_INFO, GetAppTitleID(), MB_OKCANCEL | MB_ICONEXCLAMATION);
640                 if (nChoice == IDOK)
641                         RunWizard();
642                 return;
643         }
644
645         g_CfgData.bWizard = FALSE;
646
647         SetConfigDefaults();
648
649         RegisterConfigToolHelp();
650
651         // Create the prop sheet
652         g_pSheet = PropSheet_Create(IDS_CFG_TOOL_APP_TITLE, TRUE);
653         
654         // Add the pages
655         PropSheet_AddTab(g_pSheet, IDS_PARTITIONS_PAGE_TITLE, IDD_PARTITIONS_PAGE, (DLGPROC)PartitionsPageDlgProc, 0, TRUE, TRUE);
656         PropSheet_AddTab(g_pSheet, IDS_SERVICES_PAGE_TITLE, IDD_SERVICES_PAGE, (DLGPROC)ServicesPageDlgProc, 0, TRUE);
657
658         // Let the user see it
659         PropSheet_ShowModal(g_pSheet);
660 }
661
662 static void RunWizard()
663 {
664         g_CfgData.bWizard = TRUE;
665
666     SetConfigDefaults();
667
668         RegisterWizardHelp();
669         
670         g_pWiz = new WIZARD;
671         g_pWiz->SetDialogTemplate(IDD_WIZARD, IDC_WIZARD_LEFTPANE, IDC_WIZARD_RIGHTPANE, IDBACK, IDNEXT);
672         g_pWiz->SetGraphic(IDB_GRAPHIC_16, IDB_GRAPHIC_256);
673         g_pWiz->SetStates(g_aStates, g_nNumStates);
674         g_pWiz->SetGraphicCallback(PaintPageGraphic);
675
676         g_pWiz->SetState(sidSTEP_ONE);
677         g_pWiz->Show();
678
679         delete g_pWiz;
680
681         g_pWiz = 0;
682 }
683