/*++ Copyright (c) 1994-1998 Microsoft Corporation Module Name : errors.cpp Abstract: HTTP errors property page Author: Ronald Meijer (ronaldm) Project: Internet Services Manager Revision History: --*/ // // Include Files // #include "stdafx.h" #include "common.h" #include "inetprop.h" #include "InetMgrapp.h" #include "shts.h" #include "w3sht.h" #include "resource.h" #include "fltdlg.h" #include "errors.h" #include "errordlg.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif // // CCustomErrorsListBox : a listbox of CCustomError objects // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< // // Column width relative weights // #define WT_HTTP_ERROR 3 #define WT_OUTPUT_TYPE 2 #define WT_CONTENTS 8 // // Registry key name for this dialog // const TCHAR g_szRegKey[] = _T("Errors"); // // Key under w3svc where the error descriptions live // const TCHAR g_cszErrorLocation[] = _T("Info"); IMPLEMENT_DYNAMIC(CCustomErrorsListBox, CHeaderListBox); const int CCustomErrorsListBox::nBitmaps = 3; CCustomErrorsListBox::CCustomErrorsListBox( IN UINT nIDDefault, IN UINT nIDFile, IN UINT nIDURL ) /*++ Routine Description: Error listbox constructor Arguments: UINT nIDDefault : String ID for 'default' UINT nIDFile : String ID for 'file' UINT nIDURL : String ID for 'URL' --*/ : CHeaderListBox(HLS_STRETCH, g_szRegKey) { VERIFY(m_str[CCustomError::ERT_DEFAULT].LoadString(nIDDefault)); VERIFY(m_str[CCustomError::ERT_FILE].LoadString(nIDFile)); VERIFY(m_str[CCustomError::ERT_URL].LoadString(nIDURL)); } void CCustomErrorsListBox::DrawItemEx( IN CRMCListBoxDrawStruct & ds ) /*++ Routine Description: Draw item in the listbox Arguments: CRMCListBoxDrawStruct & ds : Input data structure Return Value: N/A --*/ { CCustomError * p = (CCustomError *)ds.m_ItemData; ASSERT(p != NULL); DrawBitmap(ds, 0, p->m_nType); CString strError, strText; if (p->m_nSubError > 0) { strError.Format(_T("%d;%d"), p->m_nError, p->m_nSubError); } else { strError.Format(_T("%d"), p->m_nError); } ColumnText(ds, 0, TRUE, strError); ColumnText(ds, 1, FALSE, m_str[p->m_nType] ); if (p->IsDefault()) { strText.Format(_T("\"%s\""), p->m_strDefault); } else { strText = p->m_str; } ColumnText(ds, 2, FALSE, strText); } /* virtual */ BOOL CCustomErrorsListBox::Initialize() /*++ Routine Description: initialize the listbox. Insert the columns as requested, and lay them out appropriately Arguments: None Return Value: TRUE if initialized successfully, FALSE otherwise --*/ { if (!CHeaderListBox::Initialize()) { return FALSE; } HINSTANCE hInst = AfxGetResourceHandle(); InsertColumn(0, WT_HTTP_ERROR, IDS_HTTP_ERROR, hInst); InsertColumn(1, WT_OUTPUT_TYPE, IDS_OUTPUT_TYPE, hInst); InsertColumn(2, WT_CONTENTS, IDS_CONTENTS, hInst); // // Try to set the widths from the stored registry value, // otherwise distribute according to column weights specified // // if (!SetWidthsFromReg()) // { DistributeColumns(); // } SetRedraw(TRUE); return TRUE; } CHTTPErrorDescriptions::CHTTPErrorDescriptions( IN LPCTSTR lpszServer ) /*++ Routine Description: Constructor for default errors object. This fetches the default error definitions Arguments: LPCTSTR lpServerName : Server name Return Value: None --*/ : CMetaProperties( QueryAuthInfo(), CMetabasePath(g_cszSvc, MASTER_INSTANCE, g_cszErrorLocation) ) { m_dwMDUserType = IIS_MD_UT_SERVER; m_dwMDDataType = MULTISZ_METADATA; } /* virtual */ void CHTTPErrorDescriptions::ParseFields() /*++ Routine Description: Parse the fetched data into fields Arguments: None Return Value: None --*/ { BEGIN_PARSE_META_RECORDS(m_dwNumEntries, m_pbMDData) HANDLE_META_RECORD(MD_CUSTOM_ERROR_DESC, m_strlErrorDescriptions) END_PARSE_META_RECORDS } // // Errors property page // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< IMPLEMENT_DYNCREATE(CW3ErrorsPage, CInetPropertyPage) CW3ErrorsPage::CW3ErrorsPage( IN CInetPropertySheet * pSheet ) /*++ Routine Description: Constructor for WWW error property page Arguments: CInetPropertySheet * pSheet : Sheet object Return Value: N/A --*/ : CInetPropertyPage(CW3ErrorsPage::IDD, pSheet), m_list_Errors(IDS_DEFAULT_ERROR, IDS_FILE, IDS_URL), m_ListBoxRes(IDB_ERRORS, m_list_Errors.nBitmaps), m_strlCustomErrors(), m_strlErrorDescriptions(), m_oblErrors() { //{{AFX_DATA_INIT(CW3ErrorsPage) //}}AFX_DATA_INIT m_list_Errors.AttachResources(&m_ListBoxRes); } CW3ErrorsPage::~CW3ErrorsPage() /*++ Routine Description: Destructor Arguments: N/A Return Value: N/A --*/ { } void CW3ErrorsPage::DoDataExchange( IN CDataExchange * pDX ) /*++ Routine Description: Initialise/Store control data Arguments: CDataExchange * pDX - DDX/DDV control structure Return Value: None --*/ { CInetPropertyPage::DoDataExchange(pDX); //{{AFX_DATA_MAP(CW3ErrorsPage) DDX_Control(pDX, IDC_BUTTON_SET_TO_DEFAULT, m_button_SetDefault); DDX_Control(pDX, IDC_BUTTON_EDIT, m_button_Edit); //}}AFX_DATA_MAP DDX_Control(pDX, IDC_LIST_ERRORS, m_list_Errors); if (pDX->m_bSaveAndValidate) { CError err(StoreErrors()); if (err.MessageBoxOnFailure()) { pDX->Fail(); } } } // // Message Map // BEGIN_MESSAGE_MAP(CW3ErrorsPage, CInetPropertyPage) //{{AFX_MSG_MAP(CW3ErrorsPage) ON_BN_CLICKED(IDC_BUTTON_EDIT, OnButtonEdit) ON_BN_CLICKED(IDC_BUTTON_SET_TO_DEFAULT, OnButtonSetToDefault) ON_LBN_DBLCLK(IDC_LIST_ERRORS, OnDblclkListErrors) ON_LBN_SELCHANGE(IDC_LIST_ERRORS, OnSelchangeListErrors) //}}AFX_MSG_MAP END_MESSAGE_MAP() void CW3ErrorsPage::FillListBox() /*++ Routine Description: Populate the listbox with the directory entries Arguments: None Return Value: None --*/ { CObListIter obli(m_oblErrors); CCustomError * pError; // // Remember the selection. // int nCurSel = m_list_Errors.GetCurSel(); m_list_Errors.SetRedraw(FALSE); m_list_Errors.ResetContent(); int cItems = 0; for (/**/; pError = (CCustomError *)obli.Next(); ++cItems) { m_list_Errors.AddItem(pError); } m_list_Errors.SetRedraw(TRUE); m_list_Errors.SetCurSel(nCurSel); } HRESULT CW3ErrorsPage::StoreErrors() /*++ Routine Description: Build errors stringlist from the error oblist built up. Arguments: None Return Value: Error return code --*/ { CError err; try { m_strlCustomErrors.RemoveAll(); POSITION pos = m_oblErrors.GetHeadPosition(); while(pos) { CCustomError * pErr = (CCustomError *)m_oblErrors.GetNext(pos); if (!pErr->IsDefault()) { CString str; pErr->BuildErrorString(str); m_strlCustomErrors.AddTail(str); } } } catch(CMemoryException * e) { err = ERROR_NOT_ENOUGH_MEMORY; e->Delete(); } return err; } CCustomError * CW3ErrorsPage::FindError( IN UINT nError, IN UINT nSubError ) /*++ Routine Description: Find error in the list with the given error code and suberror code Arguments: UINT nError : Error code UINT nSubError : Sub error code Return Value: Pointer to the error or NULL if not found. --*/ { CCustomError * pErr = NULL; POSITION pos = m_oblErrors.GetHeadPosition(); while(pos) { pErr = (CCustomError *)m_oblErrors.GetNext(pos); ASSERT(pErr != NULL); if (pErr->m_nError == nError && pErr->m_nSubError == nSubError) { // // Found it! // return pErr; } } // // Not found! // return NULL; } HRESULT CW3ErrorsPage::FetchErrors() /*++ Routine Description: Build up the errors list Arguments: None Return Value: Error return code --*/ { CError err; CWaitCursor wait; do { try { // // First get the default descriptions // CHTTPErrorDescriptions ed(QueryServerName()); err = ed.LoadData(); if (err.Failed()) { break; } if (!ed.GetErrorDescriptions().IsEmpty()) { POSITION pos = ed.GetErrorDescriptions().GetHeadPosition(); while(pos) { CString & str = ed.GetErrorDescriptions().GetNext(pos); m_oblErrors.AddTail(new CCustomError(str)); } } else { ::AfxMessageBox(IDS_NO_DEF_ERRORS); break; } // // Now match up the overrides if any // POSITION pos = m_strlCustomErrors.GetHeadPosition(); while(pos) { CString & strError = m_strlCustomErrors.GetNext(pos); TRACEEOLID(strError); UINT nError; UINT nSubError; CCustomError::ERT nType; CString str; CCustomError * pErr = NULL; if (CCustomError::CrackErrorString( strError, nError, nSubError, nType, str )) { pErr = FindError(nError, nSubError); } if (pErr != NULL) { pErr->SetValue(nType, str); } else { CString strFmt; strFmt.LoadString(IDS_BAD_ERROR); str.Format(strFmt, nError, nSubError); ::AfxMessageBox(str); break; } } FillListBox(); } catch(CMemoryException * e) { err = ERROR_NOT_ENOUGH_MEMORY; e->Delete(); } } while(FALSE); return err; } void CW3ErrorsPage::SetControlStates() /*++ Routine Description: Enable/disable controls depending on the state of the dialog Arguments: None Return Value: None --*/ { CCustomError * pErr = GetSelectedListItem(); m_button_Edit.EnableWindow(pErr != NULL); m_button_SetDefault.EnableWindow(m_list_Errors.GetSelCount() > 0); } INT_PTR CW3ErrorsPage::ShowPropertyDialog() /*++ Routine Description: Display the add/edit dialog. The return value is the value returned by the dialog Arguments: None Return Value: None --*/ { int nCurSel; CCustomError * pErr = GetSelectedListItem(&nCurSel); if (pErr == NULL) { // // Must be from a double click on extended selection // return IDCANCEL; } CCustomErrorDlg dlgError(pErr, IsLocal(), this); INT_PTR nReturn = dlgError.DoModal(); if (nReturn == IDOK) { // // Re-display the text // m_list_Errors.InvalidateSelection(nCurSel); SetModified(TRUE); } return nReturn; } // // Message Handlers // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< BOOL CW3ErrorsPage::OnInitDialog() /*++ Routine Description: WM_INITDIALOG handler. Initialize the dialog. Arguments: None. Return Value: TRUE if focus is to be set automatically, FALSE if the focus is already set. --*/ { CInetPropertyPage::OnInitDialog(); m_list_Errors.Initialize(); // // Build filters oblist // CError err(FetchErrors()); err.MessageBoxOnFailure(); SetControlStates(); return TRUE; } void CW3ErrorsPage::OnButtonEdit() /*++ Routine Description: 'edit' button handler Arguments: None Return Value: None --*/ { if (ShowPropertyDialog() == IDOK) { SetControlStates(); SetModified(TRUE); } } void CW3ErrorsPage::OnButtonSetToDefault() /*++ Routine Description: 'set to default' button handler Arguments: None Return Value: None --*/ { // // Apply to each selected item // m_list_Errors.SetRedraw(FALSE); int nSel = 0; int cChanges = 0; CCustomError * pErr; while ((pErr = GetNextSelectedItem(&nSel)) != NULL) { if (!pErr->IsDefault()) { // // Force a redraw of the current item // pErr->MakeDefault(); m_list_Errors.InvalidateSelection(nSel); ++cChanges; } ++nSel; } if (cChanges) { SetModified(TRUE); } m_list_Errors.SetRedraw(TRUE); SetControlStates(); } void CW3ErrorsPage::OnDblclkListErrors() /*++ Routine Description: error list 'double click' handler Arguments: None Return Value: None --*/ { OnButtonEdit(); } void CW3ErrorsPage::OnSelchangeListErrors() /*++ Routine Description: error list selection change handler Arguments: None Return Value: None --*/ { SetControlStates(); } /* virtual */ HRESULT CW3ErrorsPage::FetchLoadedValues() /*++ Routine Description: Move configuration data from sheet to dialog controls Arguments: None Return Value: HRESULT --*/ { CError err; BEGIN_META_DIR_READ(CW3Sheet) FETCH_DIR_DATA_FROM_SHEET(m_strlCustomErrors); END_META_DIR_READ(err) return err; } /* virtual */ HRESULT CW3ErrorsPage::SaveInfo() /*++ Routine Description: Save the information on this property page Arguments: None Return Value: Error return code --*/ { ASSERT(IsDirty()); TRACEEOLID("Saving W3 errors page now..."); CError err; BeginWaitCursor(); BEGIN_META_DIR_WRITE(CW3Sheet) STORE_DIR_DATA_ON_SHEET(m_strlCustomErrors) END_META_DIR_WRITE(err) if (err.Succeeded()) { err = ((CW3Sheet *)GetSheet())->SetKeyType(); } EndWaitCursor(); return err; }