/*++ Copyright (c) 1996 Microsoft Corporation Module Name: print.c Abstract: This module contains the job specific WINFAX API functions. Author: Wesley Witt (wesw) 29-Nov-1996 Revision History: --*/ #include "faxapi.h" #pragma hdrstop #define InchesToCM(_x) (((_x) * 254L + 50) / 100) #define CMToInches(_x) (((_x) * 100L + 127) / 254) #define LEFT_MARGIN 1 // ---| #define RIGHT_MARGIN 1 // | #define TOP_MARGIN 1 // |---> in inches #define BOTTOM_MARGIN 1 // ---| #define FAX_DISPLAY_NAME TEXT("Fax Service") static int TiffDataWidth[] = { 0, // nothing 1, // TIFF_BYTE 1, // TIFF_ASCII 2, // TIFF_SHORT 4, // TIFF_LONG 8, // TIFF_RATIONAL 1, // TIFF_SBYTE 1, // TIFF_UNDEFINED 2, // TIFF_SSHORT 4, // TIFF_SLONG 8, // TIFF_SRATIONAL 4, // TIFF_FLOAT 8, // TIFF_DOUBLE }; VOID LocalSystemTimeToSystemTime( LPSYSTEMTIME LocalSystemTime, LPSYSTEMTIME SystemTime ) { FILETIME LocalFileTime; FILETIME UtcFileTime; SystemTimeToFileTime( LocalSystemTime, &LocalFileTime ); LocalFileTimeToFileTime( &LocalFileTime, &UtcFileTime ); FileTimeToSystemTime( &UtcFileTime, SystemTime ); } LPWSTR GetFaxPrinterName( VOID ) { PPRINTER_INFO_2 PrinterInfo; DWORD i; DWORD Count; PrinterInfo = (PPRINTER_INFO_2) MyEnumPrinters( NULL, 2, &Count, PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS ); if (PrinterInfo == NULL) { return NULL; } for (i=0; i= (xPrintRes - dxRight - dxLeft) ) || (lpLine == pLineEOL)) { yCurpos += yPrintChar; nPrintedLines++; xCurpos = 0; } if (nPrintedLines >= nLinesPerPage) { EndPage( hDC ); fPageStarted = FALSE; nPrintedLines = 0; xCurpos = 0; yCurpos = 0; iPageNum++; } } } while( lpLine != pLineEOL ); if (*lpLine == '\r') { lpLine += 1; } if (*lpLine == '\n') { lpLine += 1; } } if (fPageStarted) { EndPage( hDC ); } exit: if (fmText.fPtr) { MapFileClose( &fmText, 0 ); } if (hPrevFont) { SelectObject( hDC, hPrevFont ); DeleteObject( hFont ); } if (PrevBkMode) { SetBkMode( hDC, PrevBkMode ); } return rVal; } BOOL PrintRandomDocument( LPCWSTR FaxPrinterName, LPCWSTR DocName, LPWSTR OutputFile ) /*++ Routine Description: Prints a document that is attached to a message Arguments: FaxPrinterName - name of the printer to print the attachment on DocName - name of the attachment document Return Value: Print job id or zero for failure. --*/ { SHELLEXECUTEINFO sei; WCHAR Args[MAX_PATH]; WCHAR TempPath[MAX_PATH]; HANDLE hMap = NULL; HANDLE hEvent = NULL; HANDLE hMutex = NULL; HANDLE hMutexAttach = NULL; LPDWORD pJobId = NULL; DWORD JobId = 0; BOOL bSuccess = FALSE; SECURITY_ATTRIBUTES memsa,mutsa,synsa,eventsa; SECURITY_DESCRIPTOR memsd,mutsd,synsd,eventsd; // // get the temp path name and use it for the // working dir of the launched app // if (!GetTempPath( sizeof(TempPath)/sizeof(WCHAR), TempPath )) { return FALSE; } // // serialize access to this function. // this is necessary because we have to // control access to the global shared memory region and mutex // // // serialize access to this function. // this is necessary because we can't have more than one // app accessing our shared memory region and mutex // hMutexAttach = OpenMutex(MUTEX_ALL_ACCESS,FALSE,FAXRENDER_MUTEX); if (!hMutexAttach) { // // we need to open this mutex with a NULL dacl so that everyone can access this // synsa.nLength = sizeof(SECURITY_ATTRIBUTES); synsa.bInheritHandle = TRUE; synsa.lpSecurityDescriptor = &synsd; if(!InitializeSecurityDescriptor(&synsd, SECURITY_DESCRIPTOR_REVISION)) { goto exit; } if(!SetSecurityDescriptorDacl(&synsd, TRUE, (PACL)NULL, FALSE)) { goto exit; } hMutexAttach = CreateMutex( &synsa, TRUE, FAXRENDER_MUTEX ); if (!hMutexAttach) { goto exit; } } else { if (WaitForSingleObject( hMutexAttach, 1000* 60 * 5) != WAIT_OBJECT_0) { // // something went wrong // CloseHandle( hMutexAttach ); goto exit; } } // // note that this is serialized inside of a critical section. // we can only have one application setting this at a time or // we'll stomp on ourselves. // // // since mapispooler might be running under a different security context, // we must setup a NULL security descriptor // memsa.nLength = sizeof(SECURITY_ATTRIBUTES); memsa.bInheritHandle = TRUE; memsa.lpSecurityDescriptor = &memsd; if(!InitializeSecurityDescriptor(&memsd, SECURITY_DESCRIPTOR_REVISION)) { goto exit; } if(!SetSecurityDescriptorDacl(&memsd, TRUE, (PACL)NULL, FALSE)) { goto exit; } mutsa.nLength = sizeof(SECURITY_ATTRIBUTES); mutsa.bInheritHandle = TRUE; mutsa.lpSecurityDescriptor = &mutsd; if(!InitializeSecurityDescriptor(&mutsd, SECURITY_DESCRIPTOR_REVISION)) { goto exit; } if(!SetSecurityDescriptorDacl(&mutsd, TRUE, (PACL)NULL, FALSE)) { goto exit; } eventsa.nLength = sizeof(SECURITY_ATTRIBUTES); eventsa.bInheritHandle = TRUE; eventsa.lpSecurityDescriptor = &eventsd; if(!InitializeSecurityDescriptor(&eventsd, SECURITY_DESCRIPTOR_REVISION)) { goto exit; } if(!SetSecurityDescriptorDacl(&eventsd, TRUE, (PACL)NULL, FALSE)) { goto exit; } // // create the shared memory region for the print jobid // the jobid is filled in by the fax printer driver // hMap = CreateFileMapping( INVALID_HANDLE_VALUE, &memsa, PAGE_READWRITE | SEC_COMMIT, 0, 4096, FAXXP_MEM_NAME ); if (!hMap) { goto exit; } pJobId = (LPDWORD) MapViewOfFile( hMap, FILE_MAP_WRITE, 0, 0, 0 ); if (!pJobId) { goto exit; } wcscpy((LPTSTR) pJobId, OutputFile); // // set the arguments to the app. // these arguments are either passed on // the command line with the /pt switch or // use as variables for substitution in the // ddeexec value in the registry. // // the values are as follows: // %1 = file name // %2 = printer name // %3 = driver name // %4 = port name // // the first argument does not need to be // supplied in the args array because it is implied, // shellexecuteex gets it from the lpFile field. // arguments 3 & 4 are left blank because they // are win31 artifacts that are not necessary // any more. each argument must be enclosed // in double quotes. // wsprintf( Args, L"\"%s\" \"\" \"\"", FaxPrinterName ); // // fill in the SHELLEXECUTEINFO structure // sei.cbSize = sizeof(sei); sei.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_DDEWAIT; sei.hwnd = NULL; sei.lpVerb = L"printto"; sei.lpFile = DocName; sei.lpParameters = Args; sei.lpDirectory = TempPath; sei.nShow = SW_SHOWMINNOACTIVE; sei.hInstApp = NULL; sei.lpIDList = NULL; sei.lpClass = NULL; sei.hkeyClass = NULL; sei.dwHotKey = 0; sei.hIcon = NULL; sei.hProcess = NULL; // // create the named mutex for the print driver. // this is initially unclaimed, and is claimed by the first instance // of the print driver invoked after this. We do this last in order to // avoid a situation where we catch the incorrect instance of the print driver // printing // hMutex = CreateMutex( &mutsa, FALSE, FAXXP_MUTEX_NAME ); if (!hMutex) { goto exit; } // // create the named event for the print driver. // this event is signaled when the print driver is finished rendering the document // hEvent = CreateEvent( &eventsa, FALSE, FALSE, FAXXP_EVENT_NAME ); if (!hEvent) { goto exit; } // // launch the app // if (!ShellExecuteEx( &sei )) { goto exit; } // // wait for the print driver to finish rendering the document // if (WaitForSingleObject( hEvent, 1000 * 60 * 5 ) != WAIT_OBJECT_0) { // // something went wrong... // goto exit; } // // wait for the print driver to exit so we can get the document // if (WaitForSingleObject( hMutex, 1000 * 60 * 5) != WAIT_OBJECT_0) { // // something went wrong // goto exit; } ReleaseMutex(hMutex); // // save the print jobid // JobId = *pJobId; bSuccess = TRUE; exit: // // clean up and leave... // if (sei.hProcess) CloseHandle( sei.hProcess ); if (hEvent) CloseHandle( hEvent ); if (hMutex) CloseHandle( hMutex ); if (pJobId) UnmapViewOfFile( pJobId ); if (hMap) CloseHandle( hMap ); if (hMutexAttach) { ReleaseMutex( hMutexAttach ); CloseHandle( hMutexAttach ); } if (!bSuccess) { SetLastError(ERROR_INVALID_DATA); } return bSuccess; } BOOL CreateCoverpageTiffFile( IN const FAX_COVERPAGE_INFOW *CoverpageInfo, OUT LPWSTR CovTiffFile ) { WCHAR TempPath[MAX_PATH]; WCHAR TempFile[MAX_PATH]; LPWSTR FaxPrinter; FAX_PRINT_INFOW PrintInfo; FAX_CONTEXT_INFOW ContextInfo; DWORD TmpFaxJobId; BOOL Rslt; TempFile[0] = 0; FaxPrinter = GetFaxPrinterName(); if (FaxPrinter == NULL) { return FALSE; } if (!GetTempPath( sizeof(TempPath)/sizeof(WCHAR), TempPath ) || !GetTempFileName( TempPath, L"fax", 0, TempFile )) { return FALSE; } ZeroMemory( &PrintInfo, sizeof(FAX_PRINT_INFO) ); PrintInfo.SizeOfStruct = sizeof(FAX_PRINT_INFO); PrintInfo.OutputFileName = TempFile; ZeroMemory( &ContextInfo, sizeof(FAX_CONTEXT_INFOW) ); ContextInfo.SizeOfStruct = sizeof(FAX_CONTEXT_INFOW); if (!FaxStartPrintJobW( FaxPrinter, &PrintInfo, &TmpFaxJobId, &ContextInfo )) { DeleteFile( TempFile ); return FALSE; } Rslt = FaxPrintCoverPageW( &ContextInfo, CoverpageInfo ); EndDoc( ContextInfo.hDC ); DeleteDC( ContextInfo.hDC ); if (!Rslt) { DeleteFile( TempFile ); return FALSE; } wcscpy( CovTiffFile, TempFile ); return TRUE; } BOOL CreateFinalTiffFile( IN LPWSTR FileName, OUT LPWSTR FinalTiffFile, IN const FAX_COVERPAGE_INFOW *CoverpageInfo ) { WCHAR TempPath[MAX_PATH]; WCHAR FullPath[MAX_PATH]; WCHAR TempFile[MAX_PATH]; WCHAR TiffFile[MAX_PATH]; LPWSTR FaxPrinter = NULL; FAX_PRINT_INFOW PrintInfo; DWORD TmpFaxJobId; FAX_CONTEXT_INFOW ContextInfo; LPWSTR p; DWORD Flags = 0; BOOL Rslt; // // make sure that the tiff file passed in is a valid tiff file // if (!GetTempPath( sizeof(TempPath)/sizeof(WCHAR), TempPath )) { return FALSE; } if (GetTempFileName( TempPath, L"fax", 0, TempFile ) == 0 || GetFullPathName( TempFile, sizeof(FullPath)/sizeof(WCHAR), FullPath, &p ) == 0) { return FALSE; } if (!ConvertTiffFileToValidFaxFormat( FileName, FullPath, &Flags )) { if ((Flags & TIFFCF_NOT_TIFF_FILE) == 0) { Flags = TIFFCF_NOT_TIFF_FILE; } } if (Flags & TIFFCF_NOT_TIFF_FILE) { // // try to output the source file into a tiff file, // by printing to the fax printer in "file" mode // FaxPrinter = GetFaxPrinterName(); if (FaxPrinter == NULL) { DeleteFile( FullPath ); SetLastError( ERROR_INVALID_FUNCTION ); return FALSE; } if (!PrintRandomDocument( FaxPrinter, FileName, FullPath )) { DeleteFile( FullPath ); SetLastError( ERROR_INVALID_FUNCTION ); return FALSE; } wcscpy( TiffFile, FullPath ); } else if (Flags & TIFFCF_UNCOMPRESSED_BITS) { if (FaxPrinter == NULL) { FaxPrinter = GetFaxPrinterName(); if (FaxPrinter == NULL) { DeleteFile( FullPath ); SetLastError( ERROR_INVALID_FUNCTION ); return FALSE; } } if (Flags & TIFFCF_ORIGINAL_FILE_GOOD) { // // nothing at fullpath, just delete it and use the original source // DeleteFile( FullPath ); wcscpy( TiffFile, FileName ); } else { wcscpy( TiffFile, FullPath ); } if (GetTempFileName( TempPath, L"fax", 0, TempFile ) == 0 || GetFullPathName( TempFile, sizeof(FullPath)/sizeof(WCHAR), FullPath, &p ) == 0) { DeleteFile( TiffFile ); return FALSE; } ZeroMemory( &PrintInfo, sizeof(FAX_PRINT_INFOW) ); PrintInfo.SizeOfStruct = sizeof(FAX_PRINT_INFOW); PrintInfo.OutputFileName = FullPath; ZeroMemory( &ContextInfo, sizeof(FAX_CONTEXT_INFOW) ); ContextInfo.SizeOfStruct = sizeof(FAX_CONTEXT_INFOW); if (!FaxStartPrintJobW( FaxPrinter, &PrintInfo, &TmpFaxJobId, &ContextInfo )) { if ((Flags & TIFFCF_ORIGINAL_FILE_GOOD) == 0) DeleteFile( TiffFile ); DeleteFile( FullPath ); SetLastError( ERROR_INVALID_FUNCTION ); return FALSE; } Rslt = PrintTiffFile( ContextInfo.hDC, TiffFile ); EndDoc( ContextInfo.hDC ); DeleteDC( ContextInfo.hDC ); if ((Flags & TIFFCF_ORIGINAL_FILE_GOOD) == 0) { DeleteFile( TiffFile ); } if (!Rslt) { DeleteFile( FullPath ); SetLastError( ERROR_INVALID_FUNCTION ); return FALSE; } wcscpy( TiffFile, FullPath ); } else if (Flags & TIFFCF_ORIGINAL_FILE_GOOD) { // // we didn't create anything at FullPath, just use FileName // DeleteFile( FullPath ); wcscpy( TiffFile, FileName ); } else { // // should never hit this case // DeleteFile( FullPath ); SetLastError( ERROR_INVALID_FUNCTION ); return FALSE; } // // if a coverpage is specified then print the coverpage first // if (CoverpageInfo && CoverpageInfo->CoverPageName) { if (!CreateCoverpageTiffFile( CoverpageInfo, TempFile )) { if (wcscmp(FileName,TiffFile) != 0) DeleteFile( TiffFile ); DeleteFile( TempFile ); return FALSE; } if (!MergeTiffFiles( TempFile, TiffFile )) { if (wcscmp(FileName,TiffFile) != 0) DeleteFile( TiffFile ); DeleteFile( TempFile ); return FALSE; } FileName = TempFile; } else { FileName = TiffFile; } wcscpy( FinalTiffFile, FileName ); return TRUE; } BOOL CopyFileToServerQueue( IN const HANDLE FaxHandle, IN LPCWSTR TiffFile, IN LPWSTR QueueFileName ) { error_status_t ec; WCHAR FullPath[MAX_PATH]; // // get a file name from the fax server // ec = FAX_GetQueueFileName( FH_FAX_HANDLE(FaxHandle), QueueFileName, MAX_PATH ); if (ec) { SetLastError( ec ); return FALSE; } // // create the full path to the new file // if (!IsLocalFaxConnection(FaxHandle)) { // // remote file // swprintf( FullPath, FAX_QUEUE_PATH, FH_DATA(FaxHandle)->MachineName, QueueFileName ); } else { // // local file // if (!GetSpecialPath( CSIDL_COMMON_APPDATA, FullPath )) { return FALSE; } ConcatenatePaths( FullPath, FAX_QUEUE_DIR ); ConcatenatePaths( FullPath, QueueFileName ); } // // copy the file to the fax server queue dir // if (!CopyFile( TiffFile, FullPath, FALSE )) { return FALSE; } SetFileAttributes( FullPath, (GetFileAttributes( FullPath ) & (0xFFFFFFFF^FILE_ATTRIBUTE_READONLY)) | FILE_ATTRIBUTE_NORMAL ); return TRUE; } DWORD GetLineId( FARPROC LineGetId, HCALL CallHandle ) { LPVARSTRING DeviceId; long rslt = 0; DWORD LineId; // // get the deviceID associated with the call handle // DeviceId = MemAlloc(sizeof(VARSTRING)+1000); if (!DeviceId) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return 0; } DeviceId->dwTotalSize=sizeof(VARSTRING) +1000; rslt = (DWORD)LineGetId(NULL,0,(HCALL) CallHandle,LINECALLSELECT_CALL,DeviceId,L"tapi/line"); if (rslt < 0) { DebugPrint((TEXT("LineGetId() failed, ec = %x\n"),rslt)); MemFree(DeviceId); SetLastError(ERROR_INVALID_PARAMETER); return 0; } if (DeviceId->dwStringFormat != STRINGFORMAT_BINARY ) { MemFree(DeviceId); SetLastError(ERROR_INVALID_PARAMETER); return 0; } LineId = (DWORD) *((LPBYTE)DeviceId + DeviceId->dwStringOffset); MemFree(DeviceId); return LineId; } BOOL WINAPI FaxSendDocumentW( IN HANDLE FaxHandle, IN LPCWSTR FileName, IN FAX_JOB_PARAMW *JobParams, IN const FAX_COVERPAGE_INFOW *CoverpageInfo, OUT LPDWORD FaxJobId ) /*++ Routine Description: Sends a FAX document to the specified recipient. This is an asychronous operation. Use FaxReportStatus to determine when the send is completed. Arguments: FaxHandle - FAX handle obtained from FaxConnectFaxServer. FileName - File containing the TIFF-F FAX document. JobParams - pointer to FAX_JOB_PARAM structure with transmission params CoverpageInfo - optional pointer to FAX_COVERPAGE_INFO structure FaxJobId - receives the Fax JobId for the job. Return Value: TRUE - Success FALSE - Failure, call GetLastError() for more error information. --*/ { error_status_t ec; WCHAR QueueFileName[MAX_PATH]; WCHAR ExistingFile[MAX_PATH]; DWORD rc; LPWSTR p; WCHAR TiffFile[MAX_PATH]; HINSTANCE hTapiLib = NULL; WCHAR TapiPath[MAX_PATH]; WCHAR MutexName[64]; HANDLE hLineMutex = NULL; FARPROC LineHandoff; FARPROC LineGetId; IUnknown* pDisp=NULL; ITBasicCallControl* pCallControl; ITCallInfo* pCallInfo; ITAddress* pAddressInfo; ITAddressCapabilities* pAddressCaps; CALL_STATE CallState; BSTR FaxSvcName; HRESULT hr; DWORD LineId; DWORD _JobId; DWORD Event = 0; long rslt = 0; // // argument validation // if (!ValidateFaxHandle(FaxHandle, FHT_SERVICE)) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } if (!FileName || !JobParams || JobParams->SizeOfStruct != sizeof(FAX_JOB_PARAMW)) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if (JobParams->ScheduleAction != JSA_NOW && JobParams->ScheduleAction != JSA_SPECIFIC_TIME && JobParams->ScheduleAction != JSA_DISCOUNT_PERIOD) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if (JobParams->DeliveryReportType != DRT_NONE && JobParams->DeliveryReportType != DRT_EMAIL && JobParams->DeliveryReportType != DRT_INBOX ) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } // // make sure the file is there // rc = GetFullPathName(FileName,sizeof(ExistingFile)/sizeof(WCHAR),ExistingFile,&p); if (rc > MAX_PATH || rc == 0) { DebugPrint(( TEXT("GetFullPathName failed, ec= %d\n"),GetLastError() )); SetLastError( (rc > MAX_PATH) ? ERROR_BUFFER_OVERFLOW : GetLastError() ); return FALSE; } if (GetFileAttributes(ExistingFile)==0xFFFFFFFF) { SetLastError(ERROR_FILE_NOT_FOUND); return FALSE; } // // if they want a coverpage, try to validate it // if (CoverpageInfo && !ValidateCoverpage(CoverpageInfo->CoverPageName, IsLocalFaxConnection(FaxHandle) ? NULL : FH_DATA(FaxHandle)->MachineName, CoverpageInfo->UseServerCoverPage, NULL)) { SetLastError(ERROR_FILE_NOT_FOUND); return FALSE; } if (JobParams->CallHandle != 0 || JobParams->Reserved[0]==0xFFFF1234) { // // we don't support call handoff if it's a remote server connection // if (!IsLocalFaxConnection(FaxHandle)) { SetLastError(ERROR_INVALID_FUNCTION); return FALSE; } if (JobParams->CallHandle) { // // tapi is dynamic // ExpandEnvironmentStrings(TAPI_LIBRARY,TapiPath,MAX_PATH); hTapiLib = LoadLibrary(TapiPath); if (!hTapiLib) { SetLastError(ERROR_INVALID_LIBRARY); return FALSE; } LineHandoff = GetProcAddress(hTapiLib,"lineHandoffW"); LineGetId = GetProcAddress(hTapiLib,"lineGetIDW"); if (!LineHandoff || !LineGetId) { FreeLibrary(hTapiLib); SetLastError(ERROR_INVALID_FUNCTION); return FALSE; } // // get the line ID // LineId = GetLineId(LineGetId,JobParams->CallHandle); if (LineId) { JobParams->Reserved[2] = LineId; } else { FreeLibrary(hTapiLib); SetLastError(ERROR_INVALID_FUNCTION); return FALSE; } } else if (JobParams->Reserved[1]) { // // GetDeviceId from tapi3 dispinterface // pDisp = (IUnknown*) JobParams->Reserved[1]; hr = pDisp->lpVtbl->QueryInterface( pDisp, &IID_ITCallInfo, (void**)&pCallInfo ); if (FAILED(hr)) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if (FAILED(pCallInfo->lpVtbl->get_CallState(pCallInfo,&CallState))) { pCallInfo->lpVtbl->Release(pCallInfo); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if (CallState != CS_CONNECTED) { DebugPrint(( TEXT("callstate(%d) is invalid, cannot handoff job\n"),CallState )); pCallInfo->lpVtbl->Release(pCallInfo); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if (FAILED(pCallInfo->lpVtbl->get_Address(pCallInfo,&pAddressInfo))) { pCallInfo->lpVtbl->Release(pCallInfo); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if (FAILED(pAddressInfo->lpVtbl->QueryInterface(pAddressInfo, &IID_ITAddressCapabilities, (void**)&pAddressCaps))) { pCallInfo->lpVtbl->Release(pCallInfo); pAddressInfo->lpVtbl->Release(pAddressInfo); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if (FAILED(pAddressCaps->lpVtbl->get_AddressCapability( pAddressCaps, AC_LINEID, &LineId ))) { pCallInfo->lpVtbl->Release(pCallInfo); pAddressInfo->lpVtbl->Release(pAddressInfo); pAddressCaps->lpVtbl->Release(pAddressCaps); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if (LineId == 0) { pCallInfo->lpVtbl->Release(pCallInfo); pAddressInfo->lpVtbl->Release(pAddressInfo); pAddressCaps->lpVtbl->Release(pAddressCaps); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } JobParams->Reserved[2] = LineId; pCallInfo->lpVtbl->Release(pCallInfo); pAddressInfo->lpVtbl->Release(pAddressInfo); pAddressCaps->lpVtbl->Release(pAddressCaps); } else { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } DebugPrint((TEXT("device ID = %d\n"),JobParams->Reserved[2])); // // we need a mutex to ensure fax service owns the line before calling lineHandoff // wsprintf(MutexName,L"FaxLineHandoff%d",JobParams->Reserved[2]); hLineMutex = CreateMutex(NULL,FALSE,MutexName); if (!hLineMutex) { FreeLibrary(hTapiLib); return FALSE; } } else { // // this is a normal fax...validate the fax number. // if (!JobParams->RecipientNumber) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } } // // make sure that the tiff file passed in is a valid tiff file // ZeroMemory(TiffFile,sizeof(TiffFile)); if (!CreateFinalTiffFile( (LPWSTR) ExistingFile, TiffFile, CoverpageInfo )) { DeleteFile( TiffFile ); if (hTapiLib) { FreeLibrary(hTapiLib); } if (hLineMutex) { CloseHandle(hLineMutex); } SetLastError(ERROR_INVALID_DATA); return FALSE; } // // copy the file to the server's queue dir // if (!CopyFileToServerQueue( FaxHandle, TiffFile, QueueFileName )) { if (hTapiLib) { FreeLibrary(hTapiLib); } if (hLineMutex) { CloseHandle(hLineMutex); } return FALSE; } // // the passed in file should be treated as read-only // if we created a temp file then delete it // if (wcscmp(ExistingFile,TiffFile) != 0) { DeleteFile( TiffFile ); } // // queue the fax to be sent // if (JobParams->Reserved[0] != 0xffffffff) { JobParams->Reserved[0] = 0; JobParams->Reserved[1] = 0; } if (JobParams->ScheduleAction == JSA_SPECIFIC_TIME) { // // convert the system time from local to utc // LocalSystemTimeToSystemTime( &JobParams->ScheduleTime, &JobParams->ScheduleTime ); } ec = FAX_SendDocument( FH_FAX_HANDLE(FaxHandle), QueueFileName, JobParams, &_JobId ); if (ec) { SetLastError( ec ); if (hTapiLib) { FreeLibrary(hTapiLib); } if (hLineMutex) { CloseHandle(hLineMutex); } return FALSE; } if (FaxJobId) { *FaxJobId = _JobId; } // // we're done if it's a normal call // if (JobParams->CallHandle == 0 && !pDisp) { return TRUE; } // // wait for Mutex to get signalled // DebugPrint((TEXT("Waiting for mutex \"FaxLineHandoff%d\""),JobParams->Reserved[2])); Event = WaitForSingleObject(hLineMutex,INFINITE); if (Event != WAIT_OBJECT_0 ) { // // bail out, we couldn't open the line? // } // // handoff the call to the fax service, FSP must change media mode appropriately // if (JobParams->CallHandle) { // // TAPI 2.0 handoff // DebugPrint((TEXT("Handing off call %x to faxsvc"),JobParams->CallHandle)); rslt = (long)LineHandoff(JobParams->CallHandle, FAX_DISPLAY_NAME , 0 ); FreeLibrary(hTapiLib); CloseHandle(hLineMutex); if (rslt != 0) { SetLastError(rslt); return FALSE; } } else { // // TAPI 3.0 handoff // pDisp->lpVtbl->QueryInterface( pDisp, &IID_ITBasicCallControl, (void**)&pCallControl ); if (FAILED(hr)) { SetLastError(ERROR_INVALID_FUNCTION); return FALSE; } FaxSvcName = SysAllocString( FAX_DISPLAY_NAME ); hr = pCallControl->lpVtbl->HandoffDirect(pCallControl,FaxSvcName); pCallControl->lpVtbl->Release(pCallControl); SysFreeString( FaxSvcName ); if (FAILED(hr)) { DebugPrint((TEXT("call handoff failed, ec = %x"),hr)); return FALSE; } } return TRUE; } WINFAXAPI BOOL WINAPI FaxSendDocumentForBroadcastW( IN HANDLE FaxHandle, IN LPCWSTR FileName, OUT LPDWORD FaxJobId, IN PFAX_RECIPIENT_CALLBACKW FaxRecipientCallback, IN LPVOID Context ) { error_status_t ec; WCHAR TempFile[MAX_PATH]; WCHAR TiffFile[MAX_PATH]; WCHAR CovFileName[MAX_PATH]; WCHAR BodyFileName[MAX_PATH]; WCHAR ExistingFile[MAX_PATH]; DWORD rc; LPWSTR p; FAX_JOB_PARAMW JobParams; FAX_COVERPAGE_INFOW CoverpageInfo; DWORD TmpFaxJobId; DWORD BcFaxJobId = 0; DWORD i = 1; HANDLE hTiff = NULL; TIFF_INFO TiffInfo; DWORD PageCount; if (!ValidateFaxHandle(FaxHandle, FHT_SERVICE)) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } if (!FileName || !FaxRecipientCallback) { SetLastError (ERROR_INVALID_PARAMETER); return FALSE; } // // make sure the file is there // rc = GetFullPathName(FileName,sizeof(ExistingFile)/sizeof(WCHAR),ExistingFile,&p); if (rc > MAX_PATH || rc == 0) { DebugPrint(( TEXT("GetFullPathName failed, ec= %d\n"),GetLastError() )); SetLastError( (rc > MAX_PATH) ? ERROR_BUFFER_OVERFLOW : GetLastError() ); return FALSE; } if (GetFileAttributes(ExistingFile)==0xFFFFFFFF) { SetLastError(ERROR_FILE_NOT_FOUND); return FALSE; } ZeroMemory(TiffFile,sizeof(TiffFile)); if (!CreateFinalTiffFile( (LPWSTR) ExistingFile, TiffFile, NULL)) { DeleteFile( TiffFile ); SetLastError(ERROR_INVALID_DATA); return FALSE; } hTiff = TiffOpen( TiffFile, &TiffInfo, TRUE, FILLORDER_MSB2LSB ); if (hTiff == NULL) { DeleteFile( TiffFile ); SetLastError(ERROR_INVALID_DATA); return FALSE; } PageCount = TiffInfo.PageCount; TiffClose( hTiff ); if (!CopyFileToServerQueue( FaxHandle, TiffFile, BodyFileName )) { DeleteFile( TiffFile ); return FALSE; } // // the passed in file should be treated as read-only // if we created a temp file then delete it // if (wcscmp(ExistingFile,TiffFile) != 0) { DeleteFile( TiffFile ); } ZeroMemory( &JobParams, sizeof(JobParams) ); JobParams.SizeOfStruct = sizeof(JobParams); JobParams.Reserved[0] = 0xfffffffe; JobParams.Reserved[1] = 1; JobParams.Reserved[2] = 0; ec = FAX_SendDocument( FH_FAX_HANDLE(FaxHandle), BodyFileName, &JobParams, &BcFaxJobId ); if (ec) { SetLastError( ec ); return FALSE; } if (FaxJobId) { *FaxJobId = BcFaxJobId; } while (TRUE) { ZeroMemory( &JobParams, sizeof(JobParams) ); JobParams.SizeOfStruct = sizeof(JobParams); ZeroMemory( &CoverpageInfo, sizeof(CoverpageInfo) ); CoverpageInfo.SizeOfStruct = sizeof(CoverpageInfo); if (!FaxRecipientCallback( FaxHandle, i, Context, &JobParams, &CoverpageInfo )) { break; } if (JobParams.RecipientNumber == NULL) { continue; } JobParams.Reserved[0] = 0xfffffffe; JobParams.Reserved[1] = 2; JobParams.Reserved[2] = BcFaxJobId; CoverpageInfo.PageCount = PageCount + 1; GetLocalTime( &CoverpageInfo.TimeSent ); if (CreateCoverpageTiffFile( &CoverpageInfo, TempFile )) { if (CopyFileToServerQueue( FaxHandle, TempFile, CovFileName )) { ec = FAX_SendDocument( FH_FAX_HANDLE(FaxHandle), CovFileName, &JobParams, &TmpFaxJobId ); if (ec) { DeleteFile( TempFile ); SetLastError( ec ); return FALSE; } } DeleteFile( TempFile ); } else { ec = FAX_SendDocument( FH_FAX_HANDLE(FaxHandle), NULL, &JobParams, &TmpFaxJobId ); if (ec) { SetLastError( ec ); return FALSE; } } i += 1; } return TRUE; } BOOL ConvertCoverpageAndJobInfo(PFAX_JOB_PARAMW JobParams,PFAX_COVERPAGE_INFOW CoverpageInfo) { #define MyConvertString(TargetString) if (TargetString) { \ TargetString = AnsiStringToUnicodeString((LPCSTR) TargetString); \ } MyConvertString(JobParams->RecipientNumber); MyConvertString(JobParams->RecipientName); MyConvertString(JobParams->Tsid); MyConvertString(JobParams->SenderName); MyConvertString(JobParams->SenderDept); MyConvertString(JobParams->SenderCompany); MyConvertString(JobParams->BillingCode); MyConvertString(JobParams->DeliveryReportAddress); MyConvertString(JobParams->DocumentName); MyConvertString(CoverpageInfo->CoverPageName); MyConvertString(CoverpageInfo->RecName); MyConvertString(CoverpageInfo->RecFaxNumber); MyConvertString(CoverpageInfo->RecCompany); MyConvertString(CoverpageInfo->RecStreetAddress); MyConvertString(CoverpageInfo->RecCity); MyConvertString(CoverpageInfo->RecState); MyConvertString(CoverpageInfo->RecZip); MyConvertString(CoverpageInfo->RecCountry); MyConvertString(CoverpageInfo->RecTitle); MyConvertString(CoverpageInfo->RecDepartment); MyConvertString(CoverpageInfo->RecOfficeLocation); MyConvertString(CoverpageInfo->RecHomePhone); MyConvertString(CoverpageInfo->RecOfficePhone); MyConvertString(CoverpageInfo->SdrName); MyConvertString(CoverpageInfo->SdrFaxNumber); MyConvertString(CoverpageInfo->SdrCompany); MyConvertString(CoverpageInfo->SdrAddress); MyConvertString(CoverpageInfo->SdrTitle); MyConvertString(CoverpageInfo->SdrDepartment); MyConvertString(CoverpageInfo->SdrOfficeLocation); MyConvertString(CoverpageInfo->SdrHomePhone); MyConvertString(CoverpageInfo->SdrOfficePhone); MyConvertString(CoverpageInfo->Note); MyConvertString(CoverpageInfo->Subject); return TRUE; } BOOL FreeCoverpageAndJobInfo(PFAX_JOB_PARAMW JobParams,PFAX_COVERPAGE_INFOW CoverpageInfo) { #define MyFreeString(TargetString) if (TargetString) { \ MemFree( (LPBYTE) TargetString); \ } MyFreeString(JobParams->RecipientNumber); MyFreeString(JobParams->RecipientName); MyFreeString(JobParams->Tsid); MyFreeString(JobParams->SenderName); MyFreeString(JobParams->SenderDept); MyFreeString(JobParams->SenderCompany); MyFreeString(JobParams->BillingCode); MyFreeString(JobParams->DeliveryReportAddress); MyFreeString(JobParams->DocumentName); MyFreeString(CoverpageInfo->CoverPageName); MyFreeString(CoverpageInfo->RecName); MyFreeString(CoverpageInfo->RecFaxNumber); MyFreeString(CoverpageInfo->RecCompany); MyFreeString(CoverpageInfo->RecStreetAddress); MyFreeString(CoverpageInfo->RecCity); MyFreeString(CoverpageInfo->RecState); MyFreeString(CoverpageInfo->RecZip); MyFreeString(CoverpageInfo->RecCountry); MyFreeString(CoverpageInfo->RecTitle); MyFreeString(CoverpageInfo->RecDepartment); MyFreeString(CoverpageInfo->RecOfficeLocation); MyFreeString(CoverpageInfo->RecHomePhone); MyFreeString(CoverpageInfo->RecOfficePhone); MyFreeString(CoverpageInfo->SdrName); MyFreeString(CoverpageInfo->SdrFaxNumber); MyFreeString(CoverpageInfo->SdrCompany); MyFreeString(CoverpageInfo->SdrAddress); MyFreeString(CoverpageInfo->SdrTitle); MyFreeString(CoverpageInfo->SdrDepartment); MyFreeString(CoverpageInfo->SdrOfficeLocation); MyFreeString(CoverpageInfo->SdrHomePhone); MyFreeString(CoverpageInfo->SdrOfficePhone); MyFreeString(CoverpageInfo->Note); MyFreeString(CoverpageInfo->Subject); return TRUE; } WINFAXAPI BOOL WINAPI FaxSendDocumentForBroadcastA( IN HANDLE FaxHandle, IN LPCSTR FileNameA, OUT LPDWORD FaxJobId, IN PFAX_RECIPIENT_CALLBACKA FaxRecipientCallbackA, IN LPVOID Context ) { error_status_t ec; WCHAR TempFile[MAX_PATH]; WCHAR TiffFile[MAX_PATH]; WCHAR CovFileName[MAX_PATH]; WCHAR BodyFileName[MAX_PATH]; FAX_JOB_PARAMW JobParams; FAX_COVERPAGE_INFOW CoverpageInfo; DWORD TmpFaxJobId; DWORD BcFaxJobId = 0; DWORD i = 1; HANDLE hTiff = NULL; TIFF_INFO TiffInfo; DWORD PageCount; LPWSTR FileName; if (!ValidateFaxHandle(FaxHandle, FHT_SERVICE)) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } if (!FileNameA || !FaxRecipientCallbackA) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } FileName = AnsiStringToUnicodeString(FileNameA); if (!CreateFinalTiffFile( FileName, TiffFile, NULL )) { DeleteFile( TiffFile ); SetLastError(ERROR_INVALID_DATA); return FALSE; } hTiff = TiffOpen( TiffFile, &TiffInfo, TRUE, FILLORDER_MSB2LSB ); if (hTiff == NULL) { DeleteFile( TiffFile ); return FALSE; } PageCount = TiffInfo.PageCount; TiffClose( hTiff ); if (!CopyFileToServerQueue( FaxHandle, TiffFile, BodyFileName )) { DeleteFile( TiffFile ); return FALSE; } // // the passed in file should be treated as read-only // if we created a temp file then delete it // if (wcscmp(FileName,TiffFile) != 0) { DeleteFile( TiffFile ); } ZeroMemory( &JobParams, sizeof(JobParams) ); JobParams.SizeOfStruct = sizeof(JobParams); JobParams.Reserved[0] = 0xfffffffe; JobParams.Reserved[1] = 1; JobParams.Reserved[2] = 0; ec = FAX_SendDocument( FH_FAX_HANDLE(FaxHandle), BodyFileName, &JobParams, &BcFaxJobId ); if (ec) { SetLastError( ec ); return FALSE; } if (FaxJobId) { *FaxJobId = BcFaxJobId; } while (TRUE) { ZeroMemory( &JobParams, sizeof(JobParams) ); JobParams.SizeOfStruct = sizeof(JobParams); ZeroMemory( &CoverpageInfo, sizeof(CoverpageInfo) ); CoverpageInfo.SizeOfStruct = sizeof(CoverpageInfo); if (!FaxRecipientCallbackA( FaxHandle, i, Context, (PFAX_JOB_PARAMA)&JobParams,(PFAX_COVERPAGE_INFOA) &CoverpageInfo )) { break; } if (JobParams.RecipientNumber == NULL) { continue; } ConvertCoverpageAndJobInfo(&JobParams,&CoverpageInfo); JobParams.Reserved[0] = 0xfffffffe; JobParams.Reserved[1] = 2; JobParams.Reserved[2] = BcFaxJobId; CoverpageInfo.PageCount = PageCount + 1; GetLocalTime( &CoverpageInfo.TimeSent ); if (CreateCoverpageTiffFile( &CoverpageInfo, TempFile )) { if (CopyFileToServerQueue( FaxHandle, TempFile, CovFileName )) { ec = FAX_SendDocument( FH_FAX_HANDLE(FaxHandle), CovFileName, &JobParams, &TmpFaxJobId ); if (ec) { DeleteFile( TempFile ); SetLastError( ec ); return FALSE; } } DeleteFile( TempFile ); } else { ec = FAX_SendDocument( FH_FAX_HANDLE(FaxHandle), NULL, &JobParams, &TmpFaxJobId ); if (ec) { SetLastError( ec ); return FALSE; } } i += 1; FreeCoverpageAndJobInfo(&JobParams,&CoverpageInfo); } return TRUE; } BOOL WINAPI FaxSendDocumentA( IN HANDLE FaxHandle, IN LPCSTR FileName, IN FAX_JOB_PARAMA *JobParamsA, IN const FAX_COVERPAGE_INFOA *CoverpageInfoA, OUT LPDWORD FaxJobId ) /*++ Routine Description: Sends a FAX document to the specified recipient. This is an asychronous operation. Use FaxReportStatus to determine when the send is completed. Arguments: FaxHandle - FAX handle obtained from FaxConnectFaxServer. FileName - File containing the TIFF-F FAX document. JobParams - pointer to FAX_JOB_PARAM structure with transmission params CoverpageInfo - optional pointer to FAX_COVERPAGE_INFO structure FaxJobId - receives the Fax JobId for the job. Return Value: TRUE - Success FALSE - Failure, call GetLastError() for more error information. --*/ { error_status_t ec; LPWSTR FileNameW; FAX_JOB_PARAMW JobParamsW; FAX_COVERPAGE_INFOW CoverpageInfoW; if (!FileName || !JobParamsA || JobParamsA->SizeOfStruct != sizeof(FAX_JOB_PARAMA)) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if (CoverpageInfoA && CoverpageInfoA->SizeOfStruct != sizeof(FAX_COVERPAGE_INFOA)) { SetLastError(ERROR_INVALID_DATA); return FALSE; } FileNameW = AnsiStringToUnicodeString( FileName ); if (FileNameW == NULL) { goto exit; } CopyMemory(&JobParamsW, JobParamsA, sizeof(FAX_JOB_PARAMA)); JobParamsW.SizeOfStruct = sizeof(FAX_JOB_PARAMW); JobParamsW.RecipientNumber = AnsiStringToUnicodeString(JobParamsA->RecipientNumber); JobParamsW.RecipientName = AnsiStringToUnicodeString(JobParamsA->RecipientName); JobParamsW.Tsid = AnsiStringToUnicodeString(JobParamsA->Tsid); JobParamsW.SenderName = AnsiStringToUnicodeString(JobParamsA->SenderName); JobParamsW.SenderCompany = AnsiStringToUnicodeString(JobParamsA->SenderCompany); JobParamsW.SenderDept = AnsiStringToUnicodeString(JobParamsA->SenderDept); JobParamsW.BillingCode = AnsiStringToUnicodeString(JobParamsA->BillingCode); JobParamsW.DeliveryReportAddress = AnsiStringToUnicodeString(JobParamsA->DeliveryReportAddress); JobParamsW.DocumentName = AnsiStringToUnicodeString(JobParamsA->DocumentName); if (CoverpageInfoA) { CoverpageInfoW.SizeOfStruct = sizeof(FAX_COVERPAGE_INFOW); CoverpageInfoW.UseServerCoverPage = CoverpageInfoA->UseServerCoverPage; CoverpageInfoW.PageCount = CoverpageInfoA->PageCount; CoverpageInfoW.TimeSent = CoverpageInfoA->TimeSent; CoverpageInfoW.CoverPageName = AnsiStringToUnicodeString( CoverpageInfoA->CoverPageName ); CoverpageInfoW.RecName = AnsiStringToUnicodeString( CoverpageInfoA->RecName ); CoverpageInfoW.RecFaxNumber = AnsiStringToUnicodeString( CoverpageInfoA->RecFaxNumber ); CoverpageInfoW.RecCompany = AnsiStringToUnicodeString( CoverpageInfoA->RecCompany ); CoverpageInfoW.RecStreetAddress = AnsiStringToUnicodeString( CoverpageInfoA->RecStreetAddress ); CoverpageInfoW.RecCity = AnsiStringToUnicodeString( CoverpageInfoA->RecCity ); CoverpageInfoW.RecState = AnsiStringToUnicodeString( CoverpageInfoA->RecState ); CoverpageInfoW.RecZip = AnsiStringToUnicodeString( CoverpageInfoA->RecZip ); CoverpageInfoW.RecCountry = AnsiStringToUnicodeString( CoverpageInfoA->RecCountry ); CoverpageInfoW.RecTitle = AnsiStringToUnicodeString( CoverpageInfoA->RecTitle ); CoverpageInfoW.RecDepartment = AnsiStringToUnicodeString( CoverpageInfoA->RecDepartment ); CoverpageInfoW.RecOfficeLocation = AnsiStringToUnicodeString( CoverpageInfoA->RecOfficeLocation ); CoverpageInfoW.RecHomePhone = AnsiStringToUnicodeString( CoverpageInfoA->RecHomePhone ); CoverpageInfoW.RecOfficePhone = AnsiStringToUnicodeString( CoverpageInfoA->RecOfficePhone ); CoverpageInfoW.SdrName = AnsiStringToUnicodeString( CoverpageInfoA->SdrName ); CoverpageInfoW.SdrFaxNumber = AnsiStringToUnicodeString( CoverpageInfoA->SdrFaxNumber ); CoverpageInfoW.SdrCompany = AnsiStringToUnicodeString( CoverpageInfoA->SdrCompany ); CoverpageInfoW.SdrAddress = AnsiStringToUnicodeString( CoverpageInfoA->SdrAddress ); CoverpageInfoW.SdrTitle = AnsiStringToUnicodeString( CoverpageInfoA->SdrTitle ); CoverpageInfoW.SdrDepartment = AnsiStringToUnicodeString( CoverpageInfoA->SdrDepartment ); CoverpageInfoW.SdrOfficeLocation = AnsiStringToUnicodeString( CoverpageInfoA->SdrOfficeLocation ); CoverpageInfoW.SdrHomePhone = AnsiStringToUnicodeString( CoverpageInfoA->SdrHomePhone ); CoverpageInfoW.SdrOfficePhone = AnsiStringToUnicodeString( CoverpageInfoA->SdrOfficePhone ); CoverpageInfoW.Note = AnsiStringToUnicodeString( CoverpageInfoA->Note ); CoverpageInfoW.Subject = AnsiStringToUnicodeString( CoverpageInfoA->Subject ); } if (FaxSendDocumentW( FaxHandle, FileNameW, &JobParamsW, CoverpageInfoA ? &CoverpageInfoW : NULL, FaxJobId )) { ec = 0; } else { ec = GetLastError(); } exit: MemFree( (LPBYTE) FileNameW ); MemFree( (LPBYTE) JobParamsW.RecipientNumber ); MemFree( (LPBYTE) JobParamsW.RecipientName ); MemFree( (LPBYTE) JobParamsW.Tsid ); MemFree( (LPBYTE) JobParamsW.SenderName ); MemFree( (LPBYTE) JobParamsW.SenderDept ); MemFree( (LPBYTE) JobParamsW.SenderCompany ); MemFree( (LPBYTE) JobParamsW.BillingCode ); MemFree( (LPBYTE) JobParamsW.DeliveryReportAddress ); MemFree( (LPBYTE) JobParamsW.DocumentName ); if (CoverpageInfoA) { MemFree( (LPBYTE) CoverpageInfoW.CoverPageName ); MemFree( (LPBYTE) CoverpageInfoW.RecName ); MemFree( (LPBYTE) CoverpageInfoW.RecFaxNumber ); MemFree( (LPBYTE) CoverpageInfoW.RecCompany ); MemFree( (LPBYTE) CoverpageInfoW.RecStreetAddress ); MemFree( (LPBYTE) CoverpageInfoW.RecCity ); MemFree( (LPBYTE) CoverpageInfoW.RecState ); MemFree( (LPBYTE) CoverpageInfoW.RecZip ); MemFree( (LPBYTE) CoverpageInfoW.RecCountry ); MemFree( (LPBYTE) CoverpageInfoW.RecTitle ); MemFree( (LPBYTE) CoverpageInfoW.RecDepartment ); MemFree( (LPBYTE) CoverpageInfoW.RecOfficeLocation ); MemFree( (LPBYTE) CoverpageInfoW.RecHomePhone ); MemFree( (LPBYTE) CoverpageInfoW.RecOfficePhone ); MemFree( (LPBYTE) CoverpageInfoW.SdrName ); MemFree( (LPBYTE) CoverpageInfoW.SdrFaxNumber ); MemFree( (LPBYTE) CoverpageInfoW.SdrCompany ); MemFree( (LPBYTE) CoverpageInfoW.SdrAddress ); MemFree( (LPBYTE) CoverpageInfoW.SdrTitle ); MemFree( (LPBYTE) CoverpageInfoW.SdrDepartment ); MemFree( (LPBYTE) CoverpageInfoW.SdrOfficeLocation ); MemFree( (LPBYTE) CoverpageInfoW.SdrHomePhone ); MemFree( (LPBYTE) CoverpageInfoW.SdrOfficePhone ); MemFree( (LPBYTE) CoverpageInfoW.Note ); MemFree( (LPBYTE) CoverpageInfoW.Subject ); } if (ec) { SetLastError( ec ); return FALSE; } return TRUE; } BOOL WINAPI FaxAbort( IN HANDLE FaxHandle, IN DWORD JobId ) /*++ Routine Description: Abort the specified FAX job. All outstanding FAX operations are terminated. Arguments: FaxHandle - FAX Server handle obtained from FaxConnectFaxServer. JobId - job id. Return Value: TRUE - Success FALSE - Failure, call GetLastError() for more error information. --*/ { error_status_t ec; // // argument validation // if (!ValidateFaxHandle(FaxHandle, FHT_SERVICE)) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } ec = FAX_Abort( (handle_t) FH_FAX_HANDLE(FaxHandle),(DWORD) JobId ); if (ec) { SetLastError( ec ); return FALSE; } return TRUE; } BOOL WINAPI FaxEnumJobsW( IN HANDLE FaxHandle, OUT PFAX_JOB_ENTRYW *JobEntryBuffer, OUT LPDWORD JobsReturned ) { PFAX_JOB_ENTRYW JobEntry; error_status_t ec; DWORD BufferSize = 0; DWORD i; DWORD Size; if (!ValidateFaxHandle(FaxHandle, FHT_SERVICE)) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } if (!JobEntryBuffer || !JobsReturned) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } *JobEntryBuffer = NULL; *JobsReturned = 0; Size = 0; ec = FAX_EnumJobs( FH_FAX_HANDLE(FaxHandle), (LPBYTE*)JobEntryBuffer, &Size, JobsReturned ); if (ec) { SetLastError( ec ); return FALSE; } JobEntry = (PFAX_JOB_ENTRYW) *JobEntryBuffer; for (i=0; i<*JobsReturned; i++) { FixupStringPtr( JobEntryBuffer, JobEntry[i].UserName ); FixupStringPtr( JobEntryBuffer, JobEntry[i].RecipientNumber ); FixupStringPtr( JobEntryBuffer, JobEntry[i].RecipientName ); FixupStringPtr( JobEntryBuffer, JobEntry[i].DocumentName ); FixupStringPtr( JobEntryBuffer, JobEntry[i].Tsid ); FixupStringPtr( JobEntryBuffer, JobEntry[i].SenderName ); FixupStringPtr( JobEntryBuffer, JobEntry[i].SenderCompany ); FixupStringPtr( JobEntryBuffer, JobEntry[i].SenderDept ); FixupStringPtr( JobEntryBuffer, JobEntry[i].BillingCode ); FixupStringPtr( JobEntryBuffer, JobEntry[i].DeliveryReportAddress ); } return TRUE; } BOOL WINAPI FaxEnumJobsA( IN HANDLE FaxHandle, OUT PFAX_JOB_ENTRYA *JobEntryBuffer, OUT LPDWORD JobsReturned ) { PFAX_JOB_ENTRYW JobEntry; DWORD i; if (!FaxEnumJobsW( FaxHandle, (PFAX_JOB_ENTRYW *)JobEntryBuffer, JobsReturned)) { return FALSE; } JobEntry = (PFAX_JOB_ENTRYW) *JobEntryBuffer; for (i=0; i<*JobsReturned; i++) { ConvertUnicodeStringInPlace( (LPCWSTR) JobEntry[i].UserName ); ConvertUnicodeStringInPlace( (LPCWSTR) JobEntry[i].RecipientNumber ); ConvertUnicodeStringInPlace( (LPCWSTR) JobEntry[i].RecipientName ); ConvertUnicodeStringInPlace( (LPCWSTR) JobEntry[i].DocumentName ); ConvertUnicodeStringInPlace( (LPCWSTR) JobEntry[i].Tsid ); ConvertUnicodeStringInPlace( (LPCWSTR) JobEntry[i].SenderName ); ConvertUnicodeStringInPlace( (LPCWSTR) JobEntry[i].SenderCompany ); ConvertUnicodeStringInPlace( (LPCWSTR) JobEntry[i].SenderDept ); ConvertUnicodeStringInPlace( (LPCWSTR) JobEntry[i].BillingCode ); ConvertUnicodeStringInPlace( (LPCWSTR) JobEntry[i].DeliveryReportAddress ); } return TRUE; } BOOL WINAPI FaxSetJobW( IN HANDLE FaxHandle, IN DWORD JobId, IN DWORD Command, IN const FAX_JOB_ENTRYW *JobEntry ) /*++ Routine Description: set job status information for a requested JobId Note that this is the fax server JobId, not a spooler job ID. Arguments: FaxHandle - FAX handle obtained from FaxConnectFaxServer JobId - Fax service Job ID Command - JC_* constant for controlling the job JobEntry - pointer to Buffer holding the job information Return Value: ERROR_SUCCESS for success, otherwise a WIN32 error code. --*/ { error_status_t ec; // // argument validation // //if (!FaxHandle || !JobEntry || Command > JC_RESTART || Command == JC_UNKNOWN || JobId != JobEntry->JobId) { if (!ValidateFaxHandle(FaxHandle, FHT_SERVICE)) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } if (!JobEntry || Command > JC_RESTART || Command == JC_UNKNOWN) { SetLastError (ERROR_INVALID_PARAMETER); return FALSE; } ec = FAX_SetJob( FH_FAX_HANDLE(FaxHandle), JobId, Command, JobEntry ); if (ec) { SetLastError( ec ); return FALSE; } return TRUE; } BOOL WINAPI FaxSetJobA( IN HANDLE FaxHandle, IN DWORD JobId, IN DWORD Command, IN const FAX_JOB_ENTRYA *JobEntryA ) /*++ Routine Description: set job status information for a requested JobId Note that this is the fax server JobId, not a spooler job ID. Arguments: FaxHandle - FAX handle obtained from FaxConnectFaxServer JobId - Fax service Job ID Command - JC_* constant for controlling the job JobEntryA - pointer to Buffer holding the job information Return Value: ERROR_SUCCESS for success, otherwise a WIN32 error code. --*/ { FAX_JOB_ENTRYW JobEntryW; error_status_t ec = 0; if (!JobEntryA) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } JobEntryW.SizeOfStruct = sizeof(FAX_JOB_ENTRYW); JobEntryW.JobId = JobEntryA->JobId; JobEntryW.UserName = AnsiStringToUnicodeString(JobEntryA->UserName); JobEntryW.JobType = JobEntryA->JobType; JobEntryW.QueueStatus = JobEntryA->QueueStatus; JobEntryW.Status = JobEntryA->Status; JobEntryW.PageCount = JobEntryA->PageCount; JobEntryW.RecipientNumber = AnsiStringToUnicodeString(JobEntryA->RecipientNumber); JobEntryW.RecipientName = AnsiStringToUnicodeString(JobEntryA->RecipientName); JobEntryW.Tsid = AnsiStringToUnicodeString(JobEntryA->Tsid); JobEntryW.SenderName = AnsiStringToUnicodeString(JobEntryA->SenderName); JobEntryW.SenderCompany = AnsiStringToUnicodeString(JobEntryA->SenderCompany); JobEntryW.SenderDept = AnsiStringToUnicodeString(JobEntryA->SenderDept); JobEntryW.BillingCode = AnsiStringToUnicodeString(JobEntryA->BillingCode); JobEntryW.ScheduleAction = JobEntryA->ScheduleAction; JobEntryW.ScheduleTime = JobEntryA->ScheduleTime; JobEntryW.DeliveryReportType = JobEntryA->DeliveryReportType; JobEntryW.DeliveryReportAddress = AnsiStringToUnicodeString(JobEntryA->DeliveryReportAddress); JobEntryW.DocumentName = AnsiStringToUnicodeString(JobEntryA->DocumentName); if (!FaxSetJobW( FaxHandle, JobId, Command, &JobEntryW) ) { ec = GetLastError(); } MemFree( (LPBYTE) JobEntryW.UserName); MemFree( (LPBYTE) JobEntryW.RecipientNumber ); MemFree( (LPBYTE) JobEntryW.RecipientName ); MemFree( (LPBYTE) JobEntryW.Tsid ); MemFree( (LPBYTE) JobEntryW.SenderName ); MemFree( (LPBYTE) JobEntryW.SenderDept ); MemFree( (LPBYTE) JobEntryW.SenderCompany ); MemFree( (LPBYTE) JobEntryW.BillingCode ); MemFree( (LPBYTE) JobEntryW.DeliveryReportAddress ); MemFree( (LPBYTE) JobEntryW.DocumentName ); if (ec != 0) { SetLastError(ec); return FALSE; } return TRUE; } BOOL WINAPI FaxGetJobW( IN HANDLE FaxHandle, IN DWORD JobId, IN PFAX_JOB_ENTRYW *JobEntryBuffer ) /*++ Routine Description: Returns job status information for a requested JobId Note that this is the fax server JobId, not a spooler job ID. Arguments: FaxHandle - FAX handle obtained from FaxConnectFaxServer JobId - Fax service Job ID JobEntryBuffer - Buffer to hold the job information Return Value: ERROR_SUCCESS for success, otherwise a WIN32 error code. --*/ { error_status_t ec = 0; PFAX_JOB_ENTRY JobEntry; DWORD JobEntrySize = 0; // // parameter validation // if (!ValidateFaxHandle(FaxHandle, FHT_SERVICE)) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } if (!JobEntryBuffer) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } *JobEntryBuffer = NULL; ec = FAX_GetJob( FH_FAX_HANDLE(FaxHandle), JobId, (char **) JobEntryBuffer , &JobEntrySize ); if (ec) { SetLastError( ec ); return FALSE; } JobEntry = (PFAX_JOB_ENTRY) *JobEntryBuffer; FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntry->UserName); FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntry->RecipientNumber ); FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntry->RecipientName ); FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntry->Tsid ); FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntry->SenderName ); FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntry->SenderDept ); FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntry->SenderCompany ); FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntry->BillingCode ); FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntry->DeliveryReportAddress ); FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntry->DocumentName ); return TRUE; } BOOL WINAPI FaxGetJobA( IN HANDLE FaxHandle, IN DWORD JobId, IN PFAX_JOB_ENTRYA *JobEntryBuffer ) /*++ Routine Description: Returns job status information for a requested JobId Note that this is the fax server JobId, not a spooler job ID. Arguments: FaxHandle - FAX handle obtained from FaxConnectFaxServer JobId - Fax service Job ID JobEntryBuffer - Buffer to hold the job information Return Value: ERROR_SUCCESS for success, otherwise a WIN32 error code. --*/ { PFAX_JOB_ENTRYW JobEntryW; DWORD JobEntrySize = 0; error_status_t ec = 0; if (!ValidateFaxHandle(FaxHandle, FHT_SERVICE)) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } if (!JobEntryBuffer) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } *JobEntryBuffer = NULL; ec = FAX_GetJob( FH_FAX_HANDLE(FaxHandle), JobId, (char **) JobEntryBuffer,&JobEntrySize ); if (ec) { JobEntryBuffer = NULL; SetLastError(ec); return FALSE; } // // convert to Ansi // JobEntryW = (PFAX_JOB_ENTRYW) *JobEntryBuffer; FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntryW->UserName); FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntryW->RecipientNumber ); FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntryW->RecipientName ); FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntryW->Tsid ); FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntryW->SenderName ); FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntryW->SenderDept ); FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntryW->SenderCompany ); FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntryW->BillingCode ); FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntryW->DeliveryReportAddress ); FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntryW->DocumentName ); ConvertUnicodeStringInPlace( (LPCWSTR)JobEntryW->UserName); ConvertUnicodeStringInPlace( (LPCWSTR)JobEntryW->RecipientNumber ); ConvertUnicodeStringInPlace( (LPCWSTR)JobEntryW->RecipientName ); ConvertUnicodeStringInPlace( (LPCWSTR)JobEntryW->Tsid ); ConvertUnicodeStringInPlace( (LPCWSTR)JobEntryW->SenderName ); ConvertUnicodeStringInPlace( (LPCWSTR)JobEntryW->SenderDept ); ConvertUnicodeStringInPlace( (LPCWSTR)JobEntryW->SenderCompany ); ConvertUnicodeStringInPlace( (LPCWSTR)JobEntryW->BillingCode ); ConvertUnicodeStringInPlace( (LPCWSTR)JobEntryW->DeliveryReportAddress ); ConvertUnicodeStringInPlace( (LPCWSTR)JobEntryW->DocumentName ); return TRUE; } BOOL WINAPI FaxGetPageData( IN HANDLE FaxHandle, IN DWORD JobId, OUT LPBYTE *Buffer, OUT LPDWORD BufferSize, OUT LPDWORD ImageWidth, OUT LPDWORD ImageHeight ) { error_status_t ec; if (!ValidateFaxHandle(FaxHandle, FHT_SERVICE)) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } if (!Buffer || !BufferSize || !ImageWidth || !ImageHeight) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } *Buffer = NULL; *BufferSize = 0; *ImageWidth = 0; *ImageHeight = 0; ec = FAX_GetPageData( FH_FAX_HANDLE(FaxHandle), JobId, Buffer, BufferSize, ImageWidth, ImageHeight ); if (ec) { SetLastError( ec ); return FALSE; } return TRUE; }