/*++ Copyright (c) 1996 Microsoft Corporation Module Name: faxrpc.c Abstract: This module contains the functions that are dispatched as a result of an rpc call. Author: Wesley Witt (wesw) 16-Jan-1996 Revision History: --*/ #include "faxsvc.h" #pragma hdrstop // // version defines // #define WINFAX_MAJOR_VERSION 1803 #define WINFAX_MINOR_VERSION 1 #define WINFAX_VERSION ((WINFAX_MINOR_VERSION<<16) | WINFAX_MAJOR_VERSION) LIST_ENTRY ClientsListHead; CRITICAL_SECTION CsClients; LONG ConnectionCount = 0; // Represents the number of active rpc connections plus the number // of devices with receive enabled. If > zero, the service will not // shut itself down. void * MIDL_user_allocate( IN size_t NumBytes ) { return MemAlloc( NumBytes ); } void MIDL_user_free( IN void *MemPointer ) { MemFree( MemPointer ); } VOID StoreString( LPCTSTR String, PULONG_PTR DestString, LPBYTE Buffer, PULONG_PTR Offset ) { if (String) { _tcscpy( (LPTSTR) (Buffer+*Offset), String ); *DestString = *Offset; *Offset += StringSize( String ); } else { *DestString = 0; } } error_status_t FAX_ConnectionRefCount( handle_t FaxHandle, LPHANDLE FaxConHandle, DWORD Connect, LPDWORD CanShare ) /*++ Routine Description: Called on connect. Maintains an active connection count. Client unbind rpc and the counter is decremented in the rundown routine. Returns a context handle to the client. Arguments: FaxHandle - FAX handle obtained from FaxConnectFaxServer. FaxConHandle - Context handle Connect - 1 if connecting, 0 if disconnecting CanShare - non-zero if sharing is allowed, zero otherwise Return Value: TRUE - Success FALSE - Failure, call GetLastError() for more error information. --*/ { PHANDLE_ENTRY HandleEntry; error_status_t Rval = 0; static int Sharing = -1; if (Sharing == -1) { Sharing = IsProductSuite() ? 1 : 0 ; // If running on SBS or Comm Server, sharing is allowed. } __try { *CanShare = Sharing; if (Connect == 0) { HandleEntry = (PHANDLE_ENTRY) *FaxConHandle; *FaxConHandle = NULL; CloseFaxHandle( HandleEntry ); return 0; } HandleEntry = CreateNewConnectionHandle( FaxHandle ); if (!HandleEntry) { Rval = ERROR_INVALID_HANDLE; _leave; } *FaxConHandle = (HANDLE) HandleEntry; InterlockedIncrement( &ConnectionCount ); } __except (EXCEPTION_EXECUTE_HANDLER) { // // for some reason we crashed, so return the exception code // Rval = GetExceptionCode(); } return Rval; } VOID RPC_FAX_SVC_HANDLE_rundown( IN HANDLE FaxConnectionHandle ) { PHANDLE_ENTRY HandleEntry = (PHANDLE_ENTRY) FaxConnectionHandle; __try { DebugPrint(( TEXT("RPC_FAX_SVC_HANDLE_rundown() running for connection handle 0x%08x"), FaxConnectionHandle )); CloseFaxHandle( HandleEntry ); } __except (EXCEPTION_EXECUTE_HANDLER) { DebugPrint(( TEXT("RPC_FAX_SVC_HANDLE_rundown() crashed, ec=0x%08x"), GetExceptionCode() )); } return; } error_status_t FAX_GetVersion( handle_t FaxHandle, LPDWORD Version ) /*++ Routine Description: Gets the FAX dll's version number. This API is really only used as a ping API. Arguments: FaxHandle - FAX handle obtained from FaxConnectFaxServer. Version - Version number. Return Value: TRUE - Success FALSE - Failure, call GetLastError() for more error information. --*/ { if (!Version) { return ERROR_INVALID_PARAMETER; } *Version = WINFAX_VERSION; return 0; } error_status_t FAX_GetInstallType( IN handle_t FaxHandle, OUT LPDWORD InstallType, OUT LPDWORD InstalledPlatforms, OUT LPDWORD ProductType ) /*++ Routine Description: Gets the FAX dll's version number. This API is really only used as a ping API. Arguments: FaxHandle - FAX handle obtained from FaxConnectFaxServer. Version - Version number. Return Value: TRUE - Success FALSE - Failure, call GetLastError() for more error information. --*/ { DWORD Installed; if ((!GetInstallationInfo( &Installed, InstallType, InstalledPlatforms, ProductType )) || (!Installed)) { return ERROR_INVALID_FUNCTION; } return 0; } error_status_t FAX_OpenPort( handle_t FaxHandle, DWORD DeviceId, DWORD Flags, LPHANDLE FaxPortHandle ) /*++ Routine Description: Opens a fax port for subsequent use in other fax APIs. Arguments: FaxHandle - FAX handle obtained from FaxConnectFaxServer. DeviceId - Requested device id FaxPortHandle - The resulting FAX port handle. Return Value: TRUE - Success FALSE - Failure, call GetLastError() for more error information. --*/ { error_status_t Rval = 0; PLINE_INFO LineInfo; PHANDLE_ENTRY HandleEntry; if (!FaxSvcAccessCheck( SEC_PORT_QUERY, FAX_PORT_QUERY )) { return ERROR_ACCESS_DENIED; } if (!FaxPortHandle) { return ERROR_INVALID_PARAMETER; } EnterCriticalSection( &CsLine ); __try { LineInfo = GetTapiLineFromDeviceId( DeviceId ); if (LineInfo) { if (Flags & PORT_OPEN_MODIFY) { // // the client wants to open the port for modify // access so we must make sure that no other // client already has this port open for modify access // if (IsPortOpenedForModify( LineInfo )) { Rval = ERROR_INVALID_HANDLE; _leave; } } HandleEntry = CreateNewPortHandle( FaxHandle, LineInfo, Flags ); if (!HandleEntry) { Rval = ERROR_INVALID_HANDLE; _leave; } *FaxPortHandle = (HANDLE) HandleEntry; } else { Rval = ERROR_BAD_UNIT; } } __except (EXCEPTION_EXECUTE_HANDLER) { // // for some reason we crashed, so return the exception code // Rval = GetExceptionCode(); } LeaveCriticalSection( &CsLine ); return Rval; } error_status_t FAX_ClosePort( OUT LPHANDLE FaxPortHandle ) /*++ Routine Description: Closes an open FAX port. Arguments: FaxHandle - FAX handle obtained from FaxConnectFaxServer. FaxPortHandle - FAX port handle obtained from FaxOpenPort. Return Value: TRUE - Success FALSE - Failure, call GetLastError() for more error information. --*/ { error_status_t Rval = 0; if (!FaxSvcAccessCheck( SEC_PORT_QUERY, FAX_PORT_QUERY )) { return ERROR_ACCESS_DENIED; } __try { CloseFaxHandle( (PHANDLE_ENTRY) *FaxPortHandle ); *FaxPortHandle = NULL; } __except (EXCEPTION_EXECUTE_HANDLER) { // // for some reason we crashed, so return the exception code // Rval = GetExceptionCode(); } return Rval; } error_status_t FAX_SendDocument( IN handle_t FaxHandle, IN LPCWSTR FileName, IN const FAX_JOB_PARAMW *JobParams, 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 describing transmission FaxJobId - receives job id for this transmission. Return Value: TRUE - Success FALSE - Failure, call GetLastError() for more error information. --*/ { PJOB_QUEUE JobQueue = NULL, JobQueueEntry = NULL; LPCWSTR UserName; WCHAR TifFileName[MAX_PATH]; DWORD rc = ERROR_SUCCESS; // // do a security check // if (!FaxSvcAccessCheck( SEC_JOB_SET, FAX_JOB_SUBMIT )) { return ERROR_ACCESS_DENIED; } // // argument validation // if (!JobParams || !FileName || !FaxJobId || (wcslen(FileName)+wcslen(FaxQueueDir)+2 > MAX_PATH)) { return ERROR_INVALID_PARAMETER; } if (JobParams->Reserved[0] == 0xfffffffe) { if (JobParams->Reserved[1] == 2) { if (JobParams->RecipientNumber == NULL) { return ERROR_INVALID_PARAMETER; } } else if (JobParams->Reserved[1] == 1) { if (FileName == NULL) { return ERROR_INVALID_PARAMETER; } } } else if (JobParams->CallHandle != 0) { if (FileName == NULL || JobParams->RecipientNumber == NULL) { return ERROR_INVALID_PARAMETER; } } // // get the client's user name // UserName = GetClientUserName(); if (!UserName) { return GetLastError(); } // // create a full path to the file // swprintf( TifFileName, L"%s\\%s", FaxQueueDir, FileName ); // // validate the tiff file // rc = ValidateTiffFile(TifFileName); if (rc != ERROR_SUCCESS) { MemFree( (LPBYTE) UserName ); return rc; } // // add the job to the queue // JobQueueEntry = AddJobQueueEntry( JT_SEND, TifFileName, JobParams, UserName, TRUE, NULL ); MemFree( (LPBYTE) UserName ); if (!JobQueueEntry) { return ERROR_INVALID_PARAMETER; } EnterCriticalSection( &CsJob) ; EnterCriticalSection( &CsQueue ); __try { JobQueue = FindJobQueueEntryByJobQueueEntry(JobQueueEntry); if (!JobQueue) { __leave; } if (JobParams->Reserved[0] == 0xffffffff) { CreateFaxEvent( (DWORD)JobParams->Reserved[1], FEI_JOB_QUEUED, JobQueue->JobId ); } else { CreateFaxEvent( 0, FEI_JOB_QUEUED, JobQueue->JobId ); } *FaxJobId = JobQueue->JobId; rc = ERROR_SUCCESS; } __except (EXCEPTION_EXECUTE_HANDLER) { rc = GetExceptionCode(); DebugPrint(( TEXT("FAX_SendDocument() crashed, ec=0x%08x"), rc )); } LeaveCriticalSection( &CsQueue ); LeaveCriticalSection( &CsJob ); return(rc); } error_status_t FAX_GetQueueFileName( IN handle_t FaxHandle, OUT LPTSTR FileName, IN DWORD FileNameSize ) { WCHAR QueueFileName[MAX_PATH]; LPWSTR p; RPC_STATUS ec; ec = RpcImpersonateClient(FaxHandle); if (ec != RPC_S_OK) { DebugPrint(( TEXT("RpcImpersonateClient failed, ec = %d\n"),ec )); return ec; } GenerateUniqueFileName( FaxQueueDir, TEXT("tif"), QueueFileName, sizeof(QueueFileName)/sizeof(WCHAR) ); RpcRevertToSelf(); p = wcsrchr( QueueFileName, L'\\' ); if (p) { p += 1; } else { p = QueueFileName; } wcsncpy( FileName, p , FileNameSize ); return 0; } error_status_t FAX_EnumJobs( IN handle_t FaxHandle, OUT LPBYTE *Buffer, OUT LPDWORD BufferSize, OUT LPDWORD JobsReturned ) /*++ Routine Description: Enumerates jobs. Arguments: FaxHandle - FAX handle obtained from FaxConnectFaxServer. Buffer - Buffer to hold the job information BufferSize - Total size of the job info buffer Return Value: ERROR_SUCCESS for success, otherwise a WIN32 error code. --*/ { PLIST_ENTRY Next; PJOB_QUEUE JobQueue; DWORD rVal = 0; ULONG_PTR Offset = 0; DWORD Size = 0; DWORD Count = 0; PFAX_JOB_ENTRYW JobEntry; if (!FaxSvcAccessCheck( SEC_JOB_SET, FAX_JOB_QUERY )) { return ERROR_ACCESS_DENIED; } if (!Buffer || !BufferSize || !JobsReturned) return ERROR_INVALID_PARAMETER; EnterCriticalSection( &CsJob) ; EnterCriticalSection( &CsQueue ); Next = QueueListHead.Flink; while ((ULONG_PTR)Next != (ULONG_PTR)&QueueListHead) { JobQueue = CONTAINING_RECORD( Next, JOB_QUEUE, ListEntry ); Next = JobQueue->ListEntry.Flink; // don't include broadcast owner jobs, we don't want user to see these if (!( JobQueue->BroadcastJob && JobQueue->BroadcastOwner == NULL ) ) { Count += 1; Size += sizeof(FAX_JOB_ENTRYW); Size += StringSize( JobQueue->UserName ); Size += StringSize( JobQueue->JobParams.RecipientNumber ); Size += StringSize( JobQueue->JobParams.RecipientName ); Size += StringSize( JobQueue->JobParams.Tsid ); Size += StringSize( JobQueue->JobParams.SenderName ); Size += StringSize( JobQueue->JobParams.SenderCompany ); Size += StringSize( JobQueue->JobParams.SenderDept ); Size += StringSize( JobQueue->JobParams.BillingCode ); Size += StringSize( JobQueue->JobParams.DeliveryReportAddress ); Size += StringSize( JobQueue->JobParams.DocumentName ); } } *BufferSize = Size; *Buffer = (LPBYTE) MemAlloc( Size ); if (*Buffer == NULL) { LeaveCriticalSection( &CsQueue ); LeaveCriticalSection( &CsJob ); return ERROR_NOT_ENOUGH_MEMORY; } Offset = sizeof(FAX_JOB_ENTRYW) * Count; JobEntry = (PFAX_JOB_ENTRYW) *Buffer; Next = QueueListHead.Flink; while ((ULONG_PTR)Next != (ULONG_PTR)&QueueListHead) { JobQueue = CONTAINING_RECORD( Next, JOB_QUEUE, ListEntry ); Next = JobQueue->ListEntry.Flink; // don't include broadcast owner jobs, we don't want user to see these if (!( JobQueue->BroadcastJob && JobQueue->BroadcastOwner == NULL ) ) { JobEntry->SizeOfStruct = sizeof(FAX_JOB_ENTRYW); JobEntry->JobId = JobQueue->JobId; JobEntry->JobType = JobQueue->JobType; JobEntry->QueueStatus = JobQueue->JobStatus; if (JobQueue->JobEntry && JobQueue->JobEntry->LineInfo) { JobEntry->Status = JobQueue->JobEntry->LineInfo->State; } else { JobEntry->Status = 0; } JobEntry->ScheduleAction = JobQueue->JobParams.ScheduleAction; JobEntry->DeliveryReportType = JobQueue->DeliveryReportType; FileTimeToSystemTime((LPFILETIME) &JobQueue->ScheduleTime, &JobEntry->ScheduleTime); JobEntry->PageCount = JobQueue->PageCount; JobEntry->Size = JobQueue->FileSize; StoreString( JobQueue->UserName, (PULONG_PTR)&JobEntry->UserName, *Buffer, &Offset ); StoreString( JobQueue->JobParams.RecipientNumber, (PULONG_PTR)&JobEntry->RecipientNumber, *Buffer, &Offset ); StoreString( JobQueue->JobParams.RecipientName, (PULONG_PTR)&JobEntry->RecipientName, *Buffer, &Offset ); StoreString( JobQueue->JobParams.DocumentName, (PULONG_PTR)&JobEntry->DocumentName, *Buffer, &Offset ); StoreString( JobQueue->JobParams.Tsid, (PULONG_PTR)&JobEntry->Tsid, *Buffer, &Offset ); StoreString( JobQueue->JobParams.SenderName, (PULONG_PTR)&JobEntry->SenderName, *Buffer, &Offset ); StoreString( JobQueue->JobParams.SenderCompany, (PULONG_PTR)&JobEntry->SenderCompany, *Buffer, &Offset ); StoreString( JobQueue->JobParams.SenderDept, (PULONG_PTR)&JobEntry->SenderDept, *Buffer, &Offset ); StoreString( JobQueue->JobParams.BillingCode, (PULONG_PTR)&JobEntry->BillingCode, *Buffer, &Offset ); StoreString( JobQueue->JobParams.DeliveryReportAddress, (PULONG_PTR)&JobEntry->DeliveryReportAddress, *Buffer, &Offset ); JobEntry += 1; } } LeaveCriticalSection( &CsQueue ); LeaveCriticalSection( &CsJob ); *JobsReturned = Count; return 0; } DWORD GetJobSize( PJOB_QUEUE JobQueue ) { DWORD Size; Size = sizeof(FAX_JOB_ENTRYW); Size += StringSize( JobQueue->UserName ); Size += StringSize( JobQueue->JobParams.RecipientNumber ); Size += StringSize( JobQueue->JobParams.RecipientName ); Size += StringSize( JobQueue->JobParams.Tsid ); Size += StringSize( JobQueue->JobParams.SenderName ); Size += StringSize( JobQueue->JobParams.SenderCompany ); Size += StringSize( JobQueue->JobParams.SenderDept ); Size += StringSize( JobQueue->JobParams.BillingCode ); Size += StringSize( JobQueue->DeliveryReportAddress ); Size += StringSize( JobQueue->JobParams.DocumentName ); return Size; } VOID GetJobData( LPBYTE JobBuffer, PFAX_JOB_ENTRYW FaxJobEntry, PJOB_QUEUE JobQueue, PULONG_PTR Offset ) { FaxJobEntry->SizeOfStruct = sizeof (FAX_JOB_ENTRYW); FaxJobEntry->JobId = JobQueue->JobId; FaxJobEntry->JobType = JobQueue->JobType; FaxJobEntry->QueueStatus = JobQueue->JobStatus; FaxJobEntry->PageCount = JobQueue->PageCount; FaxJobEntry->Size = JobQueue->FileSize; FaxJobEntry->ScheduleAction = JobQueue->JobParams.ScheduleAction; FaxJobEntry->DeliveryReportType = JobQueue->DeliveryReportType; // // copy the schedule time that the user orginally requested // FileTimeToSystemTime((LPFILETIME) &JobQueue->ScheduleTime, &FaxJobEntry->ScheduleTime); // // get the device status, this job might not be scheduled yet, though. // EnterCriticalSection(&CsJob); __try { if (JobQueue->JobEntry && JobQueue->JobEntry->LineInfo) { FaxJobEntry->Status = JobQueue->JobEntry->LineInfo->State; } } __except (EXCEPTION_EXECUTE_HANDLER) { LeaveCriticalSection(&CsJob); } LeaveCriticalSection(&CsJob); StoreString( JobQueue->UserName, (PULONG_PTR)&FaxJobEntry->UserName, JobBuffer, Offset ); StoreString( JobQueue->JobParams.RecipientNumber, (PULONG_PTR)&FaxJobEntry->RecipientNumber, JobBuffer, Offset ); StoreString( JobQueue->JobParams.RecipientName, (PULONG_PTR)&FaxJobEntry->RecipientName, JobBuffer, Offset ); StoreString( JobQueue->JobParams.Tsid, (PULONG_PTR)&FaxJobEntry->Tsid, JobBuffer, Offset ); StoreString( JobQueue->JobParams.SenderName, (PULONG_PTR)&FaxJobEntry->SenderName, JobBuffer, Offset ); StoreString( JobQueue->JobParams.SenderCompany, (PULONG_PTR)&FaxJobEntry->SenderCompany, JobBuffer, Offset ); StoreString( JobQueue->JobParams.SenderDept, (PULONG_PTR)&FaxJobEntry->SenderDept, JobBuffer, Offset ); StoreString( JobQueue->JobParams.BillingCode, (PULONG_PTR)&FaxJobEntry->BillingCode, JobBuffer, Offset ); StoreString( JobQueue->DeliveryReportAddress, (PULONG_PTR)&FaxJobEntry->DeliveryReportAddress, JobBuffer, Offset ); StoreString( JobQueue->JobParams.DocumentName, (PULONG_PTR)&FaxJobEntry->DocumentName, JobBuffer, Offset ); return; } error_status_t FAX_GetJob( IN handle_t FaxHandle, IN DWORD JobId, OUT LPBYTE *Buffer, OUT LPDWORD BufferSize ) { PJOB_QUEUE JobQueue; ULONG_PTR Offset = sizeof(FAX_JOB_ENTRYW); DWORD Rval = 0; if (!FaxSvcAccessCheck( SEC_JOB_SET, FAX_JOB_QUERY )) { return ERROR_ACCESS_DENIED; } EnterCriticalSection( &CsJob ); EnterCriticalSection( &CsQueue ); JobQueue = FindJobQueueEntry( JobId ); // don't include broadcast owner jobs, we don't want user to see these if (!JobQueue || (JobQueue->BroadcastJob && JobQueue->BroadcastOwner == NULL) ) { Rval = ERROR_INVALID_PARAMETER; goto exit; } __try { *BufferSize = GetJobSize(JobQueue); *Buffer = MemAlloc( *BufferSize ); if (!*Buffer) { Rval = ERROR_NOT_ENOUGH_MEMORY; goto exit; } GetJobData(*Buffer,(PFAX_JOB_ENTRYW) *Buffer,JobQueue,&Offset); } __except (EXCEPTION_EXECUTE_HANDLER) { Rval = GetExceptionCode(); } exit: LeaveCriticalSection( &CsQueue ); LeaveCriticalSection( &CsJob ); return Rval; } BOOL UserOwnsJob( PJOB_QUEUE JobQueue ) { LPWSTR UserName = GetClientUserName(); BOOL RetVal = FALSE; if (JobQueue && JobQueue->UserName && (wcscmp(UserName,JobQueue->UserName)==0) ) { RetVal = TRUE; } MemFree( UserName ); return RetVal; } error_status_t FAX_SetJob( IN handle_t FaxHandle, IN DWORD JobId, IN DWORD Command, IN const FAX_JOB_ENTRYW *JobEntry ) { PJOB_QUEUE JobQueue; DWORD Rval = 0; BOOL bAccess = TRUE; if (!FaxSvcAccessCheck( SEC_JOB_SET, FAX_JOB_MANAGE )) { bAccess = FALSE; } if (!JobEntry) { return ERROR_INVALID_PARAMETER; } // // handle abort case up here because we aquire must aquire additional critical sections to avoid deadlock // if (Command == JC_DELETE) { Rval = FAX_Abort(FaxHandle,JobId); } else { EnterCriticalSection( &CsQueue ); JobQueue = FindJobQueueEntry( JobId ); // don't include broadcast owner jobs, we don't want user to see these if (!JobQueue || (JobQueue->BroadcastJob && JobQueue->BroadcastOwner == NULL) ) { Rval = ERROR_INVALID_PARAMETER; goto exit; } if (!bAccess && !UserOwnsJob( JobQueue ) ) { Rval = ERROR_ACCESS_DENIED; goto exit; } switch (Command) { case JC_UNKNOWN: Rval = ERROR_INVALID_PARAMETER; goto exit; break; /* * This case is handled above... * case JC_DELETE: * Rval = FAX_Abort(FaxHandle,JobId); * break; */ case JC_PAUSE: PauseJobQueueEntry( JobQueue ); break; case JC_RESUME: ResumeJobQueueEntry( JobQueue ); break; default: Rval = ERROR_INVALID_PARAMETER; goto exit; break; } exit: LeaveCriticalSection( &CsQueue ); } return Rval; } error_status_t FAX_GetPageData( IN handle_t FaxHandle, IN DWORD JobId, OUT LPBYTE *Buffer, OUT LPDWORD BufferSize, OUT LPDWORD ImageWidth, OUT LPDWORD ImageHeight ) { PJOB_QUEUE JobQueue; LPBYTE TiffBuffer; if (!FaxSvcAccessCheck( SEC_JOB_SET, FAX_JOB_QUERY )) { return ERROR_ACCESS_DENIED; } if (!Buffer || !BufferSize || !ImageWidth || !ImageHeight) { return ERROR_INVALID_PARAMETER; } EnterCriticalSection( &CsQueue ); JobQueue = FindJobQueueEntry( JobId ); if (!JobQueue) { LeaveCriticalSection( &CsQueue ); return ERROR_INVALID_PARAMETER; } if (JobQueue->JobType != JT_SEND) { LeaveCriticalSection( &CsQueue ); return ERROR_INVALID_DATA; } TiffExtractFirstPage( JobQueue->FileName, &TiffBuffer, BufferSize, ImageWidth, ImageHeight ); LeaveCriticalSection( &CsQueue ); *Buffer = (LPBYTE) MemAlloc( *BufferSize ); if (*Buffer == NULL) { VirtualFree( TiffBuffer, *BufferSize, MEM_RELEASE); return ERROR_NOT_ENOUGH_MEMORY; } CopyMemory( *Buffer, TiffBuffer, *BufferSize ); VirtualFree( TiffBuffer, *BufferSize, MEM_RELEASE); return 0; } error_status_t FAX_GetDeviceStatus( IN HANDLE FaxPortHandle, OUT LPBYTE *StatusBuffer, OUT LPDWORD BufferSize ) /*++ Routine Description: Obtains a status report for the specified FAX job. Arguments: FaxHandle - FAX handle obtained from FaxConnectFaxServer. StatusBuffer - receives FAX_DEVICE_STATUS pointer BufferSize - Pointer to the size of this structure Return Value: TRUE - Success FALSE - Failure, call GetLastError() for more error information. --*/ { DWORD rVal = 0; ULONG_PTR Offset; PFAX_DEVICE_STATUS FaxStatus; PLINE_INFO LineInfo = ((PHANDLE_ENTRY)FaxPortHandle)->LineInfo; if (!FaxSvcAccessCheck( SEC_PORT_QUERY, FAX_PORT_QUERY )) { return ERROR_ACCESS_DENIED; } if (!LineInfo) { return ERROR_INVALID_DATA; } __try { EnterCriticalSection( &CsJob ); EnterCriticalSection( &CsLine ); // // count the number of bytes required // *BufferSize = sizeof(FAX_DEVICE_STATUS); *BufferSize += StringSize( LineInfo->DeviceName ); *BufferSize += StringSize( LineInfo->Csid ); if (LineInfo->JobEntry) { *BufferSize += StringSize( LineInfo->JobEntry->PhoneNumber ); *BufferSize += StringSize( LineInfo->JobEntry->FaxStatus.CallerId ); *BufferSize += StringSize( LineInfo->JobEntry->FaxStatus.RoutingInfo ); *BufferSize += StringSize( LineInfo->JobEntry->FaxStatus.CSI ); *BufferSize += StringSize( LineInfo->JobEntry->JobParam.SenderName ); *BufferSize += StringSize( LineInfo->JobEntry->JobParam.RecipientName ); *BufferSize += StringSize( LineInfo->JobEntry->UserName ); } *StatusBuffer = (LPBYTE) MemAlloc( *BufferSize ); if (*StatusBuffer == NULL) { rVal = ERROR_NOT_ENOUGH_MEMORY; goto exit; } FaxStatus = (PFAX_DEVICE_STATUS) *StatusBuffer; Offset = sizeof(FAX_DEVICE_STATUS); FaxStatus->SizeOfStruct = sizeof(FAX_DEVICE_STATUS); FaxStatus->Status = LineInfo->State; FaxStatus->DeviceId = LineInfo->PermanentLineID; FaxStatus->StatusString = NULL; StoreString( LineInfo->DeviceName, (PULONG_PTR)&FaxStatus->DeviceName, *StatusBuffer, &Offset ); StoreString( LineInfo->Csid, (PULONG_PTR)&FaxStatus->Csid, *StatusBuffer, &Offset ); if (LineInfo->JobEntry) { FaxStatus->JobType = LineInfo->JobEntry->JobType; FaxStatus->TotalPages = LineInfo->JobEntry->PageCount; FaxStatus->Size = FaxStatus->JobType == JT_SEND ? LineInfo->JobEntry->FileSize : 0; //meaningful for an outbound job only FaxStatus->DocumentName = NULL; ZeroMemory( &FaxStatus->SubmittedTime, sizeof(FILETIME) ); StoreString( LineInfo->JobEntry->JobParam.SenderName, (PULONG_PTR)&FaxStatus->SenderName, *StatusBuffer, &Offset ); StoreString( LineInfo->JobEntry->JobParam.RecipientName, (PULONG_PTR)&FaxStatus->RecipientName, *StatusBuffer, &Offset ); FaxStatus->CurrentPage = LineInfo->JobEntry->FaxStatus.PageCount; CopyMemory(&FaxStatus->StartTime, &LineInfo->JobEntry->StartTime, sizeof(FILETIME)); StoreString( LineInfo->JobEntry->PhoneNumber, (PULONG_PTR)&FaxStatus->PhoneNumber, *StatusBuffer, &Offset ); StoreString( LineInfo->JobEntry->FaxStatus.CallerId, (PULONG_PTR)&FaxStatus->CallerId, *StatusBuffer, &Offset ); StoreString( LineInfo->JobEntry->FaxStatus.RoutingInfo, (PULONG_PTR)&FaxStatus->RoutingString, *StatusBuffer, &Offset ); StoreString( LineInfo->JobEntry->FaxStatus.CSI, (PULONG_PTR)&FaxStatus->Tsid, *StatusBuffer, &Offset ); StoreString( LineInfo->JobEntry->UserName, (PULONG_PTR)&FaxStatus->UserName, *StatusBuffer, &Offset ); } else { FaxStatus->PhoneNumber = NULL; FaxStatus->CallerId = NULL; FaxStatus->RoutingString = NULL; FaxStatus->CurrentPage = 0; FaxStatus->JobType = 0; FaxStatus->TotalPages = 0; FaxStatus->Size = 0; FaxStatus->DocumentName = NULL; FaxStatus->SenderName = NULL; FaxStatus->RecipientName = NULL; FaxStatus->Tsid = NULL; ZeroMemory( &FaxStatus->SubmittedTime, sizeof(FILETIME) ); ZeroMemory( &FaxStatus->StartTime, sizeof(FILETIME) ); } } __except (EXCEPTION_EXECUTE_HANDLER) { // // for some reason we crashed, so return the exception code // rVal = GetExceptionCode(); } exit: LeaveCriticalSection( &CsLine ); LeaveCriticalSection( &CsJob ); return rVal; } error_status_t FAX_Abort( IN handle_t hBinding, IN DWORD JobId ) /*++ Routine Description: Abort the specified FAX job. All outstanding FAX operations are terminated. Arguments: hBinding - FAX handle obtained from FaxConnectFaxServer. JobId - FAX job Id Return Value: TRUE - Success FALSE - Failure, call GetLastError() for more error information. --*/ { PJOB_QUEUE JobQueueEntry; BOOL bAccess = TRUE; DWORD Rval; if (!FaxSvcAccessCheck( SEC_JOB_SET, FAX_JOB_MANAGE )) { bAccess = FALSE; } EnterCriticalSection( &CsJob) ; EnterCriticalSection( &CsQueue ); JobQueueEntry = FindJobQueueEntry( JobId ); if (!JobQueueEntry) { Rval = ERROR_INVALID_PARAMETER; goto exit; } // don't include broadcast owner jobs, we don't want user to see these if (!JobQueueEntry || (JobQueueEntry->BroadcastJob && JobQueueEntry->BroadcastOwner == NULL) ) { Rval = ERROR_INVALID_PARAMETER; goto exit; } if (!bAccess && !UserOwnsJob( JobQueueEntry ) ) { Rval = ERROR_ACCESS_DENIED; goto exit; } // // abort the job if it's in progress // if (((JobQueueEntry->JobStatus & JS_INPROGRESS) == JS_INPROGRESS) && ( JobQueueEntry->JobType == JT_SEND || JobQueueEntry->JobType == JT_RECEIVE )) { __try { // signal the event we may be waiting on if (JobQueueEntry->JobEntry->hCallHandleEvent) { JobQueueEntry->JobEntry->LineInfo->HandoffCallHandle = 0; SetEvent(JobQueueEntry->JobEntry->hCallHandleEvent); } JobQueueEntry->JobEntry->Aborting = TRUE; JobQueueEntry->JobStatus = JS_DELETING; CreateFaxEvent(JobQueueEntry->JobEntry->LineInfo->PermanentLineID, FEI_ABORTING, JobId); DebugPrint(( TEXT("Attempting FaxDevAbort for job\n") )); JobQueueEntry->JobEntry->LineInfo->Provider->FaxDevAbortOperation( (HANDLE) JobQueueEntry->JobEntry->InstanceData ); } __except (EXCEPTION_EXECUTE_HANDLER) { JobQueueEntry->JobEntry->ErrorCode = GetExceptionCode(); } } else { RemoveJobQueueEntry( JobQueueEntry ); } Rval = 0; exit: LeaveCriticalSection( &CsQueue ); LeaveCriticalSection( &CsJob ); return Rval; } error_status_t FAX_GetConfiguration( IN handle_t FaxHandle, OUT LPBYTE *Buffer, IN LPDWORD BufferSize ) /*++ Routine Description: Retrieves the FAX configuration from the FAX server. The SizeOfStruct in the FaxConfig argument MUST be set to a value == sizeof(FAX_CONFIGURATION). If the BufferSize is not big enough, return an error and set BytesNeeded to the required size. Arguments: FaxHandle - FAX handle obtained from FaxConnectFaxServer. Buffer - Pointer to a FAX_CONFIGURATION structure. BufferSize - Size of Buffer BytesNeeded - Number of bytes needed Return Value: TRUE - Success FALSE - Failure, call GetLastError() for more error information. --*/ { error_status_t rVal = ERROR_SUCCESS; PFAX_CONFIGURATION FaxConfig; ULONG_PTR Offset; if (!FaxSvcAccessCheck( SEC_CONFIG_QUERY, FAX_CONFIG_QUERY )) { return ERROR_ACCESS_DENIED; } if (!Buffer || !BufferSize) return ERROR_INVALID_PARAMETER; // // count up the number of bytes needed // *BufferSize = sizeof(FAX_CONFIGURATION); Offset = sizeof(FAX_CONFIGURATION); if (InboundProfileName) { *BufferSize += StringSize( InboundProfileName ); } if (ArchiveDirectory) { *BufferSize += StringSize( ArchiveDirectory ); } *Buffer = MemAlloc( *BufferSize ); if (*Buffer == NULL) { return ERROR_NOT_ENOUGH_MEMORY; } FaxConfig = (PFAX_CONFIGURATION)*Buffer; FaxConfig->SizeOfStruct = sizeof(FAX_CONFIGURATION); FaxConfig->Retries = FaxSendRetries; FaxConfig->RetryDelay = FaxSendRetryDelay; FaxConfig->DirtyDays = FaxDirtyDays; FaxConfig->Branding = FaxUseBranding; FaxConfig->UseDeviceTsid = FaxUseDeviceTsid; FaxConfig->ServerCp = ServerCp; FaxConfig->StartCheapTime.Hour = StartCheapTime.Hour; FaxConfig->StartCheapTime.Minute = StartCheapTime.Minute; FaxConfig->StopCheapTime.Hour = StopCheapTime.Hour; FaxConfig->StopCheapTime.Minute = StopCheapTime.Minute; FaxConfig->ArchiveOutgoingFaxes = ArchiveOutgoingFaxes; FaxConfig->PauseServerQueue = QueuePaused; StoreString( ArchiveDirectory, (PULONG_PTR)&FaxConfig->ArchiveDirectory, *Buffer, &Offset ); StoreString( InboundProfileName, (PULONG_PTR)&FaxConfig->InboundProfile, *Buffer, &Offset ); return rVal; } error_status_t FAX_SetConfiguration( IN handle_t FaxHandle, IN const FAX_CONFIGURATION *FaxConfig ) /*++ Routine Description: Changes the FAX configuration on the FAX server. The SizeOfStruct in the FaxConfig argument MUST be set to a value == sizeof(FAX_CONFIGURATION). Arguments: FaxHandle - FAX handle obtained from FaxConnectFaxServer. Buffer - Pointer to a FAX_CONFIGURATION structure. BufferSize - Size of Buffer Return Value: TRUE - Success FALSE - Failure, call GetLastError() for more error information. --*/ { error_status_t rVal = ERROR_SUCCESS; LPTSTR s; if (!FaxSvcAccessCheck( SEC_CONFIG_SET, FAX_CONFIG_SET )) { return ERROR_ACCESS_DENIED; } if (!FaxConfig || FaxConfig->SizeOfStruct != sizeof(FAX_CONFIGURATION)) { return ERROR_INVALID_PARAMETER; } if (FaxConfig->ArchiveOutgoingFaxes) { // // make sure they give us something valid for a path if they want us to archive // if (!FaxConfig->ArchiveDirectory) { return ERROR_INVALID_PARAMETER; } } __try { if (FaxConfig->InboundProfile) { if (!InboundProfileName || wcscmp(FaxConfig->InboundProfile,InboundProfileName) != 0) { // // profile has changed, let's use the new one. // InboundProfileInfo = AddNewMapiProfile( FaxConfig->InboundProfile, TRUE, FALSE ); if (!InboundProfileInfo) { return ERROR_INVALID_DATA; } } } s = (LPTSTR) InterlockedExchangePointer( (LPVOID *)&InboundProfileName, FaxConfig->InboundProfile ? (PVOID)StringDup( FaxConfig->InboundProfile ) : NULL ); if (s) { MemFree( s ); } // // change the values that the server is currently using // InterlockedExchange( &FaxUseDeviceTsid, FaxConfig->UseDeviceTsid ); InterlockedExchange( &FaxUseBranding, FaxConfig->Branding ); InterlockedExchange( &ServerCp, FaxConfig->ServerCp ); InterlockedExchange( &ArchiveOutgoingFaxes, FaxConfig->ArchiveOutgoingFaxes ); InterlockedExchange( &FaxSendRetries, FaxConfig->Retries ); InterlockedExchange( &FaxDirtyDays, FaxConfig->DirtyDays ); InterlockedExchange( &FaxSendRetryDelay, FaxConfig->RetryDelay ); if ( (MAKELONG(StartCheapTime.Hour,StartCheapTime.Minute) != MAKELONG(FaxConfig->StartCheapTime.Hour,FaxConfig->StartCheapTime.Minute)) || (MAKELONG(StopCheapTime.Hour,StopCheapTime.Minute) != MAKELONG(FaxConfig->StopCheapTime.Hour, FaxConfig->StopCheapTime.Minute )) ) { InterlockedExchange( (LPLONG)&StartCheapTime, MAKELONG(FaxConfig->StartCheapTime.Hour,FaxConfig->StartCheapTime.Minute) ); InterlockedExchange( (LPLONG)&StopCheapTime, MAKELONG(FaxConfig->StopCheapTime.Hour,FaxConfig->StopCheapTime.Minute) ); SortJobQueue(); } s = (LPTSTR) InterlockedExchangePointer( (LPVOID *)&ArchiveDirectory, FaxConfig->ArchiveDirectory ? (PVOID)StringDup( FaxConfig->ArchiveDirectory ) : NULL ); if (s) { MemFree( s ); } if (FaxConfig->PauseServerQueue) { PauseServerQueue(); } else { ResumeServerQueue(); } // // change the values in the registry // SetFaxGlobalsRegistry( (PFAX_CONFIGURATION) FaxConfig ); } __except (EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode(); } return ERROR_SUCCESS; } DWORD GetPortSize( PLINE_INFO LineInfo ) { DWORD Size; Size = sizeof(FAX_PORT_INFOW); Size += StringSize( LineInfo->DeviceName ); Size += StringSize( LineInfo->Tsid ); Size += StringSize( LineInfo->Csid ); return Size; } VOID GetPortData( LPBYTE PortBuffer, PFAX_PORT_INFOW PortInfo, PLINE_INFO LineInfo, PULONG_PTR Offset ) { PortInfo->SizeOfStruct = sizeof(FAX_PORT_INFOW); PortInfo->DeviceId = LineInfo->PermanentLineID; PortInfo->State = LineInfo->State; PortInfo->Flags = LineInfo->Flags & 0x0fffffff; PortInfo->Rings = LineInfo->RingsForAnswer; PortInfo->Priority = LineInfo->Priority; StoreString( LineInfo->DeviceName, (PULONG_PTR)&PortInfo->DeviceName, PortBuffer, Offset ); StoreString( LineInfo->Tsid, (PULONG_PTR)&PortInfo->Tsid, PortBuffer, Offset ); StoreString( LineInfo->Csid, (PULONG_PTR)&PortInfo->Csid, PortBuffer, Offset ); return; } error_status_t FAX_EnumPorts( handle_t FaxHandle, LPBYTE *PortBuffer, LPDWORD BufferSize, LPDWORD PortsReturned ) /*++ Routine Description: Enumerates all of the FAX devices attached to the FAX server. The port state information is returned for each device. Arguments: FaxHandle - FAX handle obtained from FaxConnectFaxServer PortBuffer - Buffer to hold the port information BufferSize - Total size of the port info buffer PortsReturned - The number of ports in the buffer Return Value: ERROR_SUCCESS for success, otherwise a WIN32 error code. --*/ { DWORD rVal = 0; PLIST_ENTRY Next; PLINE_INFO LineInfo; DWORD i; ULONG_PTR Offset; DWORD FaxDevices; PFAX_PORT_INFOW PortInfo; if (!FaxSvcAccessCheck( SEC_PORT_QUERY, FAX_PORT_QUERY )) { return ERROR_ACCESS_DENIED; } __try { EnterCriticalSection( &CsLine ); if (!PortsReturned) { rVal = ERROR_INVALID_PARAMETER; goto exit; } if (!TapiLinesListHead.Flink) { rVal = ERROR_INVALID_PARAMETER; goto exit; } Next = TapiLinesListHead.Flink; *PortsReturned = 0; *BufferSize = 0; FaxDevices = 0; // // count the number of bytes required // *BufferSize = 0; while ((ULONG_PTR)Next != (ULONG_PTR)&TapiLinesListHead) { LineInfo = CONTAINING_RECORD( Next, LINE_INFO, ListEntry ); Next = LineInfo->ListEntry.Flink; if (LineInfo->PermanentLineID && LineInfo->DeviceName) { *BufferSize += sizeof(PFAX_PORT_INFOW); *BufferSize += GetPortSize( LineInfo ); FaxDevices += 1; } } *PortBuffer = (LPBYTE) MemAlloc( *BufferSize ); if (*PortBuffer == NULL) { rVal = ERROR_NOT_ENOUGH_MEMORY; goto exit; } PortInfo = (PFAX_PORT_INFOW) *PortBuffer; Offset = FaxDevices * sizeof(FAX_PORT_INFOW); Next = TapiLinesListHead.Flink; i = 0; while ((ULONG_PTR)Next != (ULONG_PTR)&TapiLinesListHead) { LineInfo = CONTAINING_RECORD( Next, LINE_INFO, ListEntry ); Next = LineInfo->ListEntry.Flink; if (LineInfo->PermanentLineID && LineInfo->DeviceName) { GetPortData( *PortBuffer, &PortInfo[i], LineInfo, &Offset ); } i++; } // // set the device count // *PortsReturned = FaxDevices; } __except (EXCEPTION_EXECUTE_HANDLER) { // // for some reason we crashed, so return the exception code // rVal = GetExceptionCode(); } exit: LeaveCriticalSection( &CsLine ); return rVal; } error_status_t FAX_GetPort( HANDLE FaxPortHandle, LPBYTE *PortBuffer, LPDWORD BufferSize ) /*++ Routine Description: Returns port status information for a requested port. The device id passed in should be optained from FAXEnumPorts. Arguments: FaxHandle - FAX handle obtained from FaxConnectFaxServer. DeviceId - TAPI device id PortBuffer - Buffer to hold the port information BufferSize - Total size of the port info buffer Return Value: ERROR_SUCCESS for success, otherwise a WIN32 error code. --*/ { PLINE_INFO LineInfo = ((PHANDLE_ENTRY)FaxPortHandle)->LineInfo; DWORD rVal = 0; ULONG_PTR Offset; if (!FaxSvcAccessCheck( SEC_PORT_QUERY, FAX_PORT_QUERY )) { return ERROR_ACCESS_DENIED; } if (!LineInfo) { return ERROR_INVALID_DATA; } EnterCriticalSection( &CsLine ); __try { // // calculate the required buffer size // *BufferSize = GetPortSize( LineInfo ); *PortBuffer = (LPBYTE) MemAlloc( *BufferSize ); if (*PortBuffer == NULL) { rVal = ERROR_NOT_ENOUGH_MEMORY; _leave; } Offset = sizeof(FAX_PORT_INFOW); GetPortData( *PortBuffer, (PFAX_PORT_INFO)*PortBuffer, LineInfo, &Offset ); } __except (EXCEPTION_EXECUTE_HANDLER) { // // for some reason we crashed, so return the exception code // rVal = GetExceptionCode(); } LeaveCriticalSection( &CsLine ); return rVal; } error_status_t FAX_SetPort( HANDLE FaxPortHandle, const FAX_PORT_INFOW *PortInfo ) /*++ Routine Description: Changes the port capability mask. This allows the caller to enable or disable sending & receiving on a port basis. Arguments: FaxHandle - FAX handle obtained from FaxConnectFaxServer. PortBuffer - Buffer to hold the port information BufferSize - Total size of the port info buffer Return Value: ERROR_SUCCESS for success, otherwise a WIN32 error code. --*/ { DWORD rVal = 0; DWORD flags = 0; PLINE_INFO LineInfo = ((PHANDLE_ENTRY)FaxPortHandle)->LineInfo; DWORD totalDevices; BOOL SendEnabled = FALSE; if (!FaxSvcAccessCheck( SEC_PORT_SET, FAX_PORT_SET )) { return ERROR_ACCESS_DENIED; } if (!LineInfo) { return ERROR_INVALID_DATA; } EnterCriticalSection( &CsJob ); EnterCriticalSection( &CsLine ); __try { if (PortInfo->SizeOfStruct != sizeof(FAX_PORT_INFOW)) { rVal = ERROR_INVALID_PARAMETER; _leave; } // // HACK: we allow the ring count to be set even if the line is in use so that systray will work. we don't allow // the user to change things like CSID/TSID or tapi related information since that cannot change until the call // transaction is complete. // LineInfo->RingsForAnswer = PortInfo->Rings; if (LineInfo->JobEntry) { // // changing a line while there is an outstanding // job is not allowed // rVal = ERROR_DEVICE_IN_USE; _leave; } if (LineInfo->Flags & 0x80000000) { _leave; } flags = PortInfo->Flags & (FPF_RECEIVE | FPF_SEND | FPF_VIRTUAL); // // first change the real time data that the server is using // if ((!(LineInfo->Flags & FPF_RECEIVE)) && (flags & FPF_RECEIVE)) { if (!OpenTapiLine( LineInfo )) { DebugPrint(( TEXT("Could not get an open tapi line, FAX_SetPort() failed") )); } else { InterlockedIncrement( &ConnectionCount ); } } else if ((LineInfo->Flags & FPF_RECEIVE) && (!(flags & FPF_RECEIVE))) { EnterCriticalSection( &CsLine ); if (LineInfo->hLine) { lineClose( LineInfo->hLine ); LineInfo->hLine = 0; InterlockedDecrement( &ConnectionCount ); } LeaveCriticalSection( &CsLine ); } if (!(LineInfo->Flags & FPF_SEND) && (flags & FPF_SEND)) { SendEnabled = TRUE; } LineInfo->Flags = (LineInfo->Flags & ~FPF_CLIENT_BITS) | flags; LineInfo->RingsForAnswer = PortInfo->Rings; // // make sure the user sets a reasonable priority // totalDevices = GetFaxDeviceCount(); if (PortInfo->Priority <= totalDevices) { LineInfo->Priority = PortInfo->Priority ; } if (PortInfo->Tsid) { MemFree( LineInfo->Tsid ); LineInfo->Tsid = StringDup( PortInfo->Tsid ); } if (PortInfo->Csid) { MemFree( LineInfo->Csid ); LineInfo->Csid = StringDup( PortInfo->Csid ); } SortDevicePriorities(); // // now change the registry so it sticks // (need to change all devices, since the priority may have changed) // CommitDeviceChanges(); // // update virtual devices if they changed // UpdateVirtualDevices(); } __except (EXCEPTION_EXECUTE_HANDLER) { // // for some reason we crashed, so return the exception code // rVal = GetExceptionCode(); } LeaveCriticalSection( &CsLine ); LeaveCriticalSection( &CsJob ); if (SendEnabled && JobQueueSemaphore) { ReleaseSemaphore( JobQueueSemaphore, 1, NULL ); } return rVal; } typedef struct _ENUM_CONTEXT { DWORD Function; DWORD Size; ULONG_PTR Offset; PLINE_INFO LineInfo; PFAX_ROUTING_METHOD RoutingInfoMethod; } ENUM_CONTEXT, *PENUM_CONTEXT; BOOL CALLBACK RoutingMethodEnumerator( PROUTING_METHOD RoutingMethod, PENUM_CONTEXT EnumContext ) { LPWSTR GuidString; // // we only access read-only static data in the LINE_INFO structure. // make sure that this access is protected if you access dynamic // data in the future. // if (EnumContext->Function == 1) { EnumContext->Size += sizeof(FAX_ROUTING_METHOD); StringFromIID( &RoutingMethod->Guid, &GuidString ); EnumContext->Size += StringSize( GuidString ); EnumContext->Size += StringSize( EnumContext->LineInfo->DeviceName ); EnumContext->Size += StringSize( RoutingMethod->FunctionName ); EnumContext->Size += StringSize( RoutingMethod->FriendlyName ); EnumContext->Size += StringSize( RoutingMethod->RoutingExtension->ImageName ); EnumContext->Size += StringSize( RoutingMethod->RoutingExtension->FriendlyName ); CoTaskMemFree( GuidString ); return TRUE; } if (EnumContext->Function == 2) { StringFromIID( &RoutingMethod->Guid, &GuidString ); EnumContext->RoutingInfoMethod[EnumContext->Size].SizeOfStruct = sizeof(FAX_ROUTING_METHOD); EnumContext->RoutingInfoMethod[EnumContext->Size].DeviceId = EnumContext->LineInfo->PermanentLineID; __try { EnumContext->RoutingInfoMethod[EnumContext->Size].Enabled = RoutingMethod->RoutingExtension->FaxRouteDeviceEnable( GuidString, EnumContext->LineInfo->PermanentLineID, QUERY_STATUS ); } __except (EXCEPTION_EXECUTE_HANDLER) { EnumContext->RoutingInfoMethod[EnumContext->Size].Enabled = FALSE; } StoreString( EnumContext->LineInfo->DeviceName, (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].DeviceName, (LPBYTE)EnumContext->RoutingInfoMethod, &EnumContext->Offset ); StoreString( GuidString, (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].Guid, (LPBYTE)EnumContext->RoutingInfoMethod, &EnumContext->Offset ); StoreString( RoutingMethod->FriendlyName, (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].FriendlyName, (LPBYTE)EnumContext->RoutingInfoMethod, &EnumContext->Offset ); StoreString( RoutingMethod->FunctionName, (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].FunctionName, (LPBYTE)EnumContext->RoutingInfoMethod, &EnumContext->Offset ); StoreString( RoutingMethod->RoutingExtension->ImageName, (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].ExtensionImageName, (LPBYTE)EnumContext->RoutingInfoMethod, &EnumContext->Offset ); StoreString( RoutingMethod->RoutingExtension->FriendlyName, (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].ExtensionFriendlyName, (LPBYTE)EnumContext->RoutingInfoMethod, &EnumContext->Offset ); EnumContext->Size += 1; CoTaskMemFree( GuidString ); return TRUE; } return FALSE; } error_status_t FAX_EnumRoutingMethods( IN HANDLE FaxPortHandle, OUT LPBYTE *RoutingInfoBuffer, OUT LPDWORD RoutingInfoBufferSize, OUT LPDWORD MethodsReturned ) { PLINE_INFO LineInfo = ((PHANDLE_ENTRY)FaxPortHandle)->LineInfo; ENUM_CONTEXT EnumContext; DWORD CountMethods; // // verify that the client as access rights // if (!FaxSvcAccessCheck( SEC_PORT_QUERY, FAX_PORT_QUERY )) { return ERROR_ACCESS_DENIED; } if (!RoutingInfoBuffer || !RoutingInfoBufferSize || !MethodsReturned) { return ERROR_INVALID_PARAMETER; } if (!LineInfo) { return ERROR_INVALID_DATA; } // // note that the called routines are protected so we don't have any protection here // // // compute the required size of the buffer // EnumContext.Function = 1; EnumContext.Size = 0; EnumContext.Offset = 0; EnumContext.LineInfo = LineInfo; EnumContext.RoutingInfoMethod = NULL; CountMethods = EnumerateRoutingMethods( RoutingMethodEnumerator, &EnumContext ); if (CountMethods == 0) { return ERROR_INVALID_FUNCTION; } // // allocate the buffer // *RoutingInfoBufferSize = EnumContext.Size; *RoutingInfoBuffer = (LPBYTE) MemAlloc( *RoutingInfoBufferSize ); if (*RoutingInfoBuffer == NULL) { return ERROR_NOT_ENOUGH_MEMORY; } // // fill the buffer with the data // EnumContext.Function = 2; EnumContext.Size = 0; EnumContext.Offset = sizeof(FAX_ROUTING_METHODW) * CountMethods; EnumContext.LineInfo = LineInfo; EnumContext.RoutingInfoMethod = (PFAX_ROUTING_METHOD) *RoutingInfoBuffer; if (!EnumerateRoutingMethods( RoutingMethodEnumerator, &EnumContext )) { MemFree( *RoutingInfoBuffer ); *RoutingInfoBuffer = NULL; *RoutingInfoBufferSize = 0; return ERROR_INVALID_FUNCTION; } *MethodsReturned = CountMethods; return 0; } error_status_t FAX_EnableRoutingMethod( IN HANDLE FaxPortHandle, IN LPCWSTR RoutingGuidString, IN BOOL Enabled ) { extern CRITICAL_SECTION CsRouting; error_status_t ec = 0; PLINE_INFO LineInfo = ((PHANDLE_ENTRY)FaxPortHandle)->LineInfo; PROUTING_METHOD RoutingMethod; // // verify that the client as access rights // if (!FaxSvcAccessCheck( SEC_PORT_SET, FAX_PORT_SET )) { return ERROR_ACCESS_DENIED; } if (!LineInfo) { return ERROR_INVALID_DATA; } if (!RoutingGuidString) return ERROR_INVALID_PARAMETER; EnterCriticalSection( &CsRouting ); // // get the routing method // RoutingMethod = FindRoutingMethodByGuid( RoutingGuidString ); if (!RoutingMethod) { LeaveCriticalSection( &CsRouting ); return ERROR_INVALID_DATA; } // // enable/disable the routing method for this device // __try { RoutingMethod->RoutingExtension->FaxRouteDeviceEnable( (LPWSTR)RoutingGuidString, LineInfo->PermanentLineID, Enabled ? STATUS_ENABLE : STATUS_DISABLE); } __except (EXCEPTION_EXECUTE_HANDLER) { ec = GetExceptionCode(); } LeaveCriticalSection( &CsRouting ); return ec; } typedef struct _ENUM_GLOBALCONTEXT { DWORD Function; DWORD Size; ULONG_PTR Offset; PFAX_GLOBAL_ROUTING_INFO RoutingInfoMethod; } ENUM_GLOBALCONTEXT, *PENUM_GLOBALCONTEXT; BOOL CALLBACK GlobalRoutingInfoMethodEnumerator( PROUTING_METHOD RoutingMethod, PENUM_GLOBALCONTEXT EnumContext ) { LPWSTR GuidString; if (EnumContext->Function == 1) { EnumContext->Size += sizeof(FAX_GLOBAL_ROUTING_INFO); StringFromIID( &RoutingMethod->Guid, &GuidString ); EnumContext->Size += StringSize( GuidString ); EnumContext->Size += StringSize( RoutingMethod->FunctionName ); EnumContext->Size += StringSize( RoutingMethod->FriendlyName ); EnumContext->Size += StringSize( RoutingMethod->RoutingExtension->ImageName ); EnumContext->Size += StringSize( RoutingMethod->RoutingExtension->FriendlyName ); CoTaskMemFree( GuidString ); return TRUE; } if (EnumContext->Function == 2) { StringFromIID( &RoutingMethod->Guid, &GuidString ); EnumContext->RoutingInfoMethod[EnumContext->Size].SizeOfStruct = sizeof(FAX_GLOBAL_ROUTING_INFO); EnumContext->RoutingInfoMethod[EnumContext->Size].Priority = RoutingMethod->Priority; StoreString( GuidString, (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].Guid, (LPBYTE)EnumContext->RoutingInfoMethod, &EnumContext->Offset ); StoreString( RoutingMethod->FriendlyName, (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].FriendlyName, (LPBYTE)EnumContext->RoutingInfoMethod, &EnumContext->Offset ); StoreString( RoutingMethod->FunctionName, (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].FunctionName, (LPBYTE)EnumContext->RoutingInfoMethod, &EnumContext->Offset ); StoreString( RoutingMethod->RoutingExtension->ImageName, (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].ExtensionImageName, (LPBYTE)EnumContext->RoutingInfoMethod, &EnumContext->Offset ); StoreString( RoutingMethod->RoutingExtension->FriendlyName, (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].ExtensionFriendlyName, (LPBYTE)EnumContext->RoutingInfoMethod, &EnumContext->Offset ); EnumContext->Size += 1; CoTaskMemFree( GuidString ); return TRUE; } return FALSE; } error_status_t FAX_EnumGlobalRoutingInfo( IN handle_t FaxHandle , OUT LPBYTE *RoutingInfoBuffer, OUT LPDWORD RoutingInfoBufferSize, OUT LPDWORD MethodsReturned ) { DWORD CountMethods; ENUM_GLOBALCONTEXT EnumContext; // // verify that the client as access rights // if (!FaxSvcAccessCheck( SEC_PORT_QUERY, FAX_CONFIG_QUERY )) { return ERROR_ACCESS_DENIED; } if (!RoutingInfoBuffer || !RoutingInfoBufferSize || !MethodsReturned) return ERROR_INVALID_PARAMETER; // // compute the required size of the buffer // EnumContext.Function = 1; EnumContext.Size = 0; EnumContext.Offset = 0; EnumContext.RoutingInfoMethod = NULL; CountMethods = EnumerateRoutingMethods( GlobalRoutingInfoMethodEnumerator, &EnumContext ); if (CountMethods == 0) { return ERROR_INVALID_FUNCTION; } // // allocate the buffer // *RoutingInfoBufferSize = EnumContext.Size; *RoutingInfoBuffer = (LPBYTE) MemAlloc( *RoutingInfoBufferSize ); if (*RoutingInfoBuffer == NULL) { return ERROR_NOT_ENOUGH_MEMORY; } // // fill the buffer with the data // EnumContext.Function = 2; EnumContext.Size = 0; EnumContext.Offset = sizeof(FAX_GLOBAL_ROUTING_INFOW) * CountMethods; EnumContext.RoutingInfoMethod = (PFAX_GLOBAL_ROUTING_INFO) *RoutingInfoBuffer; if (!EnumerateRoutingMethods( GlobalRoutingInfoMethodEnumerator, &EnumContext )) { MemFree( *RoutingInfoBuffer ); *RoutingInfoBuffer = NULL; *RoutingInfoBufferSize = 0; return ERROR_INVALID_FUNCTION; } *MethodsReturned = CountMethods; return 0; } error_status_t FAX_SetGlobalRoutingInfo( IN HANDLE FaxHandle, IN const FAX_GLOBAL_ROUTING_INFOW *RoutingInfo ) { extern CRITICAL_SECTION CsRouting; error_status_t ec = 0; PROUTING_METHOD RoutingMethod; // // verify that the client as access rights // if (!FaxSvcAccessCheck( SEC_CONFIG_SET, FAX_CONFIG_SET )) { return ERROR_ACCESS_DENIED; } if (!RoutingInfo) { return ERROR_INVALID_PARAMETER; } __try { if (RoutingInfo->SizeOfStruct != sizeof(FAX_GLOBAL_ROUTING_INFOW)) { return ERROR_INVALID_PARAMETER; } EnterCriticalSection( &CsRouting ); // // get the routing method // RoutingMethod = FindRoutingMethodByGuid( RoutingInfo->Guid ); if (!RoutingMethod) { LeaveCriticalSection( &CsRouting ); return ERROR_INVALID_DATA; } // // change the priority // RoutingMethod->Priority = RoutingInfo->Priority; SortMethodPriorities(); CommitMethodChanges(); } __except (EXCEPTION_EXECUTE_HANDLER) { ec = GetExceptionCode(); } LeaveCriticalSection( &CsRouting ); return ec; } error_status_t FAX_GetRoutingInfo( IN HANDLE FaxPortHandle, IN LPCWSTR RoutingGuidString, OUT LPBYTE *RoutingInfoBuffer, OUT LPDWORD RoutingInfoBufferSize ) { PLINE_INFO LineInfo = ((PHANDLE_ENTRY)FaxPortHandle)->LineInfo; PROUTING_METHOD RoutingMethod; LPBYTE RoutingInfo = NULL; DWORD RoutingInfoSize = 0; if (!FaxSvcAccessCheck( SEC_PORT_QUERY, FAX_PORT_QUERY )) { return ERROR_ACCESS_DENIED; } if (!RoutingGuidString || !RoutingInfoBuffer || !RoutingInfoBufferSize) { return ERROR_INVALID_PARAMETER; } if (!LineInfo) { return ERROR_INVALID_DATA; } RoutingMethod = FindRoutingMethodByGuid( RoutingGuidString ); if (!RoutingMethod) { return ERROR_INVALID_DATA; } __try { // // first check to see how big the buffer needs to be // if (RoutingMethod->RoutingExtension->FaxRouteGetRoutingInfo( (LPWSTR) RoutingGuidString, LineInfo->PermanentLineID, NULL, &RoutingInfoSize )) { // // allocate a client buffer // RoutingInfo = (LPBYTE) MemAlloc( RoutingInfoSize ); if (RoutingInfo == NULL) { return ERROR_NOT_ENOUGH_MEMORY; } // // get the routing data // if (RoutingMethod->RoutingExtension->FaxRouteGetRoutingInfo( RoutingGuidString, LineInfo->PermanentLineID, RoutingInfo, &RoutingInfoSize )) { // // move the data to the return buffer // *RoutingInfoBuffer = RoutingInfo; *RoutingInfoBufferSize = RoutingInfoSize; return ERROR_SUCCESS; } else { return ERROR_INVALID_DATA; } } else { return ERROR_INVALID_DATA; } } __except (EXCEPTION_EXECUTE_HANDLER) { // // for some reason we crashed, so return the exception code // return GetExceptionCode(); } return ERROR_INVALID_FUNCTION; } error_status_t FAX_SetRoutingInfo( IN HANDLE FaxPortHandle, IN LPCWSTR RoutingGuidString, IN const BYTE *RoutingInfoBuffer, IN DWORD RoutingInfoBufferSize ) { PLINE_INFO LineInfo = ((PHANDLE_ENTRY)FaxPortHandle)->LineInfo; PROUTING_METHOD RoutingMethod; if (!FaxSvcAccessCheck( SEC_PORT_SET, FAX_PORT_SET )) { return ERROR_ACCESS_DENIED; } if (!RoutingGuidString || !RoutingInfoBuffer || !RoutingInfoBufferSize) { return ERROR_INVALID_PARAMETER; } if (!LineInfo) { return ERROR_INVALID_DATA; } RoutingMethod = FindRoutingMethodByGuid( RoutingGuidString ); if (!RoutingMethod) { return ERROR_INVALID_DATA; } __try { if (RoutingMethod->RoutingExtension->FaxRouteSetRoutingInfo( RoutingGuidString, LineInfo->PermanentLineID, RoutingInfoBuffer, RoutingInfoBufferSize )) { return ERROR_SUCCESS; } else { return ERROR_INVALID_DATA; } } __except (EXCEPTION_EXECUTE_HANDLER) { // // for some reason we crashed, so return the exception code // return GetExceptionCode(); } return ERROR_INVALID_FUNCTION; } error_status_t FAX_GetTapiLocations( IN handle_t FaxHandle, OUT LPBYTE *Buffer, OUT LPDWORD LocationSize ) /*++ Routine Description: Queries the TAPI location information for the server Arguments: FaxHandle - FAX handle obtained from FaxConnectFaxServer. NumLocations - Returned number of locations LocationSize - Size of the TapiLocations buffer BytesNeeded - Size required TapiLocations - Data buffer Return Value: ERROR_SUCCESS for success, otherwise a WIN32 error code. --*/ { LPLINETRANSLATECAPS LineTransCaps = NULL; LPLINELOCATIONENTRY LineLocation = NULL; LPTSTR s,p; DWORD i,l; LONG rVal = ERROR_SUCCESS; ULONG_PTR Offset; PFAX_TAPI_LOCATION_INFO TapiLocationInfo; if (!FaxSvcAccessCheck( SEC_CONFIG_QUERY, FAX_CONFIG_QUERY )) { return ERROR_ACCESS_DENIED; } if (!Buffer || !LocationSize) return ERROR_INVALID_PARAMETER; __try { // // get the toll lists // rVal = MyLineGetTransCaps( &LineTransCaps ); if (rVal != ERROR_SUCCESS) { goto exit; } *LocationSize = sizeof(FAX_TAPI_LOCATION_INFO) + 32; if (LineTransCaps->dwLocationListSize && LineTransCaps->dwLocationListOffset) { LineLocation = (LPLINELOCATIONENTRY) ((LPBYTE)LineTransCaps + LineTransCaps->dwLocationListOffset); for (i=0; idwNumLocations; i++) { *LocationSize += sizeof(FAX_TAPI_LOCATIONS); if (LineLocation[i].dwTollPrefixListSize && LineLocation[i].dwTollPrefixListOffset) { *LocationSize += LineLocation[i].dwLocationNameSize; *LocationSize += LineLocation[i].dwTollPrefixListSize; } } } *Buffer = MemAlloc( *LocationSize ); if (*Buffer == NULL) { rVal = ERROR_NOT_ENOUGH_MEMORY; goto exit; } TapiLocationInfo = (PFAX_TAPI_LOCATION_INFO) *Buffer; Offset = sizeof(FAX_TAPI_LOCATION_INFO); TapiLocationInfo->CurrentLocationID = LineTransCaps->dwCurrentLocationID; TapiLocationInfo->NumLocations = LineTransCaps->dwNumLocations; TapiLocationInfo->TapiLocations = (PFAX_TAPI_LOCATIONS) ((LPBYTE) TapiLocationInfo + Offset); Offset += (LineTransCaps->dwNumLocations * sizeof(FAX_TAPI_LOCATIONS)); if (LineTransCaps->dwLocationListSize && LineTransCaps->dwLocationListOffset) { LineLocation = (LPLINELOCATIONENTRY) ((LPBYTE)LineTransCaps + LineTransCaps->dwLocationListOffset); for (i=0; idwNumLocations; i++) { TapiLocationInfo->TapiLocations[i].PermanentLocationID = LineLocation[i].dwPermanentLocationID; TapiLocationInfo->TapiLocations[i].CountryCode = LineLocation[i].dwCountryCode; TapiLocationInfo->TapiLocations[i].NumTollPrefixes = 0; if (LineLocation[i].dwCityCodeSize && LineLocation[i].dwCityCodeOffset) { TapiLocationInfo->TapiLocations[i].AreaCode = _ttoi( (LPTSTR) ((LPBYTE)LineTransCaps + LineLocation[i].dwCityCodeOffset) ); } else { TapiLocationInfo->TapiLocations[i].AreaCode = 0; } if (LineLocation[i].dwTollPrefixListSize && LineLocation[i].dwTollPrefixListOffset) { s = (LPTSTR) ((LPBYTE)LineTransCaps + LineLocation[i].dwTollPrefixListOffset); if (!*s) { TapiLocationInfo->TapiLocations[i].TollPrefixes = NULL; } else { TapiLocationInfo->TapiLocations[i].TollPrefixes = (LPTSTR) ((LPBYTE) TapiLocationInfo + Offset); Offset += LineLocation[i].dwTollPrefixListSize; s = (LPTSTR) ((LPBYTE)LineTransCaps + LineLocation[i].dwTollPrefixListOffset); if (*s == TEXT(',')) { s += 1; } l = _tcslen(s); if (l && s[l-1] == TEXT(',')) { s[l-1] = 0; } _tcscpy( (LPTSTR)TapiLocationInfo->TapiLocations[i].TollPrefixes, s ); // // count the number of toll prefixes // s = (LPTSTR)TapiLocationInfo->TapiLocations[i].TollPrefixes; while (*s) { p = _tcschr( s, TEXT(',') ); s = (p) ? p + 1 : s + _tcslen( s ); TapiLocationInfo->TapiLocations[i].NumTollPrefixes += 1; } } } else { TapiLocationInfo->TapiLocations[i].TollPrefixes = NULL; } if (LineLocation[i].dwLocationNameSize && LineLocation[i].dwLocationNameOffset) { TapiLocationInfo->TapiLocations[i].LocationName = (LPTSTR) ((LPBYTE) TapiLocationInfo + Offset); Offset += LineLocation[i].dwLocationNameSize; _tcscpy( (LPTSTR)TapiLocationInfo->TapiLocations[i].LocationName, (LPTSTR) ((LPBYTE)LineTransCaps + LineLocation[i].dwLocationNameOffset) ); } else { TapiLocationInfo->TapiLocations[i].LocationName = NULL; } } } for (i=0; iNumLocations; i++) { if (TapiLocationInfo->TapiLocations[i].LocationName) { TapiLocationInfo->TapiLocations[i].LocationName = (LPWSTR) ((ULONG_PTR)TapiLocationInfo->TapiLocations[i].LocationName - (ULONG_PTR)TapiLocationInfo); } if (TapiLocationInfo->TapiLocations[i].TollPrefixes) { TapiLocationInfo->TapiLocations[i].TollPrefixes = (LPWSTR) ((ULONG_PTR)TapiLocationInfo->TapiLocations[i].TollPrefixes - (ULONG_PTR)TapiLocationInfo); } } TapiLocationInfo->TapiLocations = (PFAX_TAPI_LOCATIONS) ((LPBYTE)TapiLocationInfo->TapiLocations - (ULONG_PTR)TapiLocationInfo); } __except (EXCEPTION_EXECUTE_HANDLER) { // // for some reason we crashed, so return the exception code // rVal = GetExceptionCode(); } exit: MemFree( LineTransCaps ); return rVal; } error_status_t FAX_SetTapiLocations( IN handle_t FaxHandle, IN LPBYTE Buffer, IN DWORD BufferSize ) /*++ Routine Description: Queries the TAPI location information for the server Arguments: FaxHandle - FAX handle obtained from FaxConnectFaxServer. NumLocations - Number of locations in the TapiLocations buffer TapiLocations - Data buffer Return Value: ERROR_SUCCESS for success, otherwise a WIN32 error code. --*/ { #define TOLL_MASK (LINETRANSLATERESULT_NOTINTOLLLIST|LINETRANSLATERESULT_INTOLLLIST) #define SetBit(_bitmap,_bit) (_bitmap[((_bit)>>5)]|=(1<<((_bit)-(((_bit)>>5)*32)))) #define IsBit(_bitmap,_bit) (_bitmap[((_bit)>>5)]&(1<<((_bit)-(((_bit)>>5)*32)))) PFAX_TAPI_LOCATION_INFO TapiLocationInfo = (PFAX_TAPI_LOCATION_INFO) Buffer; LPLINETRANSLATECAPS LineTransCaps = NULL; LPLINELOCATIONENTRY LineLocation = NULL; DWORD BitMap[32]; DWORD BitMapCurr[32]; LPTSTR s,p; DWORD i,j; LONG rVal = ERROR_SUCCESS; TCHAR Address[32]; DWORD TollListOption; if (!FaxSvcAccessCheck( SEC_CONFIG_SET, FAX_CONFIG_SET )) { return ERROR_ACCESS_DENIED; } __try { if (!TapiLocationInfo) { rVal = ERROR_INVALID_PARAMETER; goto exit; } TapiLocationInfo->TapiLocations = (PFAX_TAPI_LOCATIONS) (Buffer+ (ULONG_PTR) TapiLocationInfo->TapiLocations); for (i=0; iNumLocations; i++) { TapiLocationInfo->TapiLocations[i].LocationName = (LPWSTR) FixupString(Buffer,TapiLocationInfo->TapiLocations[i].LocationName); TapiLocationInfo->TapiLocations[i].TollPrefixes = (LPWSTR) FixupString(Buffer,TapiLocationInfo->TapiLocations[i].TollPrefixes); } // // get the toll lists // rVal = MyLineGetTransCaps( &LineTransCaps ); if (rVal != ERROR_SUCCESS) { goto exit; } LineLocation = (LPLINELOCATIONENTRY) ((LPBYTE)LineTransCaps + LineTransCaps->dwLocationListOffset); for (i=0; iNumLocations; i++) { // // match the location id for this location entry with // one that tapi knows about. // for (j=0; jdwNumLocations; j++) { if (LineLocation[j].dwPermanentLocationID == TapiLocationInfo->TapiLocations[i].PermanentLocationID) { break; } } if (j == LineTransCaps->dwNumLocations) { // // we got a bogus location id // continue; } // // set the bitmap for the toll prefixes that // tapi location is using. // ZeroMemory( BitMapCurr, sizeof(BitMapCurr) ); if (LineLocation[j].dwTollPrefixListOffset) { s = (LPTSTR) ((LPBYTE)LineTransCaps + LineLocation[j].dwTollPrefixListOffset); if (*s == TEXT(',')) { s += 1; } while( s && *s ) { p = _tcschr( s, TEXT(',') ); if (p) { *p = 0; } SetBit( BitMapCurr, min(_ttoi(s),999) ); if (p) { s = p + 1; } else { s += _tcslen( s ); } } } // // set the bitmap for the toll prefixes // that this location is using. // s = (LPTSTR) TapiLocationInfo->TapiLocations[i].TollPrefixes; ZeroMemory( BitMap, sizeof(BitMap) ); while( s && *s ) { p = _tcschr( s, TEXT(',') ); if (p) { *p = 0; } SetBit( BitMap, min(_ttoi(s),999) ); if (p) { s = p + 1; } else { s += _tcslen( s ); } } // // set the current location so that the toll prefix // changes affect the correct location. // rVal = lineSetCurrentLocation( hLineApp, TapiLocationInfo->TapiLocations[i].PermanentLocationID ); if (rVal != ERROR_SUCCESS) { DebugPrint(( TEXT("lineSetCurrentLocation() failed, ec=%08x"), rVal )); continue; } // // change the toll list // for (j=200; j<999; j++) { TollListOption = 0; if (!IsBit( BitMapCurr, j )) { if (IsBit(BitMap,j)) { TollListOption = LINETOLLLISTOPTION_ADD; } } else { if (!IsBit(BitMap,j)) { TollListOption = LINETOLLLISTOPTION_REMOVE; } } if (TollListOption) { wsprintf( Address, TEXT("+%d (%d) %03d-0000"), TapiLocationInfo->TapiLocations[i].CountryCode, TapiLocationInfo->TapiLocations[i].AreaCode, j ); rVal = lineSetTollList( hLineApp, 0, Address, TollListOption ); if (rVal != ERROR_SUCCESS) { DebugPrint(( TEXT("lineSetTollList() failed, address=%s, ec=%08x"), Address, rVal )); continue; } } } } // // reset the current location // rVal = lineSetCurrentLocation( hLineApp, TapiLocationInfo->CurrentLocationID ); if (rVal != ERROR_SUCCESS) { DebugPrint(( TEXT("lineSetCurrentLocation() failed, ec=%08x"), rVal )); } } __except (EXCEPTION_EXECUTE_HANDLER) { // // for some reason we crashed, so return the exception code // rVal = GetExceptionCode(); } exit: MemFree( LineTransCaps ); return rVal; } error_status_t FAX_GetMapiProfiles( IN handle_t FaxHandle, OUT LPBYTE *MapiProfiles, OUT LPDWORD BufferSize ) /*++ Routine Description: Returns a list of MAPI profiles. Arguments: FaxHandle - FAX handle obtained from FaxConnectFaxServer. MapiProfiles - Multi-SZ string containing all MAPI profiles ProfileSize - Size of the MapiProfiles array Return Value: ERROR_SUCCESS for success, otherwise a WIN32 error code. --*/ { error_status_t rVal; if (!FaxSvcAccessCheck( SEC_CONFIG_QUERY, FAX_CONFIG_QUERY )) { return ERROR_ACCESS_DENIED; } if (!MapiProfiles || !BufferSize) return ERROR_INVALID_PARAMETER; __try { rVal = (error_status_t) GetMapiProfiles( (LPWSTR*) MapiProfiles, BufferSize ); } __except (EXCEPTION_EXECUTE_HANDLER) { rVal = GetExceptionCode(); } return rVal; } error_status_t FAX_GetLoggingCategories( IN handle_t hBinding, OUT LPBYTE *Buffer, OUT LPDWORD BufferSize, OUT LPDWORD NumberCategories ) { PFAX_LOG_CATEGORY Categories; REG_FAX_LOGGING FaxRegLogging; DWORD i; ULONG_PTR Offset; if (!FaxSvcAccessCheck( SEC_CONFIG_QUERY, FAX_CONFIG_QUERY )) { return ERROR_ACCESS_DENIED; } if (!Buffer || !BufferSize || !NumberCategories) { return ERROR_INVALID_PARAMETER; } GetLoggingCategoriesRegistry( &FaxRegLogging ); *BufferSize = sizeof(FAX_LOG_CATEGORY) * FaxRegLogging.LoggingCount; Offset = *BufferSize; for (i=0; ihBinding = hBinding; ClientData->MachineName = NULL; ClientData->ClientName = NULL; ClientData->Context = 0; ClientData->hWnd = (HWND)hWnd; ClientData->MessageStart = MessageStart; ClientData->StartedMsg = FALSE; if (MessageStart != 0 ) { ec = RpcImpersonateClient(hBinding); if (ec != RPC_S_OK) { DebugPrint(( TEXT("RpcImpersonateClient failed, ec = %d\n"), ec )); goto e0; } // // need to cross threads, so duplicate thread psuedohandle? // if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &hThread, THREAD_ALL_ACCESS, FALSE, 0 )) { ec = GetLastError(); DebugPrint(( TEXT("DuplicateHandle() failed, ec=%d"), ec )); goto e1; } // // different thread will be impersonating so I better open then duplicate the token // if (!OpenThreadToken(hThread, TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, FALSE, &hToken ) ) { ec = GetLastError(); DebugPrint((TEXT("Couldn't OpenThreadToken, ec = %d.\n"), ec )); goto e2; } if (!DuplicateToken( hToken, SecurityImpersonation, &ClientData->hClientToken )) { ec = GetLastError(); DebugPrint((TEXT("Couldn't DuplicateToken, ec = %d.\n"), ec )); goto e3; } CloseHandle( hToken ); CloseHandle( hThread ); RpcRevertToSelf(); ClientData->WindowStation = StringDup( WindowStation ); ClientData->Desktop = StringDup( Desktop ); } __try { EnterCriticalSection( &CsClients ); Next = ClientsListHead.Flink; if (Next) { while ((ULONG_PTR)Next != (ULONG_PTR)&ClientsListHead) { Current = CONTAINING_RECORD( Next, FAX_CLIENT_DATA, ListEntry ); Next = Current->ListEntry.Flink; if (Current->hWnd == ClientData->hWnd && !lstrcmpi(Current->WindowStation,ClientData->WindowStation) && !lstrcmpi(Current->Desktop,ClientData->Desktop) ) { DebugPrint((TEXT("Already have window handle %d registered.\n"),Current->hWnd)); EntryExists = TRUE; if (MessageStart == 0) { // // This means that we have already registered this client. // To allow this client to logoff, we should close the impersonation token // we have for their desktop // CloseHandle( Current->hClientToken ); RemoveEntryList( &Current->ListEntry ); MemFree( (LPBYTE) Current->WindowStation ); MemFree( (LPBYTE) Current->Desktop ); MemFree( Current ); } } } } if (!EntryExists) { InsertTailList( &ClientsListHead, &ClientData->ListEntry ); } else { if ( ClientData ) { if ( ClientData->WindowStation ) MemFree ( (LPBYTE) ClientData->WindowStation ) ; if ( ClientData->Desktop ) MemFree ( (LPBYTE) ClientData->Desktop ) ; CloseHandle( ClientData->hClientToken ); MemFree( ClientData ); } LeaveCriticalSection( &CsClients ); return 0; } LeaveCriticalSection( &CsClients ); } __except (EXCEPTION_EXECUTE_HANDLER) { DebugPrint((TEXT("FAX_RegisterEventWindow exception, ec = %d.\n"),GetExceptionCode() )); if ( ClientData->WindowStation ) MemFree ( (LPBYTE) ClientData->WindowStation ) ; if ( ClientData->Desktop ) MemFree ( (LPBYTE) ClientData->Desktop ) ; if ( ClientData ) { if ( ClientData->hClientToken) { CloseHandle( ClientData->hClientToken ); } MemFree( ClientData ); } LeaveCriticalSection( &CsClients ); return GetExceptionCode(); } CreateFaxEvent( 0, FEI_FAXSVC_STARTED, 0xffffffff ); if (FaxSvcProcessId) { *FaxSvcProcessId = GetCurrentProcessId(); } return 0; e3: CloseHandle( hToken ); e2: CloseHandle( hThread ); e1: RpcRevertToSelf(); e0: MemFree(ClientData); return ec; } error_status_t FAX_StartClientServer( IN handle_t hBinding, IN LPCTSTR MachineName, IN LPCTSTR ClientName, IN ULONG64 Context ) { DWORD Error; PFAX_CLIENT_DATA ClientData,Current; PLIST_ENTRY Next; BOOL EntryExists = FALSE; ClientData = (PFAX_CLIENT_DATA) MemAlloc( sizeof(FAX_CLIENT_DATA) ); if (!ClientData) { return ERROR_NOT_ENOUGH_MEMORY; } ClientData->hBinding = hBinding; ClientData->MachineName = StringDup( MachineName ); ClientData->ClientName = StringDup( ClientName ); ClientData->Context = Context; ClientData->hWnd = NULL; ClientData->MessageStart = 0; ClientData->StartedMsg = FALSE; __try { EnterCriticalSection( &CsClients ); // // make sure we don't register a client twice // Next = ClientsListHead.Flink; if (Next) { while ((ULONG_PTR)Next != (ULONG_PTR)&ClientsListHead) { Current = CONTAINING_RECORD( Next, FAX_CLIENT_DATA, ListEntry ); Next = Current->ListEntry.Flink; // // make sure we're looking at io event-based clients // if (!Current->hWnd) { if ((_wcsicmp(Current->ClientName ,ClientData->ClientName ) == 0) && ( ((!Current->MachineName) && (!ClientData->MachineName)) || (_wcsicmp(Current->MachineName,ClientData->MachineName) == 0) )) { DebugPrint((TEXT("Already have client %s on %s registered.\n"), Current->ClientName ? Current->ClientName : L"NULL", Current->MachineName ? Current->MachineName : L"NULL" )); EntryExists = TRUE; } } } } if (!EntryExists) { Error = RpcpBindRpc( MachineName, ClientName, L"Security=identification static true", &ClientData->FaxHandle ); if (Error) { MemFree( ClientData ); LeaveCriticalSection( &CsClients ); return Error; } InsertTailList( &ClientsListHead, &ClientData->ListEntry ); } LeaveCriticalSection( &CsClients ); } __except (EXCEPTION_EXECUTE_HANDLER) { MemFree( ClientData); LeaveCriticalSection( &CsClients ); return (GetExceptionCode() ); } CreateFaxEvent( 0, FEI_FAXSVC_STARTED, 0xffffffff ); return 0; } error_status_t FAX_AccessCheck( IN handle_t hBinding, IN DWORD AccessMask, OUT LPDWORD fAccess ) { if (!hBinding || !fAccess) { return ERROR_INVALID_PARAMETER; } // // we only have one security descriptor, so the first parameter is meaningless // *fAccess = FaxSvcAccessCheck( SEC_CONFIG_QUERY, AccessMask); return 0; } VOID RPC_FAX_PORT_HANDLE_rundown( IN HANDLE FaxPortHandle ) { PHANDLE_ENTRY PortHandleEntry = (PHANDLE_ENTRY) FaxPortHandle; PLIST_ENTRY Next; PFAX_CLIENT_DATA ClientData; EnterCriticalSection( &CsLine ); EnterCriticalSection( &CsClients ); __try { DebugPrint(( TEXT("RPC_FAX_PORT_HANDLE_rundown() running for port handle 0x%08x"), FaxPortHandle )); Next = ClientsListHead.Flink; if (Next) { while ((ULONG_PTR)Next != (ULONG_PTR)&ClientsListHead) { ClientData = CONTAINING_RECORD( Next, FAX_CLIENT_DATA, ListEntry ); Next = ClientData->ListEntry.Flink; if (ClientData->hBinding == PortHandleEntry->hBinding) { RemoveEntryList( &ClientData->ListEntry ); MemFree(ClientData); } } } CloseFaxHandle( PortHandleEntry ); } __except (EXCEPTION_EXECUTE_HANDLER) { DebugPrint(( TEXT("RPC_FAX_PORT_HANDLE_rundown() crashed, ec=0x%08x"), GetExceptionCode() )); } LeaveCriticalSection( &CsClients ); LeaveCriticalSection( &CsLine ); return; }