/*++ Copyright (c) 1996 Microsoft Corporation Module Name: util.c Abstract: Misc. utility functions used by the fax configuration applet Environment: Fax configuration applet Revision History: 03/13/96 -davidx- Created it. mm/dd/yy -author- description --*/ #include "faxcpl.h" #include "forms.h" #include "cfghelp.h" #include #include #include // // A flag to indicate whether we're inside SetDlgItemText call. // This is a kluge but we have no other way of telling whether // an EN_CHANGE message is caused by user action or by us calling // SetDlgItemText. // BOOL insideSetDlgItemText = FALSE; VOID SetChangedFlag( HWND hDlg, INT pageIndex, BOOL changed ) /*++ Routine Description: Enable or disable the Apply button in the property sheet depending on if any of the dialog contents was changed Arguments: hDlg - Handle to the property page window pageIndex - Specifies the index of current property page changed - Specifies whether the Apply button should be enabled Return Value: NONE --*/ { HWND hwndPropSheet; INT pageMask = (1 << pageIndex); // // Enable or disable the Apply button as appropriate // hwndPropSheet = GetParent(hDlg); if (changed) { PropSheet_Changed(hwndPropSheet, hDlg); gConfigData->changeFlag |= pageMask; } else { gConfigData->changeFlag &= ~pageMask; if (gConfigData->changeFlag == 0) { PropSheet_UnChanged(hwndPropSheet, hDlg); } } } BOOL GetMapiProfiles( VOID ) /*++ Routine Description: Connect to the server and get its MAPI profiles. Arguments: NONE Return Value: TRUE if successful, FALSE if not --*/ { if (gConfigData->pMapiProfiles) return TRUE; if (!FaxGetMapiProfiles(gConfigData->hFaxSvc, (LPBYTE*) &gConfigData->pMapiProfiles)) { gConfigData->pMapiProfiles = NULL; Error(("Cannot retrieve MapiProfiles: %d\n", GetLastError())); return FALSE; } return TRUE; } PVOID MyEnumPrinters( LPTSTR pServerName, DWORD level, PDWORD pcPrinters, DWORD dwFlags ) /*++ Routine Description: Wrapper function for spooler API EnumPrinters Arguments: pServerName - Specifies the name of the print server level - Level of PRINTER_INFO_x structure pcPrinters - Returns the number of printers enumerated dwFlags - Flag bits passed to EnumPrinters Return Value: Pointer to an array of PRINTER_INFO_x structures NULL if there is an error --*/ { PBYTE pPrinterInfo = NULL; DWORD cb; if (! EnumPrinters(dwFlags, pServerName, level, NULL, 0, &cb, pcPrinters) && GetLastError() == ERROR_INSUFFICIENT_BUFFER && (pPrinterInfo = MemAlloc(cb)) && EnumPrinters(dwFlags, pServerName, level, pPrinterInfo, cb, &cb, pcPrinters)) { return pPrinterInfo; } Error(("EnumPrinters failed: %d\n", GetLastError())); MemFree(pPrinterInfo); return NULL; } LPTSTR MakePortNameString( VOID ) /*++ Routine Description: Compose a port name string consisting of all available fax devices Arguments: NONE Return Value: Pointer to a list of comma-separated port names NULL if there is an error --*/ { LPTSTR pPortName, p; INT index, cb; // // Connect to the fax service and retrieve the list of fax devices // GetFaxDeviceAndConfigInfo(); // // Figure out the total size of port name string // for (index=cb=0; index < gConfigData->cDevices; index++) cb += SizeOfString(gConfigData->pDevInfo[index].DeviceName); if (cb == 0 || !(p = pPortName = MemAlloc(cb))) return NULL; // // Compose the port name string // for (index=0; index < gConfigData->cDevices; index++) { if (p != pPortName) *p++ = PORTNAME_SEPARATOR; _tcscpy(p, gConfigData->pDevInfo[index].DeviceName); p += _tcslen(p); } return pPortName; } BOOL CheckFaxServerType( HWND hDlg, LPTSTR pPrinterName ) /*++ Routine Description: Make sure the print server has fax server software installed Arguments: hDlg - Handle to the currently active property page pPrinterName - Specifies the name of the shared printer Return Value: TRUE if the fax server software is installed FALSE otherwise --*/ { HANDLE hServer; LPTSTR p, pNoRemoteDrivers; INT status = 0; // // Derived the server name from the share name // Assert(_tcsncmp(pPrinterName, TEXT("\\\\"), 2) == EQUAL_STRING); p = pPrinterName + 2; if (p = _tcschr(p, TEXT(PATH_SEPARATOR))) { *p = NUL; if (OpenPrinter(pPrinterName, &hServer, NULL)) { if (pNoRemoteDrivers = GetPrinterDataStr(hServer, SPLREG_NO_REMOTE_PRINTER_DRIVERS)) { if (_tcsstr(pNoRemoteDrivers, DRIVER_NAME) != NULL) status = IDS_NO_FAXSERVER; MemFree(pNoRemoteDrivers); } ClosePrinter(hServer); } else status = IDS_SERVER_NOTALIVE; *p = TEXT(PATH_SEPARATOR); } else status = IDS_INVALID_SHARENAME; if (status != 0) DisplayMessageDialog(hDlg, 0, 0, status); return (status == 0); } PVOID FaxSvcEnumPorts( HANDLE hFaxSvc, PDWORD pcPorts ) /*++ Routine Description: Wrapper function for fax service API FaxEnumPorts Arguments: hFaxSvc - Specifies a coneection handle to the fax service DWORD - Specifies the level of FAX_PORT_INFO structure desired pcPorts - Returns the number of devices managed by the fax service Return Value: Pointer to an array of FAX_PORT_INFO_x structures NULL if there is an error --*/ { PVOID pSvcPortInfo = NULL; if (!FaxEnumPorts(hFaxSvc, (PFAX_PORT_INFO*) &pSvcPortInfo, pcPorts)) { Error(("FaxEnumPorts failed: %d\n", GetLastError())); return NULL; } return pSvcPortInfo; } BOOL GetFaxDeviceAndConfigInfo( VOID ) /*++ Routine Description: Get a list of fax devices available on the system and retrieve fax configuration information from the service Arguments: NONE Return Value: TRUE if successful, FALSE if there is an error --*/ { PFAX_PORT_INFO pSvcPortInfo; PFAX_PORT_INFO pSvcPort; PCONFIG_PORT_INFO_2 pDevInfo; DWORD index; DWORD cPorts; DWORD cb; HANDLE FaxPortHandle; LPBYTE RoutingInfo; Verbose(("Enumerating fax ports ...\n")); Assert(ValidConfigData(gConfigData)); if (gConfigData->pDevInfo) return TRUE; // // Allocate memory to hold information about fax devices // Assert(gConfigData->hFaxSvc != NULL); Assert(gConfigData->cDevices == 0); if (! (pSvcPortInfo = FaxSvcEnumPorts(gConfigData->hFaxSvc, &cPorts)) || ! (gConfigData->pDevInfo = pDevInfo = MemAllocZ(sizeof(CONFIG_PORT_INFO_2) * cPorts))) { FaxFreeBuffer(pSvcPortInfo); return FALSE; } // // Collect information about each fax device. Here we're depending on the fact that // fax devices are enumerated in reverse priority order, i.e. the lowest priority // device is enumerated first. // Verbose(("Available fax devices:\n")); for (index=0; index < cPorts; index++, pDevInfo++) { pSvcPort = &pSvcPortInfo[cPorts - index - 1]; Verbose(( " %ws\n", pSvcPort->DeviceName )); pDevInfo->SizeOfStruct = pSvcPort->SizeOfStruct; pDevInfo->DeviceId = pSvcPort->DeviceId; pDevInfo->State = pSvcPort->State; pDevInfo->Flags = pSvcPort->Flags; pDevInfo->Rings = pSvcPort->Rings; pDevInfo->Priority = pSvcPort->Priority; pDevInfo->DeviceName = DuplicateString( pSvcPort->DeviceName ); pDevInfo->CSID = DuplicateString( pSvcPort->Csid); pDevInfo->TSID = DuplicateString( pSvcPort->Tsid); pDevInfo->Mask = 0; pDevInfo->ProfileName = NULL; pDevInfo->PrinterName = NULL; pDevInfo->DirStore = NULL; // // open the fax port for query so we can get the routing info // if (FaxOpenPort(gConfigData->hFaxSvc, pDevInfo->DeviceId, PORT_OPEN_QUERY, &FaxPortHandle )) { // // get the store dir // if (FaxGetRoutingInfo( FaxPortHandle, REGVAL_RM_FOLDER_GUID, &RoutingInfo, &cb )) { if (*((LPDWORD)RoutingInfo)) { pDevInfo->Mask |= LR_STORE; pDevInfo->DirStore = DuplicateString( (LPWSTR)(RoutingInfo+sizeof(DWORD)) ); } FaxFreeBuffer( RoutingInfo ); } // // get the printer name // if (FaxGetRoutingInfo( FaxPortHandle, REGVAL_RM_PRINTING_GUID, &RoutingInfo, &cb )) { if (*((LPDWORD)RoutingInfo)) { pDevInfo->Mask |= LR_PRINT; pDevInfo->PrinterName = DuplicateString( (LPWSTR)(RoutingInfo+sizeof(DWORD)) ); } FaxFreeBuffer( RoutingInfo ); } // // get the email profile name // if (FaxGetRoutingInfo( FaxPortHandle, REGVAL_RM_EMAIL_GUID, &RoutingInfo, &cb )) { if (*((LPDWORD)RoutingInfo)) { pDevInfo->Mask |= LR_EMAIL; pDevInfo->ProfileName = DuplicateString( (LPWSTR)(RoutingInfo+sizeof(DWORD)) ); } FaxFreeBuffer( RoutingInfo ); } // // get the inbox profile name // if (FaxGetRoutingInfo( FaxPortHandle, REGVAL_RM_INBOX_GUID, &RoutingInfo, &cb )) { if (*((LPDWORD)RoutingInfo)) { pDevInfo->Mask |= LR_INBOX; MemFree( pDevInfo->ProfileName ); pDevInfo->ProfileName = DuplicateString( (LPWSTR)(RoutingInfo+sizeof(DWORD)) ); } FaxFreeBuffer( RoutingInfo ); } FaxClose( FaxPortHandle ); } gConfigData->cDevices++; } // // Retrieve fax configuration information from the service // Assert( gConfigData->pFaxConfig == NULL ); if (!FaxGetConfiguration(gConfigData->hFaxSvc, &gConfigData->pFaxConfig)) { Error(("Cannot retrieve fax configuration information: %d\n", GetLastError())); gConfigData->pFaxConfig = NULL; } // // Retrieve the logging categories // Assert( gConfigData->pFaxLogging == NULL ); if (!FaxGetLoggingCategories( gConfigData->hFaxSvc, &gConfigData->pFaxLogging, &gConfigData->NumberCategories )) { Error(("Cannot retrieve fax logging category information: %d\n", GetLastError())); gConfigData->pFaxLogging = NULL; } } BOOL SaveFaxDeviceAndConfigInfo( HWND hDlg, INT pageIndex ) /*++ Routine Description: Save fax device and configuration information Arguments: hDlg - Handle to the currently active property page pageIndex - Specifies the currently active page index Return Value: TRUE if successful, FALSE if there is an error --*/ #define FAIL_SAVE_FAX_CONFIG(err) { errorId = err; goto ExitSaveFaxConfig; } { PCONFIG_PORT_INFO_2 pDevInfo; FAX_PORT_INFO SvcPort; DWORD ec; INT index = 0; INT errorId = 0; DWORD cb; // // Check if we're on the last page that has settable fax configuration info // if ((gConfigData->changeFlag & CONFIGPAGE_MASK) != (1 << pageIndex)) { return TRUE; } if (gConfigData->hFaxSvc == NULL) { FAIL_SAVE_FAX_CONFIG(IDS_NULL_SERVICE_HANDLE); } // // Save fax configuration information // if (gConfigData->pFaxConfig && ! FaxSetConfiguration(gConfigData->hFaxSvc, gConfigData->pFaxConfig)) { ec = GetLastError(); Error(("FaxSetConfiguration failed: %d\n", ec)); FAIL_SAVE_FAX_CONFIG((ec == ERROR_ACCESS_DENIED ? IDS_NO_AUTHORITY : IDS_FAXSETCONFIG_FAILED)); } // // Save fax device information // NOTE: Here, we're calling FaxSetPort on every device which may be // a little redundant. But it shouldn't hurt anything. // pDevInfo = gConfigData->pDevInfo; for (index=0; index < gConfigData->cDevices; index++, pDevInfo++) { HANDLE FaxPortHandle; LPBYTE RoutingInfo; if (!FaxOpenPort(gConfigData->hFaxSvc, pDevInfo->DeviceId, PORT_OPEN_MODIFY, &FaxPortHandle )) { DisplayMessageDialog(hDlg, 0, 0, IDS_DEVICE_BUSY, pDevInfo->DeviceName); return FALSE; } SvcPort.SizeOfStruct = pDevInfo->SizeOfStruct; SvcPort.DeviceId = pDevInfo->DeviceId; SvcPort.State = pDevInfo->State; SvcPort.Flags = pDevInfo->Flags; SvcPort.Rings = pDevInfo->Rings; SvcPort.Priority = pDevInfo->Priority; SvcPort.DeviceName = pDevInfo->DeviceName; SvcPort.Tsid = pDevInfo->TSID; SvcPort.Csid = pDevInfo->CSID; if (! FaxSetPort(FaxPortHandle, &SvcPort)) { ec = GetLastError(); Error(("FaxSetPort failed: %d\n", ec)); FAIL_SAVE_FAX_CONFIG((ec == ERROR_ACCESS_DENIED ? IDS_NO_AUTHORITY : IDS_FAXSETPORT_FAILED)); } // // change the routing information // cb = 4096; RoutingInfo = (LPBYTE) MemAllocZ( cb ); if (!RoutingInfo) { Error(("Memory allocation failed: %d\n", GetLastError())); goto ExitSaveFaxConfig; } // // set the store dir // *((LPDWORD)RoutingInfo) = (pDevInfo->Mask & LR_STORE) > 0; if (pDevInfo->Mask & LR_STORE) { _tcscpy( (LPTSTR) (RoutingInfo+sizeof(DWORD)), pDevInfo->DirStore ); } if (!FaxSetRoutingInfo( FaxPortHandle, REGVAL_RM_FOLDER_GUID, RoutingInfo, cb )) { Error(("FaxSetRoutingInfo failed: %d\n", GetLastError())); } // // set the printer name // *((LPDWORD)RoutingInfo) = (pDevInfo->Mask & LR_PRINT) > 0; if (pDevInfo->Mask & LR_PRINT) { _tcscpy( (LPTSTR) (RoutingInfo+sizeof(DWORD)), pDevInfo->PrinterName ? pDevInfo->PrinterName : TEXT("") ); } if (!FaxSetRoutingInfo( FaxPortHandle, REGVAL_RM_PRINTING_GUID, RoutingInfo, cb )) { Error(("FaxSetRoutingInfo failed: %d\n", GetLastError())); } // // set the email profile name // *((LPDWORD)RoutingInfo) = (pDevInfo->Mask & LR_EMAIL) > 0; if (pDevInfo->Mask & LR_EMAIL) { _tcscpy( (LPTSTR) (RoutingInfo+sizeof(DWORD)), pDevInfo->ProfileName ? pDevInfo->ProfileName : TEXT("") ); } if (!FaxSetRoutingInfo( FaxPortHandle, REGVAL_RM_EMAIL_GUID, RoutingInfo, cb )) { Error(("FaxSetRoutingInfo failed: %d\n", GetLastError())); } // // set the inbox profile name // *((LPDWORD)RoutingInfo) = (pDevInfo->Mask & LR_INBOX) > 0; if (pDevInfo->Mask & LR_INBOX) { _tcscpy( (LPTSTR) (RoutingInfo+sizeof(DWORD)), pDevInfo->ProfileName ? pDevInfo->ProfileName : TEXT("") ); } if (!FaxSetRoutingInfo( FaxPortHandle, REGVAL_RM_INBOX_GUID, RoutingInfo, cb )) { Error(("FaxSetRoutingInfo failed: %d\n", GetLastError())); } MemFree( RoutingInfo ); FaxClose( FaxPortHandle ); } // // save the logging categories // if (!FaxSetLoggingCategories( gConfigData->hFaxSvc, gConfigData->pFaxLogging, gConfigData->NumberCategories )) { Error(("Cannot change fax logging category information: %d\n", GetLastError())); } ExitSaveFaxConfig: // // If an error was encountered, display a message box and return FALSE. // Otherwise, return TRUE to indicate success. // if (errorId != 0) { DisplayMessageDialog(hDlg, 0, 0, errorId); return FALSE; } if (gConfigData->priorityChanged) { DisplayMessageDialog(hDlg, MB_OK | MB_ICONINFORMATION, IDS_PRIORITY_CHANGE_TITLE, IDS_PRIORITY_CHANGE_MESSAGE); gConfigData->priorityChanged = FALSE; } return TRUE; } VOID FreeFaxDeviceAndConfigInfo( VOID ) /*++ Routine Description: Dispose of fax device and configuration information Arguments: NONE Return Value: NONE --*/ { PCONFIG_PORT_INFO_2 pDevInfo = gConfigData->pDevInfo; while (gConfigData->cDevices > 0) { MemFree(pDevInfo->DeviceName); MemFree(pDevInfo->TSID); MemFree(pDevInfo->PrinterName); MemFree(pDevInfo->DirStore); MemFree(pDevInfo->ProfileName); MemFree(pDevInfo->CSID); gConfigData->cDevices--; pDevInfo++; } MemFree(gConfigData->pDevInfo); gConfigData->pDevInfo = NULL; gConfigData->cDevices = 0; FaxFreeBuffer(gConfigData->pFaxConfig); gConfigData->pFaxConfig = NULL; FaxFreeBuffer(gConfigData->pMapiProfiles); gConfigData->pMapiProfiles = NULL; } LPTSTR DuplicateString( LPCTSTR pSrcStr ) /*++ Routine Description: Make a duplicate of the specified character string Arguments: pSrcStr - Specifies the source string to be duplicated Return Value: Pointer to the duplicated string, NULL if there is an error --*/ { LPTSTR pDestStr; INT size; if (pSrcStr == NULL) return NULL; size = SizeOfString(pSrcStr); if (pDestStr = MemAlloc(size)) CopyMemory(pDestStr, pSrcStr, size); else Error(("Couldn't duplicate string: %ws\n", pSrcStr)); return pDestStr; } VOID EnableControls( HWND hDlg, INT *pCtrlIds, BOOL enabled ) /*++ Routine Description: Enable or disable a set of controls in a dialog Arguments: hwnd - Specifies the handle to the dialog window pCtrlIds - Array of control IDs to be enabled or disabled (0 terminated) enabled - Whether to enable or disable the specified controls Return Value: NONE --*/ { while (*pCtrlIds) { EnableWindow(GetDlgItem(hDlg, *pCtrlIds), enabled); pCtrlIds++; } } VOID ShowControls( HWND hDlg, INT *pCtrlIds, BOOL visible ) /*++ Routine Description: Show or hide a set of controls in a dialog Arguments: hwnd - Specifies the handle to the dialog window pCtrlIds - Array of control IDs to be shown or hidden (0 terminated) visible - Whether to show or hide the specified controls Return Value: NONE --*/ { INT nCmdShow = visible ? SW_SHOW : SW_HIDE; while (*pCtrlIds) { ShowWindow(GetDlgItem(hDlg, *pCtrlIds), nCmdShow); pCtrlIds++; } } VOID LimitTextFields( HWND hDlg, INT *pLimitInfo ) /*++ Routine Description: Limit the maximum length for a number of text fields Arguments: hDlg - Specifies the handle to the dialog window pLimitInfo - Array of text field control IDs and their maximum length ID for the 1st text field, maximum length for the 1st text field ID for the 2nd text field, maximum length for the 2nd text field ... 0 Note: The maximum length counts the NUL-terminator. Return Value: NONE --*/ { while (*pLimitInfo != 0) { SendDlgItemMessage(hDlg, pLimitInfo[0], EM_SETLIMITTEXT, pLimitInfo[1]-1, 0); pLimitInfo += 2; } } INT DisplayMessageDialog( HWND hwndParent, UINT type, INT titleStrId, INT formatStrId, ... ) /*++ Routine Description: Display a message dialog box Arguments: hwndParent - Specifies a parent window for the error message dialog type - Specifies the type of message box to be displayed titleStrId - Title string (could be a string resource ID) formatStrId - Message format string (could be a string resource ID) ... Return Value: Same as the return value from MessageBox --*/ { LPTSTR pTitle, pFormat, pMessage; INT result; va_list ap; pTitle = pFormat = pMessage = NULL; if ((pTitle = AllocStringZ(MAX_TITLE_LEN)) && (pFormat = AllocStringZ(MAX_STRING_LEN)) && (pMessage = AllocStringZ(MAX_MESSAGE_LEN))) { // // Load dialog box title string resource // if (titleStrId == 0) titleStrId = IDS_ERROR_DLGTITLE; LoadString(ghInstance, titleStrId, pTitle, MAX_TITLE_LEN); // // Load message format string resource // LoadString(ghInstance, formatStrId, pFormat, MAX_STRING_LEN); // // Compose the message string // va_start(ap, formatStrId); wvsprintf(pMessage, pFormat, ap); va_end(ap); // // Display the message box // if (type == 0) type = MB_OK | MB_ICONERROR; result = MessageBox(hwndParent, pMessage, pTitle, type); } else { MessageBeep(MB_ICONHAND); result = 0; } MemFree(pTitle); MemFree(pFormat); MemFree(pMessage); return result; } VOID ToggleListViewCheckbox( HWND hwndLV, INT index ) /*++ Routine Description: Toggle the checkbox associated with the specified list view item Arguments: hwndLV - Handle to the list view control index - Specifies the index of the interested item Return Value: NONE --*/ { UINT state; if (IsListViewItemChecked(hwndLV, index)) state = UNCHECKED_STATE; else state = CHECKED_STATE; ListView_SetItemState(hwndLV, index, state, LVIS_STATEIMAGEMASK); } VOID InitFaxDeviceListView( HWND hwndLV, DWORD flags, PCOLUMNINFO pColumnInfo ) /*++ Routine Description: Initialize the fax device list view Arguments: hwndLV - Handle to the fax device list view flags - Miscellaneous flag bits pColumnInfo - Specifies columns to be displayed and their relative widths ID for the 1st column, relative width for the 1st column ID for the 2nd column, relative width for the 2nd column ... 0, 0 Return Value: NONE --*/ { // // Column header string resource IDs // static INT columnHeaderIDs[MAX_COLUMNS] = { 0, IDS_DEVICE_NAME_COLUMN, IDS_CSID_COLUMN, IDS_TSID_COLUMN, IDS_STATUS_COLUMN, }; INT index, nColumns, widthDenom, lvWidth; RECT rect; LV_COLUMN lvc; LV_ITEM lvi; TCHAR buffer[MAX_TITLE_LEN]; // // Count the number of columns // if (hwndLV == NULL) return; nColumns = widthDenom = 0; while (pColumnInfo[nColumns].columnId) { widthDenom += pColumnInfo[nColumns].columnWidth; nColumns++; } Assert(nColumns > 0 && nColumns <= MAX_COLUMNS); Assert(pColumnInfo[0].columnId == COLUMN_DEVICE_NAME); lvc.mask = LVCF_TEXT; lvc.pszText = buffer; lvc.cchTextMax = MAX_TITLE_LEN; if (ListView_GetColumn(hwndLV, 0, &lvc) && ! IsEmptyString(buffer)) { // // The columns have already be inserted // ListView_DeleteAllItems(hwndLV); } else { // // This is the first time and the list view is not initialized // Insert the specified columns into the list view // GetClientRect(hwndLV, &rect); lvWidth = rect.right - rect.left; // // Insert a column of check boxes if requested // if (flags & LV_HASCHECKBOX) { HBITMAP hbmp; HIMAGELIST himl; if (hbmp = LoadBitmap(ghInstance, MAKEINTRESOURCE(IDB_CHECKSTATES))) { if (himl = ImageList_Create(16, 16, TRUE, 2, 0)) { ImageList_AddMasked(himl, hbmp, RGB(255, 0, 0)); ListView_SetImageList(hwndLV, himl, LVSIL_STATE); } else Error(("LoadBitmap failed: %d\n", GetLastError())); DeleteObject(hbmp); } else Error(("LoadBitmap failed: %d\n", GetLastError())); } // // Insert list view columns // ZeroMemory(&lvc, sizeof(lvc)); lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; lvc.fmt = LVCFMT_LEFT; lvc.pszText = buffer; for (index=0; index < nColumns; index++) { lvc.cx = lvWidth * pColumnInfo[index].columnWidth / widthDenom; lvc.iSubItem = index; if (index == nColumns-1) lvc.cx -= GetSystemMetrics(SM_CXVSCROLL); LoadString(ghInstance, columnHeaderIDs[pColumnInfo[index].columnId], buffer, MAX_TITLE_LEN); if (ListView_InsertColumn(hwndLV, index, &lvc) == -1) Error(("ListView_InsertColumn failed\n")); } } // // Insert list view items list view content // ZeroMemory(&lvi, sizeof(lvi)); lvi.iSubItem = 0; lvi.mask = LVIF_STATE | LVIF_TEXT; if (flags & LV_HASCHECKBOX) { lvi.state = UNCHECKED_STATE; lvi.stateMask = LVIS_STATEIMAGEMASK; } for (index = 0; index < gConfigData->cDevices; index ++) { // // The first column is always the device name // lvi.iItem = index; lvi.pszText = gConfigData->pDevInfo[index].DeviceName; if (ListView_InsertItem(hwndLV, &lvi) == -1) { Error(("ListView_InsertItem failed\n")); break; } } // // Display the remaining columns // UpdateFaxDeviceListViewColumns(hwndLV, pColumnInfo, 1); // // The initial selection is the first fax device in the list // ListView_SetItemState(hwndLV, 0, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED); } LPTSTR MakeDeviceStatusString( DWORD state ) /*++ Routine Description: Assemble fax device status string Arguments: state - Current state of the fax device Return Value: Pointer to the device status string, NULL if there is an error --*/ { static struct _STATEBITINFO { DWORD bitFlag; INT stringId; } stateBitInfo[] = { FPS_AVAILABLE, IDS_STATUS_AVAILABLE, FPS_UNAVAILABLE, IDS_STATUS_UNAVAILABLE, FPS_SENDING, IDS_STATUS_SENDING, FPS_RECEIVING, IDS_STATUS_RECEIVING, FPS_ABORTING, IDS_STATUS_ABORTING, FPS_ROUTING, IDS_STATUS_ROUTING, FPS_DIALING, IDS_STATUS_DIALING, FPS_COMPLETED, IDS_STATUS_COMPLETED, FPS_HANDLED, IDS_STATUS_HANDLED, FPS_BUSY, IDS_STATUS_BUSY, FPS_NO_ANSWER, IDS_STATUS_NO_ANSWER, FPS_BAD_ADDRESS, IDS_STATUS_BAD_ADDRESS, FPS_NO_DIAL_TONE, IDS_STATUS_NO_DIAL_TONE, FPS_DISCONNECTED, IDS_STATUS_DISCONNECTED, FPS_FATAL_ERROR, IDS_STATUS_FATAL_ERROR, FPS_NOT_FAX_CALL, IDS_STATUS_NOT_FAX_CALL, FPS_CALL_DELAYED, IDS_STATUS_CALL_DELAYED, FPS_CALL_BLACKLISTED, IDS_STATUS_CALL_BLACKLISTED, FPS_INITIALIZING, IDS_STATUS_INITIALIZING, FPS_OFFLINE, IDS_STATUS_OFFLINE, FPS_ANSWERED, IDS_STATUS_ANSWERED }; LPTSTR pBuffer, p; INT index, count, statusLen, separatorLen; BOOL appendSeparator = FALSE; TCHAR separator[MAX_TITLE_LEN]; // // Load the string that's used separated status fields // if (! LoadString(ghInstance, IDS_STATUS_SEPARATOR, separator, MAX_TITLE_LEN)) _tcscpy(separator, TEXT(", ")); separatorLen = _tcslen(separator); // // Calculate how much space we need // count = sizeof(stateBitInfo) / sizeof(struct _STATEBITINFO); for (index=statusLen=0; index < count; index++) { if ((state & stateBitInfo[index].bitFlag) == stateBitInfo[index].bitFlag) { TCHAR buffer[MAX_TITLE_LEN]; INT length; length = LoadString(ghInstance, stateBitInfo[index].stringId, buffer, MAX_TITLE_LEN); if (length == 0) { Error(("LoadString failed: %d\n", GetLastError())); return NULL; } statusLen += (length + separatorLen); } } // // Assemble the status string // if (p = pBuffer = MemAllocZ((statusLen + 1) * sizeof(TCHAR))) { for (index=0; index < count; index++) { if ((state & stateBitInfo[index].bitFlag) == stateBitInfo[index].bitFlag) { if (appendSeparator) { _tcscpy(p, separator); p += separatorLen; appendSeparator = FALSE; } statusLen = LoadString(ghInstance, stateBitInfo[index].stringId, p, MAX_TITLE_LEN); if (statusLen > 0) { p += statusLen; appendSeparator = TRUE; } else Error(("LoadString failed: %d\n", GetLastError())); } } } return pBuffer; } VOID UpdateFaxDeviceListViewColumns( HWND hwndLV, PCOLUMNINFO pColumnInfo, INT startColumn ) /*++ Routine Description: Refresh columns in the fax device list view Arguments: hwndLV - Handle to the fax device list view pColumnInfo - Specifies columns to be redisplayed startColumn - Specifies the first column index Return Value: NONE --*/ { LPTSTR pBuffer, pColumnStr; LV_ITEM lvi; INT item, nItems, column, nColumns; // // Count the number of items in the list view // if ((hwndLV == NULL) || (nItems = ListView_GetItemCount(hwndLV)) < 0 || (nItems > gConfigData->cDevices)) { return; } // // Count the total number of columns // for (nColumns=0; pColumnInfo[nColumns].columnId; nColumns++) NULL; ZeroMemory(&lvi, sizeof(lvi)); lvi.mask = LVIF_TEXT; // // Go through each item in the list view // for (item=0; item < nItems; item++) { PCONFIG_PORT_INFO_2 pDevInfo = gConfigData->pDevInfo + item; lvi.iItem = item; // // Go through each column for every list view item // for (column=startColumn; column < nColumns; column++) { pBuffer = pColumnStr = NULL; switch (pColumnInfo[column].columnId) { case COLUMN_CSID: pColumnStr = pDevInfo->CSID; break; case COLUMN_TSID: pColumnStr = pDevInfo->TSID; break; case COLUMN_STATUS: pBuffer = pColumnStr = MakeDeviceStatusString(pDevInfo->State); break; default: Assert(FALSE); break; } lvi.iSubItem = column; lvi.pszText = pColumnStr ? pColumnStr : TEXT(""); if (! ListView_SetItem(hwndLV, &lvi)) Error(("ListView_SetItem failed\n")); MemFree(pBuffer); } } } INT BrowseCallbackProc( HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData ) /*++ Routine Description: Callback function for SHBrowseForFolder Arguments: hwnd - Handle to the browse dialog box uMsg - Identifying the reason for the callback lParam - Message parameter lpData - Application-defined value given in BROWSEINFO.lParam Return Value: 0 --*/ { if (uMsg == BFFM_INITIALIZED) SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpData); return 0; } BOOL DoBrowseForDirectory( HWND hDlg, INT textFieldId, INT titleStrId ) /*++ Routine Description: Browse for a directory Arguments: hDlg - Specifies the dialog window on which the Browse button is displayed textFieldId - Specifies the text field adjacent to the Browse button titleStrId - Specifies the title to be displayed in the browse window Return Value: TRUE if successful, FALSE if the user presses Cancel --*/ { LPITEMIDLIST pidl; TCHAR buffer[MAX_PATH]; TCHAR title[MAX_TITLE_LEN]; VOID SHFree(LPVOID); BOOL result = FALSE; BROWSEINFO bi = { hDlg, NULL, buffer, title, BIF_RETURNONLYFSDIRS, BrowseCallbackProc, (LPARAM) buffer, }; if (! LoadString(ghInstance, titleStrId, title, MAX_TITLE_LEN)) title[0] = NUL; if (! GetDlgItemText(hDlg, textFieldId, buffer, MAX_PATH)) buffer[0] = NUL; if (pidl = SHBrowseForFolder(&bi)) { if (SHGetPathFromIDList(pidl, buffer)) { if (_tcslen(buffer) > MAX_ARCHIVE_DIR) DisplayMessageDialog(hDlg, 0, 0, IDS_DIR_TOO_LONG); else { MySetDlgItemText(hDlg, textFieldId, buffer); result = TRUE; } } SHFree(pidl); } return result; } BOOL HandleHelpPopup( HWND hDlg, UINT message, UINT wParam, LPARAM lParam, INT pageIndex ) /*++ Routine Description: Handle context-sensitive help in property sheet pages Arguments: hDlg, message, wParam, lParam - Parameters passed to the dialog procedure pageIndex - Specifies the index of the current property sheet page Return Value: TRUE if the message is handle, FALSE otherwise --*/ { static LPDWORD arrayHelpIDs[MAX_PAGES] = { clientOptionsHelpIDs, personalCoverPageHelpIDs, userInfoHelpIDs, serverOptionsHelpIDs, serverCoverPageHelpIDs, sendOptionsHelpIDs, receiveOptionsHelpIDs, devicePriorityHelpIDs, deviceStatusHelpIDs, loggingHelpIDs, NULL, statusMonitorHelpIDs }; Assert(pageIndex >= 0 && pageIndex < MAX_PAGES); if (message == WM_HELP) { WinHelp(((LPHELPINFO) lParam)->hItemHandle, FAXCFG_HELP_FILENAME, HELP_WM_HELP, (DWORD) arrayHelpIDs[pageIndex]); } else { WinHelp((HWND) wParam, FAXCFG_HELP_FILENAME, HELP_CONTEXTMENU, (DWORD) arrayHelpIDs[pageIndex]); } return TRUE; } PFAX_DEVICE_STATUS FaxSvcGetDeviceStatus( HANDLE hFaxSvc, DWORD DeviceId ) /*++ Routine Description: Wrapper function for fax service API FaxGetDeviceStatus Arguments: hFaxSvc - Specifies a coneection handle to the fax service DeviceId - Specifies the ID of the interested device Return Value: Pointer to a FAX_DEVICE_STATUS structure, NULL if there is an error --*/ { PBYTE pFaxStatus = NULL; HANDLE FaxPortHandle = NULL; if ((hFaxSvc == NULL) || FaxOpenPort(hFaxSvc, DeviceId, PORT_OPEN_QUERY, &FaxPortHandle) == FALSE || !FaxGetDeviceStatus(FaxPortHandle, (PFAX_DEVICE_STATUS*)&pFaxStatus)) { Error(("FaxGetDeviceStatus failed: %d\n", GetLastError())); pFaxStatus = NULL; } if (FaxPortHandle) { FaxClose( FaxPortHandle ); } return (PFAX_DEVICE_STATUS) pFaxStatus; }