/*++ 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 #include #include #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, "%s\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, "\r\n" ); p = AddString( p, "Tornado FAX Server Project\r\n" ); p = AddString( p, "\r\n" ); p = AddString( p, "

Directory Listing:
%s


\r\n", Directory ); p = AddString( p, "

\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,
                        "Parent Directory\n",
                        dir
                        );

                    p = AddString( p, "
" ); 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, "
\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, "\r\n" ); p = AddString( p, "Tornado FAX Server Project\r\n" ); p = AddString( p, "\r\n" ); p = AddString( p, "

FAX Server Status


\n" ); p = AddString( p, "

\n" ); p = AddString( p, "" ); p = AddString( p, "\n" ); p = AddString( p, "\n" ); p = AddString( p, " \n" ); p = AddString( p, " \n" ); p = AddString( p, " \n" ); p = AddString( p, "\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; iDeviceCount; i++) { p = AddString( p, "\n" ); p = AddString( p, " \n", FaxStatus->DeviceStatus[i].DeviceName ); p = AddString( p, " \n", FaxStatus->DeviceStatus[i].DeviceId ); if (FaxStatus->DeviceStatus[i].Status & FPS_SENDING) { p = AddString( p, " \n" ); } else if (FaxStatus->DeviceStatus[i].Status & FPS_RECEIVING) { p = AddString( p, " \n" ); } else if (FaxStatus->DeviceStatus[i].Status & FPS_AVAILABLE) { p = AddString( p, " \n" ); } else if (FaxStatus->DeviceStatus[i].Status & FPS_ABORTING) { p = AddString( p, " \n" ); } else if (FaxStatus->DeviceStatus[i].Status & FPS_ROUTING) { p = AddString( p, " \n" ); } else if (FaxStatus->DeviceStatus[i].Status & FPS_UNAVAILABLE) { p = AddString( p, " \n" ); } else { p = AddString( p, " \n" ); } p = AddString( p, "\n" ); } MemFree( FaxStatus ); FaxDisconnectFaxServer( FaxHandle ); p = AddString( p, "
Port NamePort NumberStatus
%s%dSendingReceivingIdleAbortingRoutingUnavailable*Unknown Status*
" ); p = AddString( p, "\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; }