e42bdc44509bef3acc0dc74f340ec569da01bc33
[openafs.git] / src / WINNT / afssvrcfg / salvage_results_dlg.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 #include <winsock2.h>
15 #include <ws2tcpip.h>
16
17 #include "afscfg.h"             // Main header for this application
18 #include "resource.h"
19 #include "salvage_results_dlg.h"
20 extern "C" {
21 #include <afs\afs_bosAdmin.h>
22 }
23
24
25 /*
26  * DEFINITIONS _________________________________________________________________
27  *
28  */
29 static const int     UPDATE_INTERVAL        = 5000;             // milleseconds
30 static const int     LOG_BUF_SIZE           = 25000;            // bytes
31 static const int     EDIT_CONTROL_MAX_CHARS = 64000;            // Max chars an edit control can hold
32 static const char   *SALVAGE_LOG_FILE_NAME  = "SalvageLog.txt";
33
34 static rwWindowData arwDialog[] = {
35         { IDC_LOG,      raSizeX | raSizeY,      MAKELONG(350, 150), 0 },
36         { IDC_CLOSE,    raMoveX | raMoveY,      0,      0 },
37         { 9,            raMoveX | raMoveY,      0,      0 },
38         { idENDLIST,    0,                      0,      0 }
39 };
40
41
42 /*
43  * Variables _________________________________________________________________
44  *
45  */
46 static HWND hDlg = 0;                                           // HWND for this page's dialog
47 static HWND hLogo;
48 static afs_status_t nStatus;
49 static void *hServer;
50 static int nResult; 
51 static BOOL bSalvageComplete;
52
53
54 /*
55  * PROTOTYPES _________________________________________________________________
56  *
57  */
58 static void OnInitDialog(HWND hwndDlg);
59 static void OnClose();
60 static void SetMessages(int nStatusMsgID, int nLogMsgID);
61 static DWORD WINAPI ShowResults(LPVOID param);
62 static void SaveLogToDisk(char *pszLogBuf, char *pszFileName);
63 static char *AddCarriageReturnsToLog(char *pszInBuf, char *&pszOutBuf);
64 static char *GetMaxPartOfLogWeCanShow(char *pszLogBuf);
65 static BOOL AllocMemory(char *&pszLogBuf, int nBufSize);
66
67 BOOL CALLBACK SalvageResultsDlgProc(HWND hRHS, UINT msg, WPARAM wp, LPARAM lp);
68
69
70 /*
71  * EXPORTED FUNCTIONS _________________________________________________________
72  *
73  */
74 BOOL ShowSalvageResults(HWND hParent)
75 {       
76     int nResult = ModalDialog(IDD_SALVAGE_RESULTS, hParent, (DLGPROC)SalvageResultsDlgProc);
77
78     return (nResult == IDOK);
79 }
80
81
82 /*
83  * Dialog Proc _________________________________________________________________
84  *
85  */
86 BOOL CALLBACK SalvageResultsDlgProc(HWND hwndDlg, UINT msg, WPARAM wp, LPARAM lp)
87 {
88     if (AfsAppLib_HandleHelp(IDD_SALVAGE_RESULTS, hwndDlg, msg, wp, lp))
89         return TRUE;
90
91     switch (msg) {
92     case WM_INITDIALOG:
93         OnInitDialog(hwndDlg);
94         break;
95
96     case WM_COMMAND:
97         switch (LOWORD(wp)) {
98         case IDC_CLOSE:
99             OnClose();
100             break;
101
102         case IDCANCEL:
103             if (bSalvageComplete)
104                 OnClose();
105         }
106         break;
107
108     case WM_SIZE:       
109         if (lp != 0)
110             ResizeWindow(hwndDlg, arwDialog, rwaFixupGuts);
111         break;
112     }
113
114     return FALSE;
115 }       
116
117
118 /*
119  * STATIC FUNCTIONS _________________________________________________________________
120  *
121  */
122
123 /*
124  * Event Handler Functions __________________________________________________________
125  *
126  */
127 static void OnInitDialog(HWND hwndDlg)
128 {
129     hDlg = hwndDlg;
130
131     bSalvageComplete = FALSE;
132
133     ResizeWindow(hDlg, arwDialog, rwaFixupGuts);
134
135     hLogo = GetDlgItem(hDlg, IDC_LOGO);
136
137     AfsAppLib_StartAnimation(hLogo, 8);
138
139     SetMessages(IDS_SALVAGING, IDS_CURRENT_SALVAGE_LOG);
140
141     nResult = bos_ServerOpen(g_hCell, GetHostnameA(), &hServer, &nStatus);
142     if (!nResult) {
143         ShowError(hDlg, nStatus, IDS_BOS_OPEN_FAILED);
144         return;
145     }
146
147     // Remove the start menu - we do this so the user can't close
148     // the dialog while salvage is being performed.
149     DWORD dw;
150     dw = GetWindowLong(hDlg, GWL_STYLE);
151     dw &= ~WS_SYSMENU;
152     SetWindowLong(hDlg, GWL_STYLE, dw);
153
154     // Create a thread to keep the view of the log up to date
155     DWORD dwThreadID;
156     HANDLE hThread = CreateThread(0, 0, ShowResults, 0, 0, &dwThreadID);
157     CloseHandle(hThread);
158 }
159
160 static void OnClose()
161 {
162     bos_ServerClose(hServer, &nStatus);
163
164     EndDialog(hDlg, IDOK);
165 }
166
167
168 /*
169  * Utility Functions _________________________________________________________________
170  *
171  */
172 static void SetMessages(int nStatusMsgID, int nLogMsgID)
173 {
174     TCHAR szMsgBuf[cchRESOURCE];
175
176     SetDlgItemText(hDlg, IDC_SALVAGE_STATUS, GetResString(nStatusMsgID, szMsgBuf));
177     SetDlgItemText(hDlg, IDC_LOG_TITLE, GetResString(nLogMsgID, szMsgBuf));
178 }
179
180 static char *AddCarriageReturnsToLog(char *pszInBuf, char *& pszOutBuf)
181 {
182     ASSERT(pszInBuf);
183
184     char *pInBuf = pszInBuf;
185
186     // How man new lines are there?
187     int nNumNLs = 0;
188
189     while (*pInBuf) {
190         if (*pInBuf == '\n')
191             nNumNLs++;
192         pInBuf++;
193     }
194
195     // Allocate enough memory for the log buffer plus CRs plus a NULL
196     if (!AllocMemory(pszOutBuf, strlen(pszInBuf) + nNumNLs + 1))
197         return 0;
198
199     // Copy over the whole buffer, adding \r's as we go.  The edit control
200     // seems to need \r before \n, so we set it up that way.
201     pInBuf = pszInBuf;
202     char *pOutBuf = pszOutBuf;
203
204     while (*pInBuf) {
205         if (*pInBuf == '\n') {
206             *pOutBuf++ = '\r';
207             *pOutBuf++ = '\n';
208         } else
209             *pOutBuf++ = *pInBuf;
210                 
211         pInBuf++;
212     }
213
214     *pOutBuf = 0;
215
216     return pszOutBuf;
217 }
218
219 static char *GetMaxPartOfLogWeCanShow(char *pszLogBuf)
220 {
221     ASSERT(pszLogBuf);
222
223     // Find out how much of the log buffer is in use
224     int nLen = strlen(pszLogBuf);
225
226     if (nLen < EDIT_CONTROL_MAX_CHARS)
227         return pszLogBuf;
228
229     // Buffer is bigger than maximum, so find the last full line
230     // under the limit and return it.
231     char *psz = pszLogBuf + nLen - EDIT_CONTROL_MAX_CHARS;
232     
233     // Make sure we return the beginning of a line
234     while (*psz && (*psz != '\n'))
235         psz++;
236
237     if (*psz == '\n')
238         psz++;
239
240     return psz;
241 }    
242
243 static BOOL AllocMemory(char *&pszLogBuf, int nBufSize)
244 {
245     if (pszLogBuf)
246         delete pszLogBuf;
247
248     pszLogBuf = new char[nBufSize];
249
250     if (!pszLogBuf) {
251         g_LogFile.Write("Failed to allocate memory (%d bytes) for the salvage log buffer.\r\n", nBufSize);
252         return FALSE;
253     }
254
255     return TRUE;
256 }
257
258 static void SaveLogToDisk(char *pszLogBuf, char *pszFileName)
259 {
260     // If no log file was specified by the user, then do nothing
261     if (!pszFileName[0])
262         return;
263
264     FILE *fp = fopen(pszFileName, "w");
265     if (!fp) {
266         ShowError(hDlg, 0, IDS_ERROR_SAVING_SALVAGE_LOG_TO_DISK);
267         return;
268     }
269
270     fprintf(fp, "%s", pszLogBuf);
271
272     fclose(fp);
273 }
274
275 static DWORD WINAPI ShowResults(LPVOID param)
276 {
277     ULONG nBufSize = LOG_BUF_SIZE;
278     char *pszLogBuf = 0;
279     char *pszLogBufWithCRs = 0;
280     DWORD dwWait = WAIT_TIMEOUT;
281     DWORD rc = 1;
282     ULONG nLogSize = LOG_BUF_SIZE;
283
284     if (!AllocMemory(pszLogBuf, nBufSize))
285         return 0;
286     
287     while (dwWait != WAIT_OBJECT_0) {
288         // Wait for either the salvage thread to terminate or our update
289         // interval to pass.
290         dwWait = WaitForSingleObject(g_CfgData.hSalvageThread, UPDATE_INTERVAL);
291
292         // In either case, update the log display for the user
293
294         // Get the salvage log as it currently exists
295       getlog: 
296         nResult = bos_LogGet(hServer, "SalvageLog", &nLogSize, pszLogBuf, &nStatus);
297         if (!nResult) {
298             if (nStatus == ADMMOREDATA) {
299                 // If salvage isn't done, then get a bigger buffer than we need to
300                 // prevent future ADMMOREDATA errors.
301                 nBufSize = nLogSize;
302                 if (dwWait != WAIT_OBJECT_0) {
303                     nBufSize += LOG_BUF_SIZE;
304                     nLogSize = nBufSize;
305                 }
306                 if (AllocMemory(pszLogBuf, nBufSize))
307                     goto getlog;
308             }
309
310             rc = 0;
311             break;            
312         }
313
314         // NULL-terminate the log
315         pszLogBuf[nLogSize] = 0;
316
317         // The edit control that we use to show the log to the user needs \r\n at the end
318         // of each line, but the salvage log only has \n.  We must replace the \n with
319         // \r\n before showing the log.
320         if (!AddCarriageReturnsToLog(pszLogBuf, pszLogBufWithCRs)) {
321             rc = 0;
322             break;
323         }
324         
325         // The edit control has a limit to the number of characters it can hold.  If the log
326         // is bigger than that limit, then we will show the maximum portion of the end of the
327         // log that we can fit in the edit control.
328         char *pszLogToShow = GetMaxPartOfLogWeCanShow(pszLogBufWithCRs);
329
330         // Put it into the edit control so the user can see it
331         SetDlgItemText(hDlg, IDC_LOG, A2S(pszLogToShow));
332     }
333
334     AfsAppLib_StopAnimation(hLogo);
335
336     if (rc) {
337         SetMessages(IDS_SALVAGE_COMPLETE, IDS_FINAL_SALVAGE_LOG);
338         SaveLogToDisk(pszLogBufWithCRs, GetSalvageLogFileNameA());
339         MsgBox(hDlg, IDS_SALVAGE_COMPLETE, GetAppTitleID(), MB_OK);
340     } else {
341         SetMessages(IDS_SALVAGING, IDS_CANT_GET_SALVAGE_LOG);
342         ShowError(hDlg, nStatus, IDS_CANT_GET_SALVAGE_LOG);
343     }
344
345     CloseHandle(g_CfgData.hSalvageThread);
346
347     if (pszLogBuf)
348         delete pszLogBuf;
349
350     if (pszLogBufWithCRs)
351         delete pszLogBufWithCRs;
352
353     SetEnable(hDlg, IDC_CLOSE);
354
355     bSalvageComplete = TRUE;
356
357     return rc;
358 }
359