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