625 lines
11 KiB
C
625 lines
11 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1996 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
faxisapi.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module implements an isapi dll for the
|
||
|
ms fax server. The HttpExtensionProc() supports
|
||
|
the following syntax:
|
||
|
|
||
|
dir= directory browser
|
||
|
status= fax status display
|
||
|
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Wesley Witt (wesw) 01-May-1996
|
||
|
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include <windows.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <stdio.h>
|
||
|
|
||
|
#include "httpext.h"
|
||
|
#include "faxutil.h"
|
||
|
#include "winfax.h"
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
BOOL WINAPI
|
||
|
GetExtensionVersion(
|
||
|
HSE_VERSION_INFO *pVer
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Provides version information for this dll.
|
||
|
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pVer - HTTP version structure
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE - Success
|
||
|
FALSE - Failure
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
pVer->dwExtensionVersion = MAKELONG( HSE_VERSION_MINOR, HSE_VERSION_MAJOR );
|
||
|
|
||
|
strncpy(
|
||
|
pVer->lpszExtensionDesc,
|
||
|
"FAX Server ISAPI Support DLL",
|
||
|
HSE_MAX_EXT_DLL_NAME_LEN
|
||
|
);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
LPSTR
|
||
|
AddString(
|
||
|
LPSTR Buffer,
|
||
|
LPSTR String,
|
||
|
...
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Adds a string to end of a buffer.
|
||
|
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Buffer - Buffer to receive the string
|
||
|
String - The string to be added to the buffer
|
||
|
... - varargs data
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Pointer to the end of the buffer.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
DWORD len;
|
||
|
va_list arg_ptr;
|
||
|
|
||
|
|
||
|
va_start(arg_ptr, String);
|
||
|
vsprintf( Buffer, String, arg_ptr);
|
||
|
va_end(arg_ptr);
|
||
|
|
||
|
return Buffer + strlen(Buffer);
|
||
|
}
|
||
|
|
||
|
|
||
|
LPSTR
|
||
|
AppendNode(
|
||
|
LPSTR Directory,
|
||
|
LPSTR Node
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Appends a node to the end of a path.
|
||
|
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Directory - Current directory.
|
||
|
Node - Node to be added to the directory.
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Pointer to a newly allocated directory.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
LPSTR s,dir;
|
||
|
|
||
|
|
||
|
s = Directory + strlen(Directory);
|
||
|
while (*s != '\\') s--;
|
||
|
s[0] = 0;
|
||
|
dir = MemAlloc( strlen(Directory) + 128 );
|
||
|
if (!dir) {
|
||
|
return NULL;
|
||
|
}
|
||
|
sprintf( dir, "%s\\%s\\*", Directory, Node );
|
||
|
s[0] = '\\';
|
||
|
|
||
|
return dir;
|
||
|
}
|
||
|
|
||
|
|
||
|
LPSTR
|
||
|
ResolvePath(
|
||
|
LPSTR Directory
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Obtains a complete path for a directory.
|
||
|
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Directory - Current directory.
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Pointer to a newly allocated complete directory.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
LPSTR dir;
|
||
|
DWORD len;
|
||
|
LPSTR fname;
|
||
|
|
||
|
|
||
|
len = strlen(Directory) + 128;
|
||
|
dir = MemAlloc( len );
|
||
|
if (!dir) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (!GetFullPathName( Directory, len, dir, &fname )) {
|
||
|
MemFree( dir );
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
return dir;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
LPSTR
|
||
|
PrintFileInfo(
|
||
|
LPSTR Buffer,
|
||
|
LPSTR Link,
|
||
|
LPWIN32_FIND_DATA FindData
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Generates a single HTML source line for a file name.
|
||
|
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Buffer - Buffer to put the HTML source into
|
||
|
Link - TRUE=generate href, FALSE=no href
|
||
|
FindData - File information
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Pointer to the end of the buffer.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
FILETIME LocalTime;
|
||
|
SYSTEMTIME SystemTime;
|
||
|
|
||
|
FileTimeToLocalFileTime( &FindData->ftCreationTime, &LocalTime );
|
||
|
FileTimeToSystemTime( &LocalTime, &SystemTime );
|
||
|
|
||
|
Buffer = AddString(
|
||
|
Buffer,
|
||
|
"%02d-%02d-%04d %02d:%02d:%02d ",
|
||
|
SystemTime.wMonth,
|
||
|
SystemTime.wDay,
|
||
|
SystemTime.wYear,
|
||
|
SystemTime.wHour,
|
||
|
SystemTime.wMinute,
|
||
|
SystemTime.wSecond
|
||
|
);
|
||
|
|
||
|
if (Link) {
|
||
|
|
||
|
Buffer = AddString(
|
||
|
Buffer,
|
||
|
"<a href=\"/scripts/faxisapi.dll?%s\">%s</a>\n",
|
||
|
Link,
|
||
|
FindData->cFileName
|
||
|
);
|
||
|
|
||
|
|
||
|
} else {
|
||
|
|
||
|
Buffer = AddString( Buffer, "%s\n", FindData->cFileName );
|
||
|
|
||
|
}
|
||
|
|
||
|
return Buffer;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
HtmlDirectory(
|
||
|
LPSTR Directory,
|
||
|
LPBYTE Buffer
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Generates a page of HTML source for a directory.
|
||
|
This function implements a directory browser that
|
||
|
allows an HTML client to browse the directories
|
||
|
on the server's disks.
|
||
|
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Directory - Directory from which to generate HTML source.
|
||
|
Buffer - Buffer to put the HTML source into.
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE - HTML generation is successful
|
||
|
FALSE - NTML generation failed
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
LPBYTE p;
|
||
|
LPSTR dir;
|
||
|
HANDLE hFind;
|
||
|
WIN32_FIND_DATA FindData;
|
||
|
|
||
|
|
||
|
|
||
|
p = Buffer;
|
||
|
|
||
|
hFind = FindFirstFile( Directory, &FindData );
|
||
|
if (hFind == INVALID_HANDLE_VALUE) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
p = AddString( p, "Content-type: text/html\r\n\r\n" );
|
||
|
p = AddString( p, "<html>\r\n" );
|
||
|
p = AddString( p, "<head><title>Tornado FAX Server Project</title></head>\r\n" );
|
||
|
p = AddString( p, "<body>\r\n" );
|
||
|
p = AddString( p, "<h1>Directory Listing:<br>%s</h1><hr>\r\n", Directory );
|
||
|
p = AddString( p, "<p><pre>\n" );
|
||
|
|
||
|
do {
|
||
|
|
||
|
if (FindData.cFileName[0] == '.') {
|
||
|
if (FindData.cFileName[1] == '.') {
|
||
|
|
||
|
dir = AppendNode( Directory, ".." );
|
||
|
|
||
|
if (dir) {
|
||
|
|
||
|
LPSTR NewDir = ResolvePath( dir );
|
||
|
if (NewDir) {
|
||
|
MemFree( dir );
|
||
|
dir = NewDir;
|
||
|
}
|
||
|
|
||
|
p = AddString(
|
||
|
p,
|
||
|
"<a href=\"/scripts/faxisapi.dll?%s\"><img src=\"/images/b_arrow.gif\" border=0 >Parent Directory</a>\n",
|
||
|
dir
|
||
|
);
|
||
|
|
||
|
p = AddString( p, "<br>" );
|
||
|
|
||
|
MemFree( dir );
|
||
|
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||
|
|
||
|
dir = AppendNode( Directory, FindData.cFileName );
|
||
|
|
||
|
if (dir) {
|
||
|
|
||
|
p = PrintFileInfo( p, dir, &FindData );
|
||
|
|
||
|
MemFree( dir );
|
||
|
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
p = PrintFileInfo( p, NULL, &FindData );
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} while( FindNextFile( hFind, &FindData ) );
|
||
|
|
||
|
p = AddString( p, "</pre></body></html>\r\n" );
|
||
|
|
||
|
FindClose( hFind );
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
HtmlFaxStatus(
|
||
|
LPBYTE Buffer
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Generates a page of HTML source that shows
|
||
|
a status display for a ms fax server.
|
||
|
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Buffer - Buffer to put the HTML source into.
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE - HTML generation is successful
|
||
|
FALSE - NTML generation failed
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
LPBYTE p;
|
||
|
PFAX_STATUS FaxStatus = NULL;
|
||
|
DWORD BytesNeeded;
|
||
|
DWORD i;
|
||
|
HFAX FaxHandle = NULL;
|
||
|
|
||
|
|
||
|
p = Buffer;
|
||
|
|
||
|
p = AddString( p, "Content-type: text/html\r\n\r\n" );
|
||
|
p = AddString( p, "<html>\r\n" );
|
||
|
p = AddString( p, "<head><title>Tornado FAX Server Project</title></head>\r\n" );
|
||
|
p = AddString( p, "<body>\r\n" );
|
||
|
p = AddString( p, "<h1>FAX Server Status</h1><hr>\n" );
|
||
|
p = AddString( p, "<p>\n" );
|
||
|
p = AddString( p, "<body background=\"/images/softgrid.gif\">" );
|
||
|
p = AddString( p, "<table border=5 cellpadding=5 cellspacing=10>\n" );
|
||
|
p = AddString( p, "<tr>\n" );
|
||
|
p = AddString( p, " <th>Port Name</th>\n" );
|
||
|
p = AddString( p, " <th>Port Number</th>\n" );
|
||
|
p = AddString( p, " <th>Status</th>\n" );
|
||
|
p = AddString( p, "</tr>\n" );
|
||
|
|
||
|
FaxStatus = (PFAX_STATUS) MemAlloc( 4096 );
|
||
|
if (!FaxStatus) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (!FaxConnectFaxServer( NULL, &FaxHandle )) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
if (!FaxGetDeviceStatus( FaxHandle, 0, (LPBYTE) FaxStatus, 4096, &BytesNeeded )) {
|
||
|
FaxDisconnectFaxServer( FaxHandle );
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
for (i=0; i<FaxStatus->DeviceCount; i++) {
|
||
|
|
||
|
p = AddString( p, "<tr>\n" );
|
||
|
p = AddString( p, " <td>%s</td>\n", FaxStatus->DeviceStatus[i].DeviceName );
|
||
|
p = AddString( p, " <td>%d</td>\n", FaxStatus->DeviceStatus[i].DeviceId );
|
||
|
|
||
|
if (FaxStatus->DeviceStatus[i].Status & FPS_SENDING) {
|
||
|
|
||
|
p = AddString( p, " <td>Sending</td>\n" );
|
||
|
|
||
|
} else if (FaxStatus->DeviceStatus[i].Status & FPS_RECEIVING) {
|
||
|
|
||
|
p = AddString( p, " <td>Receiving</td>\n" );
|
||
|
|
||
|
} else if (FaxStatus->DeviceStatus[i].Status & FPS_AVAILABLE) {
|
||
|
|
||
|
p = AddString( p, " <td>Idle</td>\n" );
|
||
|
|
||
|
} else if (FaxStatus->DeviceStatus[i].Status & FPS_ABORTING) {
|
||
|
|
||
|
p = AddString( p, " <td>Aborting</td>\n" );
|
||
|
|
||
|
} else if (FaxStatus->DeviceStatus[i].Status & FPS_ROUTING) {
|
||
|
|
||
|
p = AddString( p, " <td>Routing</td>\n" );
|
||
|
|
||
|
} else if (FaxStatus->DeviceStatus[i].Status & FPS_UNAVAILABLE) {
|
||
|
|
||
|
p = AddString( p, " <td>Unavailable</td>\n" );
|
||
|
|
||
|
} else {
|
||
|
|
||
|
p = AddString( p, " <td>*Unknown Status*</td>\n" );
|
||
|
|
||
|
}
|
||
|
|
||
|
p = AddString( p, "</tr>\n" );
|
||
|
|
||
|
}
|
||
|
|
||
|
MemFree( FaxStatus );
|
||
|
|
||
|
FaxDisconnectFaxServer( FaxHandle );
|
||
|
|
||
|
p = AddString( p, "</table>" );
|
||
|
p = AddString( p, "</body></html>\n" );
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD WINAPI
|
||
|
HttpExtensionProc(
|
||
|
EXTENSION_CONTROL_BLOCK *pECB
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Function that is called by the HTTP server.
|
||
|
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pECB - HTTP extension control block
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
HSE_STATUS_ERROR - failure
|
||
|
HSE_STATUS_SUCCESS - success
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
#define MAX_BUFFER_SIZE (1024*1024)
|
||
|
LPBYTE Buffer;
|
||
|
DWORD Length;
|
||
|
LPSTR s;
|
||
|
|
||
|
|
||
|
pECB->dwHttpStatusCode = 0;
|
||
|
|
||
|
|
||
|
s = strchr( pECB->lpszQueryString, '=' );
|
||
|
if (!s) {
|
||
|
return HSE_STATUS_ERROR;
|
||
|
}
|
||
|
|
||
|
*s++ = 0;
|
||
|
|
||
|
if (_stricmp( pECB->lpszQueryString, "dir" ) == 0) {
|
||
|
|
||
|
Buffer = (LPBYTE) VirtualAlloc( NULL, MAX_BUFFER_SIZE, MEM_COMMIT, PAGE_READWRITE );
|
||
|
if (!Buffer) {
|
||
|
return HSE_STATUS_ERROR;
|
||
|
}
|
||
|
|
||
|
if (!HtmlDirectory( s, Buffer )) {
|
||
|
return HSE_STATUS_ERROR;
|
||
|
}
|
||
|
|
||
|
} else if (_stricmp( pECB->lpszQueryString, "status" ) == 0) {
|
||
|
|
||
|
Buffer = (LPBYTE) VirtualAlloc( NULL, MAX_BUFFER_SIZE, MEM_COMMIT, PAGE_READWRITE );
|
||
|
if (!Buffer) {
|
||
|
return HSE_STATUS_ERROR;
|
||
|
}
|
||
|
|
||
|
if (!HtmlFaxStatus( Buffer )) {
|
||
|
return HSE_STATUS_ERROR;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
return HSE_STATUS_ERROR;
|
||
|
|
||
|
}
|
||
|
|
||
|
if (Buffer) {
|
||
|
Length = strlen( Buffer );
|
||
|
|
||
|
|
||
|
pECB->ServerSupportFunction(
|
||
|
pECB->ConnID,
|
||
|
HSE_REQ_SEND_RESPONSE_HEADER,
|
||
|
NULL,
|
||
|
&Length,
|
||
|
(LPDWORD) Buffer
|
||
|
);
|
||
|
|
||
|
pECB->dwHttpStatusCode = 200;
|
||
|
|
||
|
VirtualFree( Buffer, MAX_BUFFER_SIZE, MEM_DECOMMIT );
|
||
|
|
||
|
} else {
|
||
|
|
||
|
return HSE_STATUS_ERROR;
|
||
|
|
||
|
}
|
||
|
|
||
|
return HSE_STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
FaxIsapiDllEntry(
|
||
|
HINSTANCE hInstance,
|
||
|
DWORD Reason,
|
||
|
LPVOID Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
DLL initialization function.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
hInstance - Instance handle
|
||
|
Reason - Reason for the entrypoint being called
|
||
|
Context - Context record
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE - Initialization succeeded
|
||
|
FALSE - Initialization failed
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
if (Reason == DLL_PROCESS_ATTACH) {
|
||
|
DisableThreadLibraryCalls( hInstance );
|
||
|
HeapInitialize();
|
||
|
}
|
||
|
|
||
|
if (Reason == DLL_PROCESS_DETACH) {
|
||
|
HeapCleanup();
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|