/*++ Copyright (c) 1994-2001 Microsoft Corporation Module Name : errordlg.cpp Abstract: Error edit dialog Author: Ronald Meijer (ronaldm) Sergei Antonov (sergeia) Project: Internet Services Manager Revision History: --*/ #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 "errordlg.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif // // HTTP Custom Error Definition // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< // // Static Initialization // LPCTSTR CCustomError::s_szSep = _T(","); LPCTSTR CCustomError::s_szURL = _T("URL"); LPCTSTR CCustomError::s_szFile = _T("FILE"); LPCTSTR CCustomError::s_szNoSubError = _T("*"); #define GET_FIELD()\ end = strError.Find(s_szSep, start);\ if (end == -1) \ end = strError.GetLength() #define SKIP()\ start = end + skip #define GET_INT_FIELD(n)\ GET_FIELD();\ (n) = StrToInt(strError.Mid(start, end - start));\ SKIP() /* static */ BOOL CCustomError::CrackErrorString( IN LPCTSTR lpstrErrorString, OUT UINT & nError, OUT UINT & nSubError, OUT ERT & nType, OUT CString & str ) /*++ Routine Description Helper function to parse error string into component parts Arguments: LPCTSTR lpstrErrorString : Error input string UINT & nError : Error UINT & nSubError : Sub Error int & nType : Error type CString & str : Text parameter Return Value: TRUE for success, FALSE for failure --*/ { BOOL fSuccess = FALSE; do { CString strError(lpstrErrorString); TRACEEOLID(strError); int start = 0, end, skip = lstrlen(s_szSep); GET_INT_FIELD(nError); ASSERT(nError > 0); GET_INT_FIELD(nSubError); GET_FIELD(); nType = strError.Mid(start, end - start).CompareNoCase(s_szURL) == 0 ? ERT_URL : ERT_FILE; SKIP(); if (-1 != (end = strError.ReverseFind((TCHAR) s_szSep))) str = strError.Mid(start, end - start); else str = strError.Right(strError.GetLength() - start); fSuccess = TRUE; } while(FALSE); return fSuccess; } /* static */ void CCustomError::CrackErrorDescription( IN LPCTSTR lpstrErrorString, OUT UINT & nError, OUT UINT & nSubError, OUT BOOL & fURLSupported, OUT CString & str ) /*++ Routine Description Helper function to parse error description into component parts Arguments: LPCTSTR lpstrErrorString : Error input string UINT & nError : Error UINT & nSubError : Sub Error BOOL & fURLSupported : Return TRUE if urls are allowed CString & str : Text parameter Return Value: None. --*/ { try { CString strError(lpstrErrorString); TRACEEOLID(strError); int start = 0, end, skip = lstrlen(s_szSep); fURLSupported = FALSE; do { GET_INT_FIELD(nError); ASSERT(nError > 0); GET_INT_FIELD(nSubError); GET_FIELD(); str = strError.Mid(start, end - start); SKIP(); GET_FIELD(); if (nSubError > 0) { str += _T(" - "); str += strError.Mid(start, end - start); } SKIP(); GET_FIELD(); fURLSupported = end != -1 && end > start ? 0 == StrToInt(strError.Mid(start, end - start)) : FALSE; } while (FALSE); /* LPTSTR lp = strError.GetBuffer(0); LPTSTR lpField = StringTok(lp, s_szSep); nError = _ttoi(lpField); ASSERT(nError > 0); lpField = StringTok(NULL, s_szSep); ASSERT(lpField != NULL); nSubError = lpField != NULL ? _ttoi(lpField) : 0; lpField = StringTok(NULL, s_szSep); ASSERT(lpField != NULL); str = lpField; lpField = StringTok(NULL, s_szSep); ASSERT(lpField != NULL); if (nSubError > 0) { // // Add sub error text // ASSERT(nSubError > 0); str += _T(" - "); str += lpField; lpField = StringTok(NULL, s_szSep); } ASSERT(lpField != NULL); fURLSupported = lpField != NULL ? (_ttoi(lpField) == 0) : FALSE; */ } catch(CException * e) { e->ReportError(); e->Delete(); } } CCustomError::CCustomError( IN LPCTSTR lpstrErrorString ) /*++ Routine Description: Construct error definition from metabase string Arguments: LPCTSTR lpstrErrorString : Error string Return Value: N/A --*/ : m_nType(ERT_DEFAULT) { CrackErrorDescription( lpstrErrorString, m_nError, m_nSubError, m_fURLSupported, m_strDefault ); } void CCustomError::BuildErrorString( OUT CString & str ) /*++ Routine Description: Build metabase-ready error string out of the current values Arguments: CString & str : String Return Value: None --*/ { ASSERT(!IsDefault()); try { if (m_nSubError > 0) { str.Format(_T("%d,%d,%s,%s"), m_nError, m_nSubError, IsFile() ? s_szFile : s_szURL, (LPCTSTR)m_str ); } else { str.Format( _T("%d,%s,%s,%s"), m_nError, s_szNoSubError, IsFile() ? s_szFile : s_szURL, (LPCTSTR)m_str ); } } catch(CMemoryException * e) { e->ReportError(); e->Delete(); } } int CCustomError::OrderByErrorNum( IN const CObjectPlus * pobAccess ) const /*++ Routine Description: Compare two custom errors against each other, and sort on Number first, and order secondarily. Arguments: const CObjectPlus * pobAccess : This really refers to another CCustomError to be compared to. Return Value: Sort (+1, 0, -1) return value --*/ { const CCustomError * pob = (CCustomError *)pobAccess; if (pob->m_nError != m_nError) { // sort by error in small to big order return m_nError - pob->m_nError; } // // Sort by sub error in small to big order // return m_nSubError - pob->m_nSubError; } // // Custom Errors property page // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CCustomErrorDlg::CCustomErrorDlg( IN OUT CCustomError * pErr, IN BOOL fLocal, IN CWnd * pParent OPTIONAL ) /*++ Routine Description: Error editing dialog Arguments: CCustomError * pErr : Error definition to be edited BOOL fLocal : TRUE if the current computer is local CWnd * pParent : Optional parent window or NULL Return Value: N/A --*/ : CDialog(CCustomErrorDlg::IDD, pParent), m_fLocal(fLocal), m_pErr(pErr), m_nMessageType(pErr->m_nType), m_strTextFile(pErr->m_str), m_strDefText(pErr->m_strDefault) { #if 0 // Keep Class Wizard Happy //{{AFX_DATA_INIT(CCustomErrorDlg) m_nMessageType = -1; m_strTextFile = _T(""); m_strDefText = _T(""); //}}AFX_DATA_INIT #endif // 0 VERIFY(m_strFile.LoadString(IDS_FILE_PROMPT)); VERIFY(m_strURL.LoadString(IDS_URL_PROMPT)); } void CCustomErrorDlg::DoDataExchange( IN CDataExchange * pDX ) /*++ Routine Description: Initialise/Store control data Arguments: CDataExchange * pDX - DDX/DDV control structure Return Value: None --*/ { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CCustomErrorDlg) DDX_CBIndex(pDX, IDC_COMBO_MESSAGE_TYPE, m_nMessageType); DDX_Text(pDX, IDC_STATIC_DEF_TEXT, m_strDefText); DDX_Control(pDX, IDC_EDIT_TEXT_FILE, m_edit_TextFile); DDX_Control(pDX, IDC_STATIC_SUB_PROMPT, m_static_SubErrorPrompt); DDX_Control(pDX, IDC_STATIC_SUB_ERROR_CODE, m_static_SubError); DDX_Control(pDX, IDC_STATIC_TEXT_FILE_PROMT, m_static_TextFilePrompt); DDX_Control(pDX, IDC_BUTTON_BROWSE, m_button_Browse); DDX_Control(pDX, IDC_COMBO_MESSAGE_TYPE, m_combo_MessageType); DDX_Control(pDX, IDOK, m_button_OK); //}}AFX_DATA_MAP DDX_TextBalloon(pDX, IDC_STATIC_ERROR_CODE, m_pErr->m_nError); DDX_TextBalloon(pDX, IDC_STATIC_SUB_ERROR_CODE, m_pErr->m_nSubError); DDX_Text(pDX, IDC_EDIT_TEXT_FILE, m_strTextFile); m_strTextFile.TrimLeft(); m_strTextFile.TrimRight(); if (pDX->m_bSaveAndValidate) { if (m_nMessageType == CCustomError::ERT_FILE) { DDV_FilePath(pDX, m_strTextFile, m_fLocal); } else if (m_nMessageType == CCustomError::ERT_URL) { // We are accepting only absolute URLs within the site, i.e. /foo/bar/error.html if (!IsRelURLPath(m_strTextFile)) { pDX->PrepareEditCtrl(IDC_EDIT_TEXT_FILE); DDV_ShowBalloonAndFail(pDX, IDS_BAD_ERROR_URL); } } } } // // Message Map // BEGIN_MESSAGE_MAP(CCustomErrorDlg, CDialog) //{{AFX_MSG_MAP(CCustomErrorDlg) ON_CBN_SELCHANGE(IDC_COMBO_MESSAGE_TYPE, OnSelchangeComboMessageType) ON_BN_CLICKED(IDC_BUTTON_BROWSE, OnButtonBrowse) ON_EN_CHANGE(IDC_EDIT_TEXT_FILE, OnChangeEditTextFile) //}}AFX_MSG_MAP END_MESSAGE_MAP() BOOL CCustomErrorDlg::SetControlStates() /*++ Routine Description: Set the enabled states of the dialog controls depending on the current state of the dialog Arguments: None Return Value: TRUE if file/url is selected, FALSE otherwise --*/ { int nCurSel = m_combo_MessageType.GetCurSel(); BOOL fFile = nCurSel == CCustomError::ERT_FILE; BOOL fDefault = nCurSel == CCustomError::ERT_DEFAULT; ActivateControl(m_button_Browse, m_fLocal && fFile); ActivateControl(m_edit_TextFile, !fDefault); ActivateControl(m_static_TextFilePrompt, !fDefault); m_static_TextFilePrompt.SetWindowText(fFile ? m_strFile : m_strURL); m_button_OK.EnableWindow(fDefault || m_edit_TextFile.GetWindowTextLength() > 0); return !fDefault; } // // Message Handlers // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< BOOL CCustomErrorDlg::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. --*/ { CDialog::OnInitDialog(); // // Browsing available locally only // m_button_Browse.EnableWindow(m_fLocal); CString str; VERIFY(str.LoadString(IDS_DEFAULT_ERROR)); m_combo_MessageType.AddString(str); VERIFY(str.LoadString(IDS_FILE)); m_combo_MessageType.AddString(str); if (m_pErr->URLSupported() || m_nMessageType == CCustomError::ERT_URL) { VERIFY(str.LoadString(IDS_URL)); m_combo_MessageType.AddString(str); } m_combo_MessageType.SetCurSel(m_nMessageType); if (m_pErr->m_nSubError == 0) { DeActivateControl(m_static_SubErrorPrompt); DeActivateControl(m_static_SubError); } SetControlStates(); // if (m_nMessageType == CCustomError::ERT_FILE) // { // #ifdef SUPPORT_SLASH_SLASH_QUESTIONMARK_SLASH_TYPE_PATHS // LimitInputPath(CONTROL_HWND(IDC_EDIT_TEXT_FILE),TRUE); // #else // LimitInputPath(CONTROL_HWND(IDC_EDIT_TEXT_FILE),FALSE); // #endif // } // else if (m_nMessageType == CCustomError::ERT_URL) // { // } return TRUE; } void CCustomErrorDlg::OnSelchangeComboMessageType() /*++ Routine Description: Handle change in message type combo box Arguments: None Return Value: None --*/ { int nSel = m_combo_MessageType.GetCurSel(); if (m_nMessageType == nSel) { // // Selection didn't change // return; } m_nMessageType = nSel; if (SetControlStates()) { m_edit_TextFile.SetWindowText(_T("")); m_edit_TextFile.SetFocus(); } } void CCustomErrorDlg::OnChangeEditTextFile() /*++ Routine Description: Handle change in text/file edit box Arguments: None Return Value: None --*/ { SetControlStates(); } void CCustomErrorDlg::OnOK() /*++ Routine Description: Handle the OK button being pressed Arguments: None Return Value: None --*/ { if (UpdateData(TRUE)) { m_pErr->m_nType = (CCustomError::ERT)m_nMessageType; m_pErr->m_str = m_strTextFile; CDialog::OnOK(); } } void CCustomErrorDlg::OnButtonBrowse() /*++ Routine Description: Browse for HTML File Arguments: None Return Value: None --*/ { ASSERT(m_fLocal); // // popup the file dialog and let the user select the error htm file // CString str; str.LoadString(IDS_HTML_MASK); CFileDialog dlgBrowse(TRUE, NULL, NULL, OFN_HIDEREADONLY, str, this); // Disable hook to get Windows 2000 style dialog dlgBrowse.m_ofn.Flags &= ~(OFN_ENABLEHOOK); dlgBrowse.m_ofn.Flags |= OFN_DONTADDTORECENT|OFN_FILEMUSTEXIST; if (dlgBrowse.DoModal() == IDOK) { m_pErr->m_str = dlgBrowse.GetPathName(); m_edit_TextFile.SetWindowText(m_pErr->m_str); } }