/*++ Copyright (c) 1996 Microsoft Corporation Module Name: coverpg.c Abstract: Functions for working with cover pages Environment: Windows NT fax driver user interface Revision History: 02/05/96 -davidx- Created it. mm/dd/yy -author- description --*/ #include "faxcpl.h" #include #include #include #define FAXUTIL_DEBUG #define FAXUTIL_MEM #define FAXUTIL_REG #define FAXUTIL_ADAPTIVE #include "faxutil.h" // // Find the filename portion given a filename: // return a pointer to the '.' character if successful // NULL if there is no extension // #define FindFilenameExtension(pFilename) _tcsrchr(pFilename, TEXT(FILENAME_EXT)) VOID AddCoverPagesToList( PCPDATA pCPInfo, HWND hwndList, INT dirIndex ) /*++ Routine Description: Add the cover page files in the specified directory to a list Arguments: pCPInfo - Points to cover page information hwndList - Handle to a list window dirIndex - Cover page directory index Return Value: NONE --*/ { WIN32_FIND_DATA findData; TCHAR filename[MAX_PATH]; HANDLE hFindFile; LPTSTR pDirPath, pFilename, pExtension; INT listIndex, dirLen, fileLen, flags; // // Copy the directory path to a local buffer // flags = dirIndex; pDirPath = pCPInfo->pDirPath[dirIndex]; if (IsEmptyString(pDirPath)) return; if ((dirLen = _tcslen(pDirPath)) >= MAX_PATH - MAX_FILENAME_EXT - 1) { Error(("Directory name too long: %ws\n", pDirPath)); return; } _tcscpy(filename, pDirPath); // // Go through the following loop twice: // Once to add the files with .ncp extension // Again to add the files with .lnk extension // // Don't chase links for server based cover pages // do { // // Generate a specification for the files we're interested in // pFilename = &filename[dirLen]; *pFilename = TEXT('*'); _tcscpy(pFilename+1, (flags & CPFLAG_LINK) ? LNK_FILENAME_EXT : CP_FILENAME_EXT); // // Call FindFirstFile/FindNextFile to enumerate the files // matching our specification // hFindFile = FindFirstFile(filename, &findData); if (hFindFile != INVALID_HANDLE_VALUE) { do { // // Exclude directories and hidden files // if (findData.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_DIRECTORY)) continue; // // Make sure we have enough room to store the full pathname // if ((fileLen = _tcslen(findData.cFileName)) <= MAX_FILENAME_EXT) continue; if (fileLen + dirLen >= MAX_PATH) { Error(("Filename too long: %ws%ws\n", pDirPath, findData.cFileName)); continue; } // // If we're chasing links, make sure the link refers to // a cover page file. // if (flags & CPFLAG_LINK) { _tcscpy(pFilename, findData.cFileName); if (! IsCoverPageShortcut(filename)) continue; } // // Don't display the filename extension // if (pExtension = FindFilenameExtension(findData.cFileName)) *pExtension = NUL; // // Add the cover page name to the list window // listIndex = SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM) findData.cFileName); if (listIndex != LB_ERR) SendMessage(hwndList, LB_SETITEMDATA, listIndex, flags); } while (FindNextFile(hFindFile, &findData)); FindClose(hFindFile); } flags ^= CPFLAG_LINK; } while ((flags & CPFLAG_LINK) && ! pCPInfo->serverCP); } VOID InitCoverPageList( PCPDATA pCPInfo, HWND hDlg ) /*++ Routine Description: Generate a list of available cover pages Arguments: pCPInfo - Points to cover page information hDlg - Handle to the dialog window containing cover page list Return Value: NONE --*/ { HWND hwndList; INT index, lastSel; if ((hwndList = GetDlgItem(hDlg, IDC_COVERPG_LIST)) && pCPInfo) { // // Disable redraw on the list and reset its content // if ((lastSel = SendMessage(hwndList, LB_GETCURSEL, 0, 0)) == LB_ERR) lastSel = 0; SendMessage(hwndList, WM_SETREDRAW, FALSE, 0); SendMessage(hwndList, LB_RESETCONTENT, 0, 0); // // Add cover pages to the list // for (index=0; index < pCPInfo->nDirs; index++) AddCoverPagesToList(pCPInfo, hwndList, index); // // Highlight the first cover page in the list // if ((index = SendMessage(hwndList, LB_GETCOUNT, 0, 0)) > 0 && lastSel >= index) lastSel = index - 1; SendMessage(hwndList, LB_SETCURSEL, lastSel, 0); // // Enable redraw on the list window // SendMessage(hwndList, WM_SETREDRAW, TRUE, 0); } else if (hwndList) { SendMessage(hwndList, LB_RESETCONTENT, 0, 0); } UpdateCoverPageControls(hDlg); } INT GetSelectedCoverPage( PCPDATA pCPInfo, HWND hwndList, LPTSTR pBuffer ) /*++ Routine Description: Retrieve the currently selected cover page filename Arguments: pCPInfo - Points to cover page information hwndList - Handle to the list window pBuffer - Points to a buffer for storing the selected cover page filename The size of the buffer is assumed to be MAX_PATH characters. if pBuffer is NULL, we assume the called is interested in the item flags Return Value: Flags associated with the currently selected item Negative if there is an error --*/ { LPTSTR pDirPath; INT selIndex, itemFlags; // // Default to empty string in case of an error // if (pBuffer) pBuffer[0] = NUL; if (pCPInfo == NULL || hwndList == NULL) return LB_ERR; // // Get currently selected item index // if ((selIndex = SendMessage(hwndList, LB_GETCURSEL, 0, 0)) == LB_ERR) return selIndex; // // Get the flags associated with the currently selected item // itemFlags = SendMessage(hwndList, LB_GETITEMDATA, selIndex, 0); if (itemFlags == LB_ERR || !pBuffer) return itemFlags; Assert((itemFlags & CPFLAG_DIRINDEX) < pCPInfo->nDirs); pDirPath = pCPInfo->pDirPath[itemFlags & CPFLAG_DIRINDEX]; // // Assemble the full pathname for the cover page file // directory prefix // display name // filename extension // while (*pBuffer++ = *pDirPath++) NULL; pBuffer--; SendMessage(hwndList, LB_GETTEXT, selIndex, (LPARAM) pBuffer); _tcscat(pBuffer, (itemFlags & CPFLAG_LINK) ? LNK_FILENAME_EXT : CP_FILENAME_EXT); return itemFlags; } BOOL GetServerCoverPageDirs( PCPDATA pCPInfo ) /*++ Routine Description: Find the directories in which the server cover pages are stored Arguments: hPrinter - Handle to a printer object pCPInfo - Points to cover page information Return Value: TRUE if successful, FALSE otherwise --*/ { BOOL status = FALSE; DWORD cbNeeded; LPTSTR pServerDir; // // Find the driver directory on the printer server // cbNeeded = (_tcslen(gConfigData->pServerName) + _tcslen(SERVER_CP_DIRECTORY) + 16) * sizeof(TCHAR); if (pServerDir = MemAllocZ(cbNeeded)) { _tcscpy( pServerDir, gConfigData->pServerName ); _tcscat( pServerDir, SERVER_CP_DIRECTORY ); Assert(pCPInfo->nDirs == 0); pCPInfo->nDirs = 1; pCPInfo->pDirPath[0] = pServerDir; status = TRUE; } // // Clean up before returning to caller // if (! status) { MemFree(pServerDir); } return status; } VOID AppendPathSeparator( LPTSTR pDirPath ) /*++ Routine Description: Append a path separator (if necessary) at the end of a directory name Arguments: pDirPath - Points to a directory name Return Value: NONE --*/ { INT length; // // Calculate the length of directory string // length = _tcslen(pDirPath); if (length >= MAX_PATH-1 || length < 1) return; // // If the last character is not a path separator, // append a path separator at the end // if (pDirPath[length-1] != TEXT(PATH_SEPARATOR)) { pDirPath[length] = TEXT(PATH_SEPARATOR); pDirPath[length+1] = NUL; } } PCPDATA AllocCoverPageInfo( BOOL serverCP ) /*++ Routine Description: Allocate memory to hold cover page information Arguments: serverCP - Is the caller interested in server or user cover pages hPrinter - Handle to a printer object if serverCP is TRUE Return Value: Pointer to a CPDATA structure, NULL if there is an error NOTE: Put this inside a critical section is the caller is concerned about being thread safe. --*/ { PCPDATA pCPInfo; INT nDirs; LPTSTR pDirPath, pUserCPDir, pSavedPtr; if (pCPInfo = MemAllocZ(sizeof(CPDATA))) { if (pCPInfo->serverCP = serverCP) { // // Find the directory in which the server cover pages are stored // if (! GetServerCoverPageDirs(pCPInfo)) Error(("Couldn't get server cover page directories\n")); } else if (pUserCPDir = pSavedPtr = GetUserCoverPageDir()) { // // Find the directory in which the user cover pages are stored // while (*pUserCPDir && pCPInfo->nDirs < MAX_COVERPAGE_DIRS) { LPTSTR pNextDir = pUserCPDir; // // Find the next semicolon character // while (*pNextDir && *pNextDir != TEXT(';')) pNextDir++; if (*pNextDir != NUL) *pNextDir++ = NUL; // // Make sure the directory name is not too long // if (_tcslen(pUserCPDir) < MAX_PATH) { if (! (pDirPath = AllocStringZ(MAX_PATH))) break; pCPInfo->pDirPath[pCPInfo->nDirs++] = pDirPath; _tcscpy(pDirPath, pUserCPDir); } pUserCPDir = pNextDir; } MemFree(pSavedPtr); } // // Append path separators at the end if necessary // for (nDirs=0; nDirs < pCPInfo->nDirs; nDirs++) { AppendPathSeparator(pCPInfo->pDirPath[nDirs]); Verbose(("Cover page directory: %ws\n", pCPInfo->pDirPath[nDirs])); } } return pCPInfo; } VOID FreeCoverPageInfo( PCPDATA pCPInfo ) /*++ Routine Description: Free up memory used for cover page information Arguments: pCPInfo - Points to cover page information to be freed Return Value: NONE --*/ { if (pCPInfo) { INT index; for (index=0; index < pCPInfo->nDirs; index++) MemFree(pCPInfo->pDirPath[index]); MemFree(pCPInfo); } } LPTSTR MakeQuotedParameterString( LPTSTR pInputStr ) /*++ Routine Description: Make a copy of the input string and make sure it's in the same form as expected by SHELLEXECUTEINFO.lpParameters. Arguments: pInputStr - Specifies the input string Return Value: Pointer to the processed parameter string --*/ #define QUOTE TEXT('"') { LPTSTR pStr, pDestStr; INT length; // // Special case: if the input string is NULL, simply return NULL // if (pInputStr == NULL) return NULL; // // Figure out how long the resulting string is. // Initial value is 3 = two extra quotes plus NUL terminator. // for (pStr=pInputStr, length=3; *pStr; pStr++) length += (*pStr == QUOTE) ? 3 : 1; // // Copy the input string and replace quote characters // if (pStr = pDestStr = MemAlloc(length * sizeof(TCHAR))) { *pStr++ = QUOTE; while (*pInputStr) { if ((*pStr++ = *pInputStr++) == QUOTE) { *pStr++ = QUOTE; *pStr++ = QUOTE; } } *pStr++ = QUOTE; *pStr = NUL; } return pDestStr; } VOID HandleOpenCoverPage( HWND hDlg, PCPDATA pCPInfo, HWND hwndList, LPTSTR pSelected, INT action ) /*++ Routine Description: Edit the currently selected cover page file or create a new cover page file Arguments: hDlg - Handle to the dialog window on which the list of cover pages is displayed pCPInfo - Points to cover page information hwndList - Handle to cover page listbox window pSelected - Currently selected cover page filename action - Open an existing cover page file or create a new one Return Value: NONE --*/ { TCHAR filename[MAX_PATH]; LPTSTR pExecutableName, pDirPath, pFilename; SHELLEXECUTEINFO shellExeInfo = { sizeof(SHELLEXECUTEINFO), SEE_MASK_NOCLOSEPROCESS, hDlg, NULL, NULL, NULL, NULL, SW_SHOWNORMAL, }; // // Determine the default directory to run the cover page editor in: // if (action == CPACTION_NEW) { // // When creating a new cover page, the default directory is either // the server cover page directory or the user cover page directory // depending on whether the user is doing server adminstration. // pDirPath = pCPInfo->pDirPath[0]; pFilename = NULL; } else { INT flags; // // If the currently selected file is a link, resolve it first // _tcscpy(filename, pSelected); if (!IsEmptyString(pSelected) && (flags = GetSelectedCoverPage(pCPInfo, hwndList, NULL)) > 0 && (flags & CPFLAG_LINK) && !ResolveShortcut(pSelected, filename)) { DisplayMessageDialog(hDlg, 0, 0, IDS_RESOLVE_LINK_FAILED, pSelected); return; } // // Separate the filename into directory and filename components // if (pFilename = _tcsrchr(filename, TEXT(PATH_SEPARATOR))) { *pFilename++ = NUL; pDirPath = filename; } else { pFilename = filename; pDirPath = NULL; } } // // Find the "Cover Page Editor" executable // if ((pExecutableName = GetCoverPageEditor()) == NULL) { DisplayMessageDialog(hDlg, 0, 0, IDS_CANNOT_FIND_CPEDITOR); return; } // // Start cover page editor and wait for it to exit before proceeding // shellExeInfo.lpFile = pExecutableName; shellExeInfo.lpDirectory = pDirPath; shellExeInfo.lpParameters = MakeQuotedParameterString(pFilename); Verbose(("Cover page editor: %ws\n", pExecutableName)); Verbose(("Initial working directory: %ws\n", pDirPath)); Verbose(("Cover page filename: %ws\n", shellExeInfo.lpParameters)); if (! ShellExecuteEx(&shellExeInfo)) { DisplayMessageDialog(hDlg, 0, 0, IDS_CANNOT_OPEN_CPEDITOR, pExecutableName); MemFree(shellExeInfo.lpParameters); MemFree(pExecutableName); return; } // // Refresh the list of cover page files when we're done // MemFree(shellExeInfo.lpParameters); MemFree(pExecutableName); if (WaitForSingleObject(shellExeInfo.hProcess, INFINITE) != WAIT_FAILED) InitCoverPageList(pCPInfo, hDlg); } VOID HandleBrowseCoverPage( HWND hDlg, PCPDATA pCPInfo, HWND hwndList, LPTSTR pSelected ) /*++ Routine Description: Remove the currently selected cover page file Arguments: hDlg - Handle to the dialog window on which the list of cover pages is displayed pCPInfo - Points to cover page information hwndList - Handle to cover page listbox window pSelected - Currently selected cover page filename Return Value: NONE --*/ { TCHAR filename[MAX_PATH]; TCHAR title[MAX_TITLE_LEN]; TCHAR filter[MAX_TITLE_LEN]; LPTSTR pExtension, pFilename; LPTSTR pCPDir; INT n; OPENFILENAME ofn = { sizeof(OPENFILENAME), hDlg, ghInstance, filter, NULL, 0, 1, filename, MAX_PATH, NULL, 0, NULL, title, OFN_FILEMUSTEXIST | OFN_NODEREFERENCELINKS | OFN_HIDEREADONLY, 0, 0, NULL, 0, NULL, NULL, }; // // Figure out what the initial directory should be // if (! IsEmptyString(pSelected)) { INT flags; // // Find out if the currently selected cover page file is a // user cover page and whether it's a link // if ((flags = GetSelectedCoverPage(pCPInfo, hwndList, NULL)) > 0 && (flags & CPFLAG_LINK) && ResolveShortcut(pSelected, filename)) { // // Set the initial directory to the link destination // _tcscpy(pSelected, filename); if (pFilename = _tcsrchr(pSelected, TEXT(PATH_SEPARATOR))) { *pFilename = NUL; ofn.lpstrInitialDir = pSelected; } } } // // Compose the file-type filter string // LoadString(ghInstance, IDS_CP_FILETYPE, title, MAX_TITLE_LEN); wsprintf(filter, TEXT("%s%c*%s%c"), title, NUL, CP_FILENAME_EXT, NUL); LoadString(ghInstance, IDS_BROWSE_COVERPAGE, title, MAX_TITLE_LEN); filename[0] = NUL; // // Present the "Open File" dialog // if (! GetOpenFileName(&ofn)) return; // // Make sure the selected filename has the correct extension // if ((pExtension = FindFilenameExtension(filename)) == NULL || _tcsicmp(pExtension, CP_FILENAME_EXT) != EQUAL_STRING) { DisplayMessageDialog(hDlg, 0, 0, IDS_BAD_CP_EXTENSION, CP_FILENAME_EXT); return; } // // Check if the selected file is already inside one of the // cover page directories // for (n=0; n < pCPInfo->nDirs; n++) { if (_tcsnicmp(filename, pCPInfo->pDirPath[n], ofn.nFileOffset) == EQUAL_STRING) { DisplayMessageDialog(hDlg, 0, 0, IDS_CP_DUPLICATE, filename); return; } } // // Add the selected cover page file to the first cover page directory // Create the cover page directory if necessary // pCPDir = pCPInfo->pDirPath[0]; if (!pCPDir || IsEmptyString(pCPDir)) { DisplayMessageDialog(hDlg, 0, 0, IDS_NO_COVERPG_DIR); return; } CreateDirectory(pCPDir, NULL); pFilename = &filename[ofn.nFileOffset]; _tcscpy(pSelected, pCPDir); n = _tcslen(pSelected); if (n + _tcslen(pFilename) >= MAX_PATH - MAX_FILENAME_EXT || pFilename >= pExtension) { DisplayMessageDialog(hDlg, 0, 0, IDS_FILENAME_TOOLONG); return; } _tcsncpy(pSelected + n, pFilename, pExtension - pFilename); n += pExtension - pFilename; if (pCPInfo->serverCP) { // // Copy the physical file for server cover pages // _tcscpy(pSelected + n, CP_FILENAME_EXT); if (! CopyFile(filename, pSelected, FALSE)) { DisplayMessageDialog(hDlg, 0, 0, IDS_COPY_FILE_FAILED, filename, pSelected); return; } } else { // // Create the shortcut file for user cover page // _tcscpy(pSelected + n, LNK_FILENAME_EXT); if (! CreateShortcut(pSelected, filename)) { DisplayMessageDialog(hDlg, 0, 0, IDS_CREATE_LINK_FAILED, pSelected, filename); return; } } // // Refresh the cover page list - we're being lazy here in that // we reset the entire list content // InitCoverPageList(pCPInfo, hDlg); } VOID HandleRemoveCoverPage( HWND hDlg, PCPDATA pCPInfo, HWND hwndList, LPTSTR pFilename ) /*++ Routine Description: Remove the currently selected cover page file Arguments: hDlg - Handle to the dialog window on which the list of cover pages is displayed pCPInfo - Points to cover page information hwndList - Handle to cover page listbox window pFilename - Currently selected cover page filename Return Value: NONE --*/ { // // Display the confirmation dialog before proceeding // if (DisplayMessageDialog(hDlg, MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2, IDS_CONFIRM_DELETE, IDS_DELETE_PROMPT, pFilename) == IDYES) { if (DeleteFile(pFilename)) { // // Update the list box if the file is successfully removed // INT selIndex, count; if ((selIndex = SendMessage(hwndList, LB_GETCURSEL, 0, 0)) != LB_ERR) { SendMessage(hwndList, LB_DELETESTRING, selIndex, 0); if ((count = SendMessage(hwndList, LB_GETCOUNT, 0, 0)) > 0) { count --; SendMessage(hwndList, LB_SETCURSEL, min(selIndex, count), 0); } } UpdateCoverPageControls(hDlg); } else DisplayMessageDialog(hDlg, 0, 0, IDS_DELETE_FAILED, pFilename); } } VOID ManageCoverPageList( HWND hDlg, PCPDATA pCPInfo, HWND hwndList, INT action ) /*++ Routine Description: Perform various action to manage the list of cover pages Arguments: hDlg - Handle to the dialog window on which the list of cover pages is displayed pCPInfo - Points to cover page information hwndList - Handle to cover page listbox window action - What action to perform on the cover page list Return Value: NONE --*/ { TCHAR filename[MAX_PATH]; // // Get the name of currently selected cover page file // if (pCPInfo == NULL || hwndList == NULL) return; GetSelectedCoverPage(pCPInfo, hwndList, filename); // // Call appropriate function depends on the action parameter // switch (action) { case CPACTION_OPEN: if (IsEmptyString(filename)) break; case CPACTION_NEW: HandleOpenCoverPage(hDlg, pCPInfo, hwndList, filename, action); break; case CPACTION_BROWSE: HandleBrowseCoverPage(hDlg, pCPInfo, hwndList, filename); break; case CPACTION_REMOVE: if (! IsEmptyString(filename)) HandleRemoveCoverPage(hDlg, pCPInfo, hwndList, filename); break; } } VOID UpdateCoverPageControls( HWND hDlg ) /*++ Routine Description: Enable/disable buttons for manage cover page files Arguments: hDlg - Handle to the property page containing the cover page controls Return Value: NONE --*/ { HWND hwndOpen, hwndRemove; // // If all buttons are disabled, leave them alone here // if (! IsWindowEnabled(GetDlgItem(hDlg, IDC_COVERPG_NEW))) return; hwndOpen = GetDlgItem(hDlg, IDC_COVERPG_OPEN); hwndRemove = GetDlgItem(hDlg, IDC_COVERPG_REMOVE); if (SendDlgItemMessage(hDlg, IDC_COVERPG_LIST, LB_GETCURSEL, 0, 0) != LB_ERR) { EnableWindow(hwndOpen, TRUE); EnableWindow(hwndRemove, TRUE); } else { if (GetFocus() == hwndOpen || GetFocus() == hwndRemove) SetFocus(GetDlgItem(hDlg, IDC_COVERPG_NEW)); EnableWindow(hwndOpen, FALSE); EnableWindow(hwndRemove, FALSE); } }