3436 lines
89 KiB
C
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;
|
|
}
|
|
|
|
|