windows-nt/Source/XPSP1/NT/printscan/fax/service/server/faxrpc.c
2020-09-26 16:20:57 +08:00

3436 lines
89 KiB
C

/*++
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; i<LineTransCaps->dwNumLocations; 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; i<LineTransCaps->dwNumLocations; 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; i<TapiLocationInfo->NumLocations; 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; i<TapiLocationInfo->NumLocations; 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; i<TapiLocationInfo->NumLocations; i++) {
//
// match the location id for this location entry with
// one that tapi knows about.
//
for (j=0; j<LineTransCaps->dwNumLocations; 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; i<FaxRegLogging.LoggingCount; i++) {
*BufferSize += StringSize( FaxRegLogging.Logging[i].CategoryName );
}
*Buffer = (LPBYTE) MemAlloc( *BufferSize );
if (!*Buffer) {
*BufferSize = 0;
return ERROR_NOT_ENOUGH_MEMORY;
}
*NumberCategories = FaxRegLogging.LoggingCount;
Categories = (PFAX_LOG_CATEGORY) *Buffer;
for (i=0; i<FaxRegLogging.LoggingCount; i++) {
StoreString(
FaxRegLogging.Logging[i].CategoryName,
(PULONG_PTR)&Categories[i].Name,
*Buffer,
&Offset
);
Categories[i].Category = FaxRegLogging.Logging[i].Number;
Categories[i].Level = FaxRegLogging.Logging[i].Level;
}
return 0;
}
error_status_t
FAX_SetLoggingCategories(
IN handle_t hBinding,
IN const LPBYTE Buffer,
IN DWORD BufferSize,
IN DWORD NumberCategories
)
{
REG_FAX_LOGGING FaxRegLogging;
DWORD i;
if (!FaxSvcAccessCheck( SEC_CONFIG_QUERY, FAX_CONFIG_SET )) {
return ERROR_ACCESS_DENIED;
}
if (!Buffer || !BufferSize)
return ERROR_INVALID_PARAMETER;
//
// setup the data
//
FaxRegLogging.LoggingCount = NumberCategories;
FaxRegLogging.Logging = (PREG_CATEGORY) Buffer;
for (i=0; i<FaxRegLogging.LoggingCount; i++) {
FaxRegLogging.Logging[i].CategoryName = (LPWSTR) FixupString(Buffer,FaxRegLogging.Logging[i].CategoryName);
}
//
// first change the real time data that the server is using
//
RefreshEventLog( &FaxRegLogging );
//
// now change the registry so it sticks
//
return SetLoggingCategoriesRegistry( &FaxRegLogging ) ? 0 : GetLastError();
}
error_status_t
FAX_RegisterEventWindow(
IN handle_t hBinding,
IN ULONG64 hWnd,
IN UINT MessageStart,
IN LPCWSTR WindowStation,
IN LPCWSTR Desktop,
OUT LPDWORD FaxSvcProcessId
)
{
PFAX_CLIENT_DATA ClientData,Current;
PLIST_ENTRY Next;
BOOL EntryExists = FALSE;
RPC_STATUS ec;
HANDLE hToken;
HANDLE hThread;
if (!hWnd || !FaxSvcProcessId)
return ERROR_INVALID_PARAMETER;
ClientData = (PFAX_CLIENT_DATA) MemAlloc( sizeof(FAX_CLIENT_DATA) );
if (!ClientData) {
return ERROR_NOT_ENOUGH_MEMORY;
}
ClientData->hBinding = 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;
}