/*++ Copyright (c) 1996 Microsoft Corporation Module Name: proxysup.c Abstract: Contains implementation for proxy server and proxy bypass list dialog interface. WARNING: Changes in this code need to be syncronizated with changes in proxysup.cxx in the WININET project. Contents: Author: Arthur L Bierer (arthurbi) 18-Apr-1996 Revision History: 18-Apr-1996 arthurbi Created --*/ #include "inetcplp.h" #include // Disable warning for VC6 (ASSERT macro causing the problem) #pragma warning(4:4509) // nonstandard extension used: 'ftn' uses SEH and 'object' has destructor // // Don't use CRTs so define our own isdigit // #undef isdigit #define isdigit(ch) (ch >= '0' && ch <= '9') // // ARRAY_ELEMENTS - returns number of elements in array // #define ARRAY_ELEMENTS(array) (sizeof(array)/sizeof(array[0])) #define GET_TERMINATOR(string) while(*string != '\0') string++ #define IS_BLANK(string) (*string == '\0') // // private types // typedef enum { STATE_START, STATE_PROTOCOL, STATE_SCHEME, STATE_SERVER, STATE_PORT, STATE_END, STATE_ERROR } PARSER_STATE; typedef struct tagMY_URL_SCHEME { LPSTR SchemeName; DWORD SchemeLength; INTERNET_SCHEME SchemeType; DWORD dwControlId; DWORD dwPortControlId; } MY_URL_SCHEME; const MY_URL_SCHEME UrlSchemeList[] = { NULL, 0, INTERNET_SCHEME_DEFAULT,IDC_NOTUSED, IDC_NOTUSED, "ftp", 3, INTERNET_SCHEME_FTP, IDC_PROXY_FTP_ADDRESS, IDC_PROXY_FTP_PORT, "gopher", 6, INTERNET_SCHEME_GOPHER, IDC_PROXY_GOPHER_ADDRESS, IDC_PROXY_GOPHER_PORT, "http", 4, INTERNET_SCHEME_HTTP, IDC_PROXY_HTTP_ADDRESS, IDC_PROXY_HTTP_PORT, "https", 5, INTERNET_SCHEME_HTTPS, IDC_PROXY_SECURITY_ADDRESS, IDC_PROXY_SECURITY_PORT, "socks", 5, INTERNET_SCHEME_SOCKS, IDC_PROXY_SOCKS_ADDRESS, IDC_PROXY_SOCKS_PORT, }; #define INTERNET_MAX_PORT_LENGTH sizeof("123456789") typedef struct tagBEFOREUSESAME { // addresses TCHAR szFTP [ INTERNET_MAX_URL_LENGTH + 1 ]; TCHAR szGOPHER [ INTERNET_MAX_URL_LENGTH + 1 ]; TCHAR szSECURE [ INTERNET_MAX_URL_LENGTH + 1 ]; TCHAR szSOCKS [ INTERNET_MAX_URL_LENGTH + 1 ]; // ports TCHAR szFTPport [ INTERNET_MAX_PORT_LENGTH + 1 ]; TCHAR szGOPHERport [ INTERNET_MAX_PORT_LENGTH + 1 ]; TCHAR szSECUREport [ INTERNET_MAX_PORT_LENGTH + 1 ]; TCHAR szSOCKSport [ INTERNET_MAX_PORT_LENGTH + 1 ]; } BEFOREUSESAME, *LPBEFOREUSESAME; static const int g_iProxies[] = {IDC_PROXY_HTTP_ADDRESS, IDC_PROXY_FTP_ADDRESS, IDC_PROXY_GOPHER_ADDRESS, IDC_PROXY_SECURITY_ADDRESS, IDC_PROXY_SOCKS_ADDRESS}; typedef struct tagPROXYPAGE { LPBEFOREUSESAME lpOldSettings; BOOL fNT; LPPROXYINFO lpi; HINSTANCE hinstUrlMon; // runtime load URLMON.DLL } PROXYPAGE, *LPPROXYPAGE; extern const TCHAR cszLocalString[] = TEXT(""); #define MAX_SCHEME_NAME_LENGTH sizeof("gopher") #define MAX_TITLE 80 #define MAX_DIALOG_MESSAGE 300 // // private function prototypes // LPBEFOREUSESAME SaveCurrentSettings(HWND hDlg); void RestorePreviousSettings(HWND hDlg, LPBEFOREUSESAME lpSave); BOOL ProxyDlgInitProxyServers( IN HWND hDlg ); BOOL ProxyDlgOK( IN HWND hDlg ); BOOL ProxyDlgInit( IN HWND hDlg, LPARAM lParam ); VOID EnableProxyControls( IN HWND hDlg ); BOOL IsProxyValid( IN HWND hDlg ); BOOL ParseEditCtlForPort( IN OUT LPSTR lpszProxyName, IN HWND hDlg, IN DWORD dwProxyNameCtlId, IN DWORD dwProxyPortCtlId ); BOOL FormatOutProxyEditCtl( IN HWND hDlg, IN DWORD dwProxyNameCtlId, IN DWORD dwProxyPortCtlId, OUT LPSTR lpszOutputStr, IN OUT LPDWORD lpdwOutputStrSize, IN DWORD dwOutputStrLength, IN BOOL fDefaultProxy ); INTERNET_SCHEME MapUrlSchemeName( IN LPSTR lpszSchemeName, IN DWORD dwSchemeNameLength ); DWORD MapUrlSchemeTypeToCtlId( IN INTERNET_SCHEME SchemeType, IN BOOL fIdForPortCtl ); BOOL MapCtlIdUrlSchemeName( IN DWORD dwEditCtlId, OUT LPSTR lpszSchemeOut ); DWORD MapAddrCtlIdToPortCtlId( IN DWORD dwEditCtlId ); BOOL RemoveLocalFromExceptionList( IN LPTSTR lpszExceptionList ); // // functions // /******************************************************************* NAME: ProxyDlgProc SYNOPSIS: Proxy property sheet dialog proc. ********************************************************************/ INT_PTR CALLBACK ProxyDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { LPPROXYPAGE pPxy= (LPPROXYPAGE) GetWindowLongPtr(hDlg, DWLP_USER); switch (uMsg) { case WM_INITDIALOG: { BOOL fInited; fInited = ProxyDlgInit(hDlg, lParam); return fInited; } case WM_NOTIFY: { NMHDR * lpnm = (NMHDR *) lParam; switch (lpnm->code) { case PSN_APPLY: { BOOL fRet = ProxyDlgOK(hDlg); SetPropSheetResult(hDlg,!fRet); return !fRet; break; } case PSN_RESET: SetPropSheetResult(hDlg,FALSE); break; } break; } case WM_COMMAND: switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_PROXY_ENABLE: EnableProxyControls(hDlg); break; case IDC_PROXY_HTTP_ADDRESS: case IDC_PROXY_GOPHER_ADDRESS: case IDC_PROXY_SECURITY_ADDRESS: case IDC_PROXY_FTP_ADDRESS: case IDC_PROXY_SOCKS_ADDRESS: if ( GET_WM_COMMAND_CMD(wParam, lParam) == EN_KILLFOCUS ) { ParseEditCtlForPort(NULL, hDlg, (GET_WM_COMMAND_ID(wParam, lParam)), 0); EnableProxyControls(hDlg); } break; case IDC_PROXY_HTTP_PORT: case IDC_PROXY_GOPHER_PORT: case IDC_PROXY_SECURITY_PORT: case IDC_PROXY_FTP_PORT: case IDC_PROXY_SOCKS_PORT: if ( GET_WM_COMMAND_CMD(wParam, lParam) == EN_KILLFOCUS ) { EnableProxyControls(hDlg); } break; case IDC_PROXY_USE_SAME_SERVER: if ( GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED ) { if (IsDlgButtonChecked(hDlg, IDC_PROXY_USE_SAME_SERVER)) pPxy->lpOldSettings = SaveCurrentSettings(hDlg); else if (pPxy->lpOldSettings !=NULL) { RestorePreviousSettings(hDlg, pPxy->lpOldSettings); pPxy->lpOldSettings = NULL; } EnableProxyControls(hDlg); } break; case IDOK: if ( GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED ) { BOOL fLeaveDialog = TRUE; if (!IsProxyValid(hDlg)) { // The proxy is invalid, so we need to ask the user if they want to turn it off. TCHAR szTitle[MAX_TITLE]; TCHAR szMessage[MAX_DIALOG_MESSAGE]; int nUserResponce; MLLoadShellLangString(IDS_INVALID_PROXY_TITLE, szTitle, ARRAYSIZE(szTitle)); MLLoadShellLangString(IDS_INVALID_PROXY, szMessage, ARRAYSIZE(szMessage)); // Ask the user if they want to turn off the proxy. nUserResponce = MessageBox(hDlg, szMessage, szTitle, MB_YESNOCANCEL | MB_ICONERROR); if (IDYES == nUserResponce) pPxy->lpi->fEnable = FALSE; else if (IDCANCEL == nUserResponce) fLeaveDialog = FALSE; // The user hit cancel, so let's not leave the dialog. } if (fLeaveDialog) { // // Read the Ctls and Save out to the proxy.. // ProxyDlgOK(hDlg); EndDialog(hDlg, IDOK); } } break; case IDCANCEL: if ( GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED ) { EndDialog(hDlg, IDCANCEL); } break; } break; case WM_DESTROY: if (pPxy->lpOldSettings) LocalFree(pPxy->lpOldSettings); if (pPxy->hinstUrlMon) FreeLibrary(pPxy->hinstUrlMon); LocalFree(pPxy); return TRUE; case WM_HELP: // F1 ResWinHelp((HWND) ((LPHELPINFO)lParam)->hItemHandle, IDS_HELPFILE, HELP_WM_HELP, (DWORD_PTR)(LPSTR)mapIDCsToIDHs); break; case WM_CONTEXTMENU: // right mouse click ResWinHelp((HWND)wParam, IDS_HELPFILE, HELP_CONTEXTMENU, (DWORD_PTR)(LPSTR)mapIDCsToIDHs); break; default: return FALSE; } return TRUE; } // // Private Functions. // VOID EnableProxyControls(HWND hDlg) /*++ Routine Description: Enables controls appropriately depending on what checkboxes are checked. Arguments: hDlg - Page Dialog Box. Return Value: VOID --*/ { BOOL fNT = ((LPPROXYPAGE)GetWindowLongPtr(hDlg, DWLP_USER))->fNT; BOOL fEnable = !g_restrict.fProxy; BOOL fUseOneProxy = IsDlgButtonChecked(hDlg,IDC_PROXY_USE_SAME_SERVER); EnableDlgItem(hDlg,IDC_GRP_SETTINGS2, fEnable); EnableDlgItem(hDlg,IDC_PROXY_EXCEPTIONS_GROUPBOX, fEnable); EnableDlgItem(hDlg,IDC_TYPE_TEXT, fEnable); EnableDlgItem(hDlg,IDC_ADDR_TEXT, fEnable); EnableDlgItem(hDlg,IDC_PORT_TEXT, fEnable); EnableDlgItem(hDlg,IDC_EXCEPT_TEXT, fEnable); EnableDlgItem(hDlg,IDC_EXCEPT2_TEXT, fEnable); EnableDlgItem(hDlg,IDC_PROXY_ICON1, fEnable); EnableDlgItem(hDlg,IDC_PROXY_ICON2, fEnable); EnableDlgItem(hDlg,IDC_PROXY_HTTP_CAPTION, fEnable); EnableDlgItem(hDlg,IDC_PROXY_SECURITY_CAPTION, fEnable); EnableDlgItem(hDlg,IDC_PROXY_FTP_CAPTION, fEnable); EnableDlgItem(hDlg,IDC_PROXY_GOPHER_CAPTION, fEnable); EnableDlgItem(hDlg,IDC_PROXY_SOCKS_CAPTION, fEnable); EnableDlgItem(hDlg, IDC_PROXY_USE_SAME_SERVER, fEnable); EnableDlgItem(hDlg,IDC_PROXY_HTTP_ADDRESS,fEnable); EnableDlgItem(hDlg,IDC_PROXY_HTTP_PORT,fEnable); EnableDlgItem(hDlg,IDC_PROXY_OVERRIDE,fEnable); // // If we only want one Proxy, then make all others use the same // proxy. // EnableDlgItem(hDlg,IDC_PROXY_SECURITY_ADDRESS,!fUseOneProxy && fEnable); EnableDlgItem(hDlg,IDC_PROXY_SECURITY_PORT,!fUseOneProxy && fEnable); EnableDlgItem(hDlg,IDC_PROXY_FTP_ADDRESS,!fUseOneProxy && fEnable); EnableDlgItem(hDlg,IDC_PROXY_FTP_PORT,!fUseOneProxy && fEnable); EnableDlgItem(hDlg,IDC_PROXY_GOPHER_ADDRESS,!fUseOneProxy && fEnable); EnableDlgItem(hDlg,IDC_PROXY_GOPHER_PORT,!fUseOneProxy && fEnable); EnableDlgItem(hDlg,IDC_PROXY_SOCKS_ADDRESS,!fUseOneProxy && fEnable); EnableDlgItem(hDlg,IDC_PROXY_SOCKS_PORT,!fUseOneProxy && fEnable); // // If we only want one proxy, prepopulate the other fields // so they use the the mirror of the first one. // if (fUseOneProxy) { TCHAR szProxyName[MAX_URL_STRING+1]; TCHAR szProxyPort[INTERNET_MAX_PORT_LENGTH]; GetDlgItemText(hDlg, IDC_PROXY_HTTP_ADDRESS, szProxyName, ARRAYSIZE(szProxyName)); GetDlgItemText(hDlg, IDC_PROXY_HTTP_PORT, szProxyPort, ARRAYSIZE(szProxyPort)); SetDlgItemText(hDlg,IDC_PROXY_SECURITY_ADDRESS,szProxyName); SetDlgItemText(hDlg,IDC_PROXY_SECURITY_PORT,szProxyPort); SetDlgItemText(hDlg,IDC_PROXY_FTP_ADDRESS,szProxyName); SetDlgItemText(hDlg,IDC_PROXY_FTP_PORT,szProxyPort); SetDlgItemText(hDlg,IDC_PROXY_GOPHER_ADDRESS,szProxyName); SetDlgItemText(hDlg,IDC_PROXY_GOPHER_PORT,szProxyPort); SetDlgItemText(hDlg,IDC_PROXY_SOCKS_ADDRESS,TEXT("")); SetDlgItemText(hDlg,IDC_PROXY_SOCKS_PORT,TEXT("")); } } // // SaveCurrentSettings() // // Saves current settings... just in case user changes their mind. // // Returns a pointer to a structure filled with current settings. // LPBEFOREUSESAME SaveCurrentSettings(HWND hDlg) { LPBEFOREUSESAME lpSave = (LPBEFOREUSESAME)LocalAlloc(LPTR, sizeof(*lpSave)); if (!lpSave) return lpSave; // if NULL return NULL GetDlgItemText(hDlg, IDC_PROXY_FTP_ADDRESS, lpSave->szFTP, INTERNET_MAX_URL_LENGTH); GetDlgItemText(hDlg, IDC_PROXY_GOPHER_ADDRESS, lpSave->szGOPHER, INTERNET_MAX_URL_LENGTH); GetDlgItemText(hDlg, IDC_PROXY_SECURITY_ADDRESS, lpSave->szSECURE, INTERNET_MAX_URL_LENGTH); GetDlgItemText(hDlg, IDC_PROXY_SOCKS_ADDRESS, lpSave->szSOCKS, INTERNET_MAX_URL_LENGTH); GetDlgItemText(hDlg, IDC_PROXY_FTP_PORT, lpSave->szFTPport, INTERNET_MAX_URL_LENGTH); GetDlgItemText(hDlg, IDC_PROXY_GOPHER_PORT, lpSave->szGOPHERport, INTERNET_MAX_URL_LENGTH); GetDlgItemText(hDlg, IDC_PROXY_SECURITY_PORT, lpSave->szSECUREport, INTERNET_MAX_URL_LENGTH); GetDlgItemText(hDlg, IDC_PROXY_SOCKS_PORT, lpSave->szSOCKSport, INTERNET_MAX_URL_LENGTH); return lpSave; } // SaveCurrentSettings() // // RestorePreviousSettings() // // Restores settings... just in case user changes their mind. // void RestorePreviousSettings(HWND hDlg, LPBEFOREUSESAME lpSave) { if (!lpSave) return; // nothing to do SetDlgItemText(hDlg, IDC_PROXY_FTP_ADDRESS, lpSave->szFTP ); SetDlgItemText(hDlg, IDC_PROXY_GOPHER_ADDRESS, lpSave->szGOPHER ); SetDlgItemText(hDlg, IDC_PROXY_SECURITY_ADDRESS, lpSave->szSECURE ); SetDlgItemText(hDlg, IDC_PROXY_SOCKS_ADDRESS, lpSave->szSOCKS ); SetDlgItemText(hDlg, IDC_PROXY_FTP_PORT, lpSave->szFTPport ); SetDlgItemText(hDlg, IDC_PROXY_GOPHER_PORT, lpSave->szGOPHERport ); SetDlgItemText(hDlg, IDC_PROXY_SECURITY_PORT, lpSave->szSECUREport ); SetDlgItemText(hDlg, IDC_PROXY_SOCKS_PORT, lpSave->szSOCKSport ); LocalFree(lpSave); // give back the memory } // RestorePreviousSettings() BOOL ProxyDlgInit( IN HWND hDlg, LPARAM lParam ) /*++ Routine Description: Initialization proc for proxy prop page Arguments: hDlg - Page Dialog Box. Return Value: BOOL Success - TRUE Failure - FALSE --*/ { BOOL fSuccess; LPPROXYPAGE pPxy; pPxy = (LPPROXYPAGE)LocalAlloc(LPTR, sizeof(*pPxy)); // NOTE: this NULLS lpOldSettings if (!pPxy) return FALSE; // no memory? OSVERSIONINFOA osvi; osvi.dwOSVersionInfoSize = sizeof(osvi); GetVersionExA(&osvi); pPxy->fNT = (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT); ASSERT(pPxy->lpOldSettings == NULL); // tell dialog where to get info SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)pPxy); pPxy->lpi = (LPPROXYINFO)lParam; // // Begin by reading and setting the list of proxy // servers we have. // fSuccess = ProxyDlgInitProxyServers( hDlg ); if (!fSuccess) return FALSE; // // read settings from registry, for the list of Exclusion Hosts. // RegEntry re(REGSTR_PATH_INTERNETSETTINGS,HKEY_CURRENT_USER); if (re.GetError() == ERROR_SUCCESS) { BUFFER bufProxyString(MAX_URL_STRING+1); if (!bufProxyString) { MsgBox(NULL,IDS_ERROutOfMemory,MB_ICONEXCLAMATION,MB_OK); return FALSE; } // // get proxy override settings from registry and stuff fields // Prevent entry of more than (MAX_URL_STRING - ("" + safety)) SendMessage(GetDlgItem(hDlg, IDC_PROXY_OVERRIDE), EM_SETLIMITTEXT, (WPARAM)ARRAYSIZE(pPxy->lpi->szOverride)-20, 0); SetDlgItemText(hDlg, IDC_PROXY_OVERRIDE, pPxy->lpi->szOverride); } // // initialize the UI appropriately // EnableProxyControls(hDlg); return TRUE; } BOOL ProxyDlgOK( IN HWND hDlg ) /*++ Routine Description: OK button handler for proxy prop page Arguments: hDlg - Page Dialog Box. Return Value: BOOL Success - TRUE Failure - FALSE --*/ { LPPROXYPAGE pPxy = (LPPROXYPAGE)GetWindowLongPtr(hDlg, DWLP_USER); TCHAR szProxyListOutputBuffer[MAX_URL_STRING]; CHAR szProxyListOutputBufferA[MAX_URL_STRING]; DWORD dwBufferOffset = 0; // // Get the state of our two check boxes. // BOOL fUseOneProxy = IsDlgButtonChecked(hDlg,IDC_PROXY_USE_SAME_SERVER); // // Open our Registry Key. // RegEntry re(REGSTR_PATH_INTERNETSETTINGS,HKEY_CURRENT_USER); if (re.GetError() == ERROR_SUCCESS) { // // Now Format, and write out the list of proxies to // the registry. We special case the case of // only proxy. // szProxyListOutputBufferA[dwBufferOffset] = '\0'; if ( fUseOneProxy ) { FormatOutProxyEditCtl( hDlg, IDC_PROXY_HTTP_ADDRESS, IDC_PROXY_HTTP_PORT, szProxyListOutputBufferA, &dwBufferOffset, ARRAY_ELEMENTS(szProxyListOutputBufferA), TRUE ); } else { for (int i = 1; i < ARRAY_ELEMENTS(UrlSchemeList); ++i) { FormatOutProxyEditCtl( hDlg, UrlSchemeList[i].dwControlId, UrlSchemeList[i].dwPortControlId, szProxyListOutputBufferA, &dwBufferOffset, ARRAY_ELEMENTS(szProxyListOutputBufferA), FALSE ); } } szProxyListOutputBufferA[dwBufferOffset] = '\0'; #ifdef UNICODE SHAnsiToUnicode(szProxyListOutputBufferA, szProxyListOutputBuffer, MAX_URL_STRING); #else lstrcpy(szProxyListOutputBuffer, szProxyListOutputBufferA); #endif StrCpyN(pPxy->lpi->szProxy, szProxyListOutputBuffer, MAX_URL_STRING); // // Now Write out the Proxy Exception List // (list of addresses to use for local connections) // szProxyListOutputBuffer[0] = '\0'; GetDlgItemText(hDlg, IDC_PROXY_OVERRIDE, szProxyListOutputBuffer, ARRAY_ELEMENTS(szProxyListOutputBuffer)); StrCpyN(pPxy->lpi->szOverride, szProxyListOutputBuffer, MAX_URL_STRING); } else { AssertMsg(0, TEXT("Couldn't save settings to registry!")); } // let any active (participating) wininet's get notified // InternetSetOption(NULL, INTERNET_OPTION_SETTINGS_CHANGED, NULL, 0); return TRUE; } INTERNET_SCHEME MapUrlSchemeName( IN LPSTR lpszSchemeName, IN DWORD dwSchemeNameLength ) /*++ Routine Description: Maps a scheme name/length to a scheme name type Arguments: lpszSchemeName - pointer to name of scheme to map dwSchemeNameLength - length of scheme (if -1, lpszSchemeName is ASCIZ) Return Value: INTERNET_SCHEME --*/ { if (dwSchemeNameLength == (DWORD)-1) { dwSchemeNameLength = (DWORD)lstrlenA(lpszSchemeName); } for (int i = 0; i < ARRAY_ELEMENTS(UrlSchemeList); ++i) { if (UrlSchemeList[i].SchemeLength == dwSchemeNameLength) { CHAR chBackup = lpszSchemeName[dwSchemeNameLength]; lpszSchemeName[dwSchemeNameLength] = '\0'; if(StrCmpIA(UrlSchemeList[i].SchemeName,lpszSchemeName) == 0) { lpszSchemeName[dwSchemeNameLength] = chBackup; return UrlSchemeList[i].SchemeType; } lpszSchemeName[dwSchemeNameLength] = chBackup; } } return INTERNET_SCHEME_UNKNOWN; } DWORD MapUrlSchemeTypeToCtlId( IN INTERNET_SCHEME SchemeType, IN BOOL fIdForPortCtl ) /*++ Routine Description: Maps a scheme to a dlg child control id. Arguments: Scheme - Scheme to Map fIdForPortCtl - If TRUE, means we really want the ID for a the PORT control not the ADDRESS control. Return Value: DWORD --*/ { for (int i = 0; i < ARRAY_ELEMENTS(UrlSchemeList); ++i) { if (SchemeType == UrlSchemeList[i].SchemeType) { return (fIdForPortCtl ? UrlSchemeList[i].dwPortControlId : UrlSchemeList[i].dwControlId ); } } return IDC_NOTUSED; } BOOL MapCtlIdUrlSchemeName( IN DWORD dwEditCtlId, OUT LPSTR lpszSchemeOut ) /*++ Routine Description: Maps a dlg child control id to String represnting the name of the scheme. Arguments: dwEditCtlId - Edit Control to Map Out. lpszSchemeOut - Scheme to Map Out. WARNING: ASSUMED to be size of largest scheme type. Return Value: BOOL Success - TRUE Failure - FALSE --*/ { ASSERT(lpszSchemeOut); for (int i = 0; i < ARRAY_ELEMENTS(UrlSchemeList); ++i) { if (dwEditCtlId == UrlSchemeList[i].dwControlId ) { StrCpyA(lpszSchemeOut, UrlSchemeList[i].SchemeName); return TRUE; } } return FALSE; } DWORD MapAddrCtlIdToPortCtlId( IN DWORD dwEditCtlId ) /*++ Routine Description: Maps a dlg child control id for addresses to a dlg control id for ports. Arguments: dwEditCtlId - Edit Control to Map Out. Return Value: DWORD Success - Correctly mapped ID. Failure - 0. --*/ { for (int i = 0; i < ARRAY_ELEMENTS(UrlSchemeList); ++i) { if (dwEditCtlId == UrlSchemeList[i].dwControlId ) { return UrlSchemeList[i].dwPortControlId ; } } return FALSE; } BOOL ProxyDlgInitProxyServers( IN HWND hDlg ) /*++ Routine Description: Parses a list of proxy servers and sets them into the newly created Proxy Dialog. Ruthlessly stolen from RFirth's proxysup.cxx in WININET by ArthurBi. Arguments: hDlg - HWin to add our stuff to. Return Value: BOOL Success - TRUE Failure - FALSE Comments: Designed to handle Proxy string entry of the Form: pointer to list of proxies of the form: [=]["://"][":"][";"*] The list can is read from the registry. --*/ { DWORD error = !ERROR_SUCCESS; DWORD entryLength; LPSTR protocolName; DWORD protocolLength; LPSTR schemeName; DWORD schemeLength; LPSTR serverName; DWORD serverLength; PARSER_STATE state; DWORD nSlashes; INTERNET_PORT port; BOOL done; LPSTR lpszList; entryLength = 0; protocolLength = 0; schemeName = NULL; schemeLength = 0; serverName = NULL; serverLength = 0; state = STATE_PROTOCOL; nSlashes = 0; port = 0; done = FALSE; // // Open the Reg Key. // RegEntry re(REGSTR_PATH_INTERNETSETTINGS,HKEY_CURRENT_USER); if (re.GetError() != ERROR_SUCCESS) return FALSE; // no REG values.. // // Crack the Registry values, read the proxy list // BUFFER bufProxyString(MAX_URL_STRING+1); BOOL fProxyEnabled; if (!bufProxyString) { MsgBox(NULL,IDS_ERROutOfMemory,MB_ICONEXCLAMATION,MB_OK); return FALSE; } // // is proxy enabled? // It should if we got into this dialog. // fProxyEnabled = (BOOL)re.GetNumber(REGSTR_VAL_PROXYENABLE,0); // // get proxy server and override settings from registry and stuff fields // re.GetString(REGSTR_VAL_PROXYSERVER,bufProxyString.QueryPtr(), bufProxyString.QuerySize()); LPPROXYPAGE pPxy = (LPPROXYPAGE)GetWindowLongPtr(hDlg, DWLP_USER); // if there's a proxy passed in from the main page, then use it; otherwise use the registry val #ifndef UNICODE lpszList = pPxy->lpi->szProxy; #else char* szList = NULL; LPTSTR lpTmp = pPxy->lpi->szProxy; DWORD cch = lstrlen(lpTmp) + 1; szList = new char[2 * cch]; if (szList) { SHUnicodeToAnsi(lpTmp, szList, 2 * cch); lpszList = szList; } else { MsgBox(NULL,IDS_ERROutOfMemory,MB_ICONEXCLAMATION,MB_OK); return FALSE; } #endif protocolName = lpszList; // // walk the list, pulling out the various scheme parts // do { char ch = *lpszList++; if ((nSlashes == 1) && (ch != '/')) { state = STATE_ERROR; break; } switch (ch) { case '=': if ((state == STATE_PROTOCOL) && (entryLength != 0)) { protocolLength = entryLength; entryLength = 0; state = STATE_SCHEME; schemeName = lpszList; } else { // // '=' can't legally appear anywhere else // state = STATE_ERROR; } break; case ':': switch (state) { case STATE_PROTOCOL: if (*lpszList == '/') { schemeName = protocolName; protocolName = NULL; schemeLength = entryLength; protocolLength = 0; state = STATE_SCHEME; } else if (*lpszList != '\0') { serverName = protocolName; serverLength = entryLength; state = STATE_PORT; } else { state = STATE_ERROR; } entryLength = 0; break; case STATE_SCHEME: if (*lpszList == '/') { schemeLength = entryLength; } else if (*lpszList != '\0') { serverName = schemeName; serverLength = entryLength; state = STATE_PORT; } else { state = STATE_ERROR; } entryLength = 0; break; case STATE_SERVER: serverLength = entryLength; state = STATE_PORT; entryLength = 0; break; default: state = STATE_ERROR; break; } break; case '/': if ((state == STATE_SCHEME) && (nSlashes < 2) && (entryLength == 0)) { if (++nSlashes == 2) { state = STATE_SERVER; serverName = lpszList; } } else { state = STATE_ERROR; } break; case '\v': // vertical tab, 0x0b case '\f': // form feed, 0x0c if (!((state == STATE_PROTOCOL) && (entryLength == 0))) { // // can't have embedded whitespace // state = STATE_ERROR; } break; default: if (state != STATE_PORT) { ++entryLength; } else if (isdigit(ch)) { // // we will overflow if >65535 // Assert(port < 65535); port = port * 10 + (ch - '0'); } else { // // STATE_PORT && non-digit character - error // state = STATE_ERROR; } break; case '\0': done = TRUE; // // fall through // case ' ': case '\t': case '\n': case '\r': case ';': case ',': if (serverLength == 0) { serverLength = entryLength; } if (serverLength != 0) { if (serverName == NULL) { serverName = (schemeName != NULL) ? schemeName : protocolName; } ASSERT(serverName != NULL); INTERNET_SCHEME protocol; if (protocolLength != 0) { protocol = MapUrlSchemeName(protocolName, protocolLength); } else { protocol = INTERNET_SCHEME_DEFAULT; } INTERNET_SCHEME scheme; if (schemeLength != 0) { scheme = MapUrlSchemeName(schemeName, schemeLength); } else { scheme = INTERNET_SCHEME_DEFAULT; } // // add an entry if this is a protocol we handle and we don't // already have an entry for it // if ((protocol != INTERNET_SCHEME_UNKNOWN) && (scheme != INTERNET_SCHEME_UNKNOWN)) { DWORD dwCtlId = IDC_NOTUSED; DWORD dwPortCtlId = IDC_NOTUSED; CHAR chBackup; error = ERROR_SUCCESS; // // we can only currently handle CERN proxies (unsecure or // secure) so kick out anything that wants to go via a different // proxy scheme // if (protocol == INTERNET_SCHEME_DEFAULT) { CheckDlgButton( hDlg, IDC_PROXY_USE_SAME_SERVER, TRUE ); dwCtlId = IDC_PROXY_HTTP_ADDRESS; dwPortCtlId = IDC_PROXY_HTTP_PORT; } else { dwCtlId = MapUrlSchemeTypeToCtlId(protocol,FALSE); dwPortCtlId = MapUrlSchemeTypeToCtlId(protocol,TRUE); } // // Set the Field Entry. // LPSTR lpszProxyNameText; if (scheme != INTERNET_SCHEME_DEFAULT) { ASSERT(schemeLength != 0); lpszProxyNameText = schemeName; } else lpszProxyNameText = serverName; chBackup = serverName[serverLength]; serverName[serverLength] = '\0'; SetDlgItemTextA( hDlg, dwCtlId, lpszProxyNameText ); if ( port ) SetDlgItemInt( hDlg, dwPortCtlId, port, FALSE ); serverName[serverLength] = chBackup; } else { // // bad/unrecognised protocol or scheme. Treat it as error // for now // error = !ERROR_SUCCESS; } } entryLength = 0; protocolName = lpszList; protocolLength = 0; schemeName = NULL; schemeLength = 0; serverName = NULL; serverLength = 0; nSlashes = 0; port = 0; if (error == ERROR_SUCCESS) { state = STATE_PROTOCOL; } else { state = STATE_ERROR; } break; } if (state == STATE_ERROR) { break; } } while (!done); #ifdef UNICODE delete [] szList; #endif if (state == STATE_ERROR) { error = ERROR_INVALID_PARAMETER; } if ( error == ERROR_SUCCESS ) error = TRUE; else error = FALSE; return error; } BOOL IsProxyValid( IN HWND hDlg ) /*++ Routine Description: Determines if the Proxy is valid. The proxy is invalid if all of the proxy entries are empty. Arguments: hDlg - HWIN of the dialog to play with. Return Value: BOOL Success TRUE - Valid. FALSE - Invalid. --*/ { BOOL fProxyIsValid = FALSE; TCHAR szProxyUrl[MAX_URL_STRING+1]; int iCurrentProxy = 0; ASSERT(IsWindow(hDlg)); for (int iIndex = 0; iIndex < ARRAYSIZE(g_iProxies); iIndex++) { szProxyUrl[0] = '\0'; GetDlgItemText(hDlg, g_iProxies[iIndex], szProxyUrl, sizeof(szProxyUrl)); if (szProxyUrl[0]) { fProxyIsValid = TRUE; break; } } return fProxyIsValid; } BOOL ParseEditCtlForPort( IN OUT LPSTR lpszProxyName, IN HWND hDlg, IN DWORD dwProxyNameCtlId, IN DWORD dwProxyPortCtlId ) /*++ Routine Description: Parses a Port Number off then end of a Proxy Server URL that is located either in the Proxy Name Edit Box, or passed in as a string pointer. Arguments: lpszProxyName - (OPTIONAL) string pointer with Proxy Name to parse, and set into the Proxy Name edit ctl field. hDlg - HWIN of the dialog to play with. dwProxyNameCtlId - Res Ctl Id to play with. dwProxyPortCtlId - Res Ctl Id of Port Number Edit Box. Return Value: BOOL Success TRUE - Failure FALSE --*/ { CHAR szProxyUrl[MAX_URL_STRING+1]; LPSTR lpszPort; LPSTR lpszProxyUrl; ASSERT(IsWindow(hDlg)); if ( dwProxyPortCtlId == 0 ) { dwProxyPortCtlId = MapAddrCtlIdToPortCtlId(dwProxyNameCtlId); ASSERT(dwProxyPortCtlId); } // // Get the Proxy String from the Edit Control // (OR) from the Registry [passed in] // if ( lpszProxyName ) lpszProxyUrl = lpszProxyName; else { // // Need to Grab it out of the edit control. // GetDlgItemTextA(hDlg, dwProxyNameCtlId, szProxyUrl, sizeof(szProxyUrl)); lpszProxyUrl = szProxyUrl; } // // Now find the port. // lpszPort = lpszProxyUrl; GET_TERMINATOR(lpszPort); lpszPort--; // // Walk backwards from the end of url looking // for a port number sitting on the end like this // http://proxy:1234 // while ( (lpszPort > lpszProxyUrl) && (*lpszPort != ':') && (isdigit(*lpszPort)) ) { lpszPort--; } // // If we found a match for our rules // then set the port, otherwise // we assume the user knows what he's // doing. // if ( *lpszPort == ':' && isdigit(*(lpszPort+1)) ) { *lpszPort = '\0'; SetDlgItemTextA(hDlg, dwProxyPortCtlId, (lpszPort+1)); } SetDlgItemTextA(hDlg, dwProxyNameCtlId, lpszProxyUrl); return TRUE; } BOOL FormatOutProxyEditCtl( IN HWND hDlg, IN DWORD dwProxyNameCtlId, IN DWORD dwProxyPortCtlId, OUT LPSTR lpszOutputStr, IN OUT LPDWORD lpdwOutputStrSize, IN DWORD dwOutputStrLength, IN BOOL fDefaultProxy ) /*++ Routine Description: Combines Proxy URL components into a string that can be saved in the registry. Can be called multiple times to build a list of proxy servers, or once to special case a "default" proxy. Arguments: hDlg - HWIN of the dialog to play with. dwProxyNameCtlId - Res Ctl Id to play with. dwProxyPortCtlId - Res Ctl Id of Port Number Edit Box. lpszOutputStr - The start of the output string to send the product of this function. lpdwOutputStrSize - The amount of used space in lpszOutputStr that is already used. New output should start from (lpszOutputStr + *lpdwOutputStrSize) fDefaultProxy - Default Proxy, don't add scheme= in front of the proxy just use plop one proxy into the registry. Return Value: BOOL Success TRUE Failure FALSE --*/ { LPSTR lpszOutput; LPSTR lpszEndOfOutputStr; ASSERT(IsWindow(hDlg)); ASSERT(lpdwOutputStrSize); lpszOutput = lpszOutputStr + *lpdwOutputStrSize; lpszEndOfOutputStr = lpszOutputStr + dwOutputStrLength; ASSERT( lpszEndOfOutputStr > lpszOutput ); if ( lpszEndOfOutputStr <= lpszOutput ) return FALSE; // bail out, ran out of space // // Plop ';' if we're not the first in this string buffer. // if (*lpdwOutputStrSize != 0 ) { *lpszOutput = ';'; lpszOutput++; if ( lpszEndOfOutputStr <= lpszOutput ) return FALSE; // bail out, ran out of space } // // Put the schemetype= into the string // ex: http= // if ( ! fDefaultProxy ) { if ( lpszEndOfOutputStr <= (MAX_SCHEME_NAME_LENGTH + lpszOutput + 1) ) return FALSE; // bail out, ran out of space if (!MapCtlIdUrlSchemeName(dwProxyNameCtlId,lpszOutput)) return FALSE; lpszOutput += lstrlenA(lpszOutput); *lpszOutput = '='; lpszOutput++; } // // Need to Grab ProxyUrl out of the edit control. // GetDlgItemTextA(hDlg, dwProxyNameCtlId, lpszOutput, (int)(lpszEndOfOutputStr - lpszOutput)); if ( IS_BLANK(lpszOutput) ) return FALSE; // // Now seperate out the port so we can save them seperately. // But go past the Proxy Url while we're at it. // ex: http=http://netscape-proxy // if (!ParseEditCtlForPort(lpszOutput, hDlg, dwProxyNameCtlId, dwProxyPortCtlId)) return FALSE; lpszOutput += lstrlenA(lpszOutput); // // Now, add in a ':" for the port number, if we don't // have a port we'll remove it. // { *lpszOutput = ':'; lpszOutput++; if ( lpszEndOfOutputStr <= lpszOutput ) return FALSE; // bail out, ran out of space } // // Grab Proxy Port if its around. // Back out the ':' if its not. // GetDlgItemTextA(hDlg, dwProxyPortCtlId,lpszOutput, (int)(lpszEndOfOutputStr - lpszOutput)); if ( IS_BLANK(lpszOutput) ) { lpszOutput--; ASSERT(*lpszOutput == ':'); *lpszOutput = '\0'; } lpszOutput += lstrlenA(lpszOutput); // // Now we're done return our final sizes. // *lpdwOutputStrSize = (DWORD)(lpszOutput - lpszOutputStr); return TRUE; } BOOL RemoveLocalFromExceptionList( IN LPTSTR lpszExceptionList ) /*++ Routine Description: Scans a delimited list of entries, and removed " if found. If is found we return TRUE. Arguments: lpszExceptionList - String List of proxy excepion entries. Return Value: BOOL TRUE - If found FALSE - If local was not found. --*/ { LPTSTR lpszLocalInstToRemove; BOOL fFoundLocal; if ( !lpszExceptionList || ! *lpszExceptionList ) return FALSE; fFoundLocal = FALSE; lpszLocalInstToRemove = lpszExceptionList; // // Loop looking "" entries in the list. // do { lpszLocalInstToRemove = StrStrI(lpszLocalInstToRemove,cszLocalString); if ( lpszLocalInstToRemove ) { fFoundLocal = TRUE; // // Nuke out of the string. ;otherstuff\0 // Dest is: '<'local>;otherstuff\0 // ??? (OR) ';' if the ; is the first character.??? // Src is: >'o'therstuff\0 // size is: sizeof(';otherstuff\0') // MoveMemory( lpszLocalInstToRemove, (lpszLocalInstToRemove+lstrlen(cszLocalString)), lstrlen(lpszLocalInstToRemove+lstrlen(cszLocalString))*sizeof(TCHAR)+sizeof(TCHAR) ); } } while (lpszLocalInstToRemove && *lpszLocalInstToRemove); // // If we produced a ; on the end, nuke it. // lpszLocalInstToRemove = lpszExceptionList; GET_TERMINATOR(lpszLocalInstToRemove); if ( lpszLocalInstToRemove != lpszExceptionList && *(lpszLocalInstToRemove-1) == ';' ) { *(lpszLocalInstToRemove-1) = '\0'; } return fFoundLocal; }