home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 19 Printer
/
19-Printer.zip
/
RESPOOL.ZIP
/
RESPOOL.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-07-08
|
18KB
|
524 lines
/* Network Respooler v 1.0
by Phillip G. Austin
The following is a Lan Manager service designed to allow redirection of
print jobs to network printers from any system that does not support
network connection but that will print to a serial device. The service
can run on either a server or an OS/2 workstation, and the number of
redirected print devices is limited only by the machine/network capacity
through the use of multiple threads. See the file "respool.txt" for
installation instructions.
Version 1.0 of this software is released as shareware and may be freely
used and distributed, however commercial sale of this software or
distribution where fees are charged is prohibited unless consent of the
author is first obtained. This software has no warranty of any kind,
is distributed as-is, and usage is at the risk of the user.
This program requires Microsoft C 6.0 and the Lan Manager PTK in order
to compile. The file "makeit.bat" illustrates the required compiler
and linker command lines.
*/
#define INCL_KBD
#define INCL_VIO
#define INCL_DOSSIGNALS
#define INCL_DOSPROCESS
#define INCL_DOSSEMAPHORES
#define INCL_DOSFILEMGR
#define INCL_DOSERRORS
#define INCL_DOSDEVIOCTL
#include <os2.h> // MS OS/2 header files
#define INCL_NETSERVICE
#define INCL_NETALERT
#define INCL_NETERRORS
#define INCL_NETERRORLOG
#include <lan.h> // LAN Manager header files
#include <stdio.h>
#include <process.h>
#include <stdlib.h>
#include <string.h>
#define DEFAULT_STACK_SIZE (8152+512) // 8K thread stack size
#define MYSERVICENAME "RESPOOLER"
#define DEFAULTCOMPONENTNAME "RESPOOLER"
#define MSGERRCNTRLCSIGNAL "Error in Setting CTL-C Handler %d"
#define MSGERRCNTRLBSIGNAL "Error in Setting CTL-BREAK Handler %d"
#define MSGERRKILLPSIGNAL "Error in Setting KILLPROCESS Handler %d"
#define MSGERRFLAGASIGNAL "Error in Setting Flag A Handler %d"
#define MSGERRFLAGBSIGNAL "Error in Setting Flag B Handler %d"
#define MSGERRFLAGCSIGNAL "Error in Setting Flag C Handler %d"
#define MSGERRSRVSSIGNAL "Error in Setting Service Handler %d"
#define MSGERRDOSSEMSET "Error in DosSemSet %d"
#define MSGERRDOSSEMWAIT "Error in DosSemWait %d"
#define MSGERRBEGINTHREAD "Error in Spawning Thread tid: %d"
#define MSGERRSEMWAIT "Error in DosSemWait %d"
#define MSGERRGETPID "Error in DosGetPID %d"
#define MSGERRDOSOPEN "Error in DosOpen %d"
#define MSGERRCREATESEM "Error Creating System Semaphore %d"
PFNSIGHANDLER pnPrevHandler; // Previous handle address
unsigned short pfPrevAction; // Previous action flag
int fSigStarted; // Flag: TRUE if signal handler started
struct service_status ssStatus; // Service status structure
PBYTE pbStack; // Address of top of stack
TID tThreadTid; // TID of Alert handler thread
// Application Semaphores
unsigned long hSemThreadInit; // RAM semaphore to pause main during thread init
unsigned long hSemPause = 0; // RAM semaphore for pausing respooler
HSEM hSemThreadBlock; // System Semaphore to block main until threads complete
char szErrBuffer[80]; // Buffer used to report errors
int Shutdown = FALSE; // Service shutdown flag
// Function declarations
void far Respool(char *arg);
void ErrOut(unsigned short, char far *);
void far pascal SignalHandler(unsigned short, unsigned short);
void far PopOneUp(char far *);
unsigned extern far pascal DosDevIOCtl(void far *, void far *, unsigned, unsigned, unsigned);
void main(int argc, char *argv[])
{
int iCount; // Index for parsing argv
unsigned uReturnCode; // Return code
char szErrBuffer[80]; // Buffer used to report errors
unsigned short usAction; // Action taken by DosOpen
PIDINFO pidInfo; // Get PID of main process
HFILE hFileNul; // Handle for NUL device
HFILE hNewHandle; // Temporary handle
fSigStarted = FALSE; // Signal handler not started
// Set up service status for param error
ssStatus.svcs_status = SERVICE_UNINSTALLED |
SERVICE_UNINSTALLABLE;
ssStatus.svcs_code = SERVICE_UIC_M_ERRLOG; // Look at error log
/*
* Get the process ID of the main process to be
* used in subsequest NetServiceStatus calls.
*/
uReturnCode = DosGetPID( &pidInfo);
if (uReturnCode != NERR_Success)
{
sprintf(szErrBuffer, MSGERRGETPID, uReturnCode);
ErrOut(uReturnCode, szErrBuffer);
}
ssStatus.svcs_pid = pidInfo.pid;
/*
* Notify LAN Manager that the service is installing. At this time,
* the service cannot be paused or uninstalled because signal handler
* has not been installed.
*/
ssStatus.svcs_status = SERVICE_INSTALL_PENDING |
SERVICE_NOT_UNINSTALLABLE |
SERVICE_NOT_PAUSABLE;
ssStatus.svcs_code = SERVICE_UIC_NORMAL;
uReturnCode = NetServiceStatus((char far *) &ssStatus, sizeof(ssStatus));
/*
* Install the signal handler. Ignore CTRL-C, BREAK, and KILL
* signals and let LAN Manager take care of them. The signal
* handler will be raised when SERVICE_RCV_SIG_FLAG is raised
* (SERVICE_RCV_SIG_FLAG is the same as SIG_PFLG_A).
*/
uReturnCode = DosSetSigHandler(SignalHandler,
&pnPrevHandler,
&pfPrevAction,
SIGA_ACCEPT,
SERVICE_RCV_SIG_FLAG);
if (uReturnCode != NERR_Success)
{
sprintf(szErrBuffer, MSGERRCNTRLCSIGNAL, uReturnCode);
ErrOut(uReturnCode, szErrBuffer);
}
// PopOneUp("Signal Handler Installed");
/*
* Signal handler has been installed. Service can now be
* paused or uninstalled.
*/
fSigStarted = TRUE;
ssStatus.svcs_status = SERVICE_INSTALL_PENDING |
SERVICE_UNINSTALLABLE |
SERVICE_PAUSABLE;
ssStatus.svcs_code = SERVICE_UIC_NORMAL;
uReturnCode = NetServiceStatus((char far *)&ssStatus, sizeof(ssStatus));
uReturnCode = DosSetSigHandler(NULL, // Ignore CTRL-C
&pnPrevHandler,
&pfPrevAction,
SIGA_IGNORE,
SIG_CTRLC);
if (uReturnCode != NERR_Success)
{
sprintf(szErrBuffer, MSGERRCNTRLCSIGNAL, uReturnCode);
ErrOut(uReturnCode, szErrBuffer);
}
uReturnCode = DosSetSigHandler(NULL, // Ignore BREAK signal
&pnPrevHandler,
&pfPrevAction,
SIGA_IGNORE,
SIG_CTRLBREAK);
if (uReturnCode != NERR_Success)
{
sprintf(szErrBuffer, MSGERRCNTRLBSIGNAL, uReturnCode);
ErrOut(uReturnCode, szErrBuffer);
}
uReturnCode = DosSetSigHandler(NULL, // Ignore KILL signal
&pnPrevHandler,
&pfPrevAction,
SIGA_IGNORE,
SIG_KILLPROCESS);
if (uReturnCode != NERR_Success)
{
sprintf(szErrBuffer, MSGERRKILLPSIGNAL, uReturnCode);
ErrOut(uReturnCode, szErrBuffer);
}
uReturnCode = DosSetSigHandler(NULL, // Flag B should cause error
&pnPrevHandler,
&pfPrevAction,
SIGA_ERROR,
SIG_PFLG_B);
if (uReturnCode != NERR_Success)
{
sprintf(szErrBuffer, MSGERRFLAGBSIGNAL, uReturnCode);
ErrOut(uReturnCode, szErrBuffer);
}
uReturnCode = DosSetSigHandler(NULL, // Flag C should cause error
&pnPrevHandler,
&pfPrevAction,
SIGA_ERROR,
SIG_PFLG_C);
if (uReturnCode != NERR_Success)
{
sprintf(szErrBuffer, MSGERRFLAGCSIGNAL, uReturnCode);
ErrOut(uReturnCode, szErrBuffer);
}
/*
* Close stdin, stdout, and stderr handles so that
* they cannot be used from this service. Redirect stdin, stdout,
* stderr to NULL device.
*/
// Open the null device
uReturnCode = DosOpen("NUL", // Name of device
&hFileNul, // Handle
&usAction, // Action taken
0L, // File size
FILE_NORMAL, // File attribute
FILE_OPEN, // Open action
// Open mode
OPEN_ACCESS_READWRITE|OPEN_SHARE_DENYNONE,
0L); // Reserved
if (uReturnCode != NERR_Success)
{
sprintf(szErrBuffer, MSGERRDOSOPEN, uReturnCode);
ErrOut(uReturnCode, szErrBuffer);
}
// Reroute stdin, stderr, and stderr to NUL
for (hNewHandle=0; hNewHandle < 3; hNewHandle++)
{
// Skip the duplicating operation if the
// handle already points to NUL
if (hFileNul != hNewHandle)
DosDupHandle(hFileNul, &hNewHandle);
}
// Extra handle to NUL not needed anymore
if (hFileNul > 2)
DosClose(hFileNul);
/* Create ThreadBlock system semaphore which is recursively owned by
* each thread.
*/
uReturnCode = DosCreateSem(0,&hSemThreadBlock,"\\SEM\\RESPOOL\\TBLOCK.SEM");
if (uReturnCode != 0)
{
sprintf(szErrBuffer, MSGERRCREATESEM, uReturnCode);
ErrOut(0, szErrBuffer);
}
// Notify LAN Manager that the service is installed and active.
ssStatus.svcs_status = SERVICE_INSTALLED |
SERVICE_ACTIVE |
SERVICE_UNINSTALLABLE|
SERVICE_PAUSABLE;
ssStatus.svcs_code = SERVICE_UIC_NORMAL;
uReturnCode = NetServiceStatus((char far *) &ssStatus, sizeof(ssStatus));
/*
* Parse the service parameters passed by LAN Manager.
* The parameters passed in argv are from the LANMAN.INI
* [Respooler] section and follow the convention:
*
* Input Port=Printer Name,Timeout (seconds)
*
* Start a thread to service each port listed.
*/
for (iCount = 1; iCount < argc; iCount++)
{
DosSemSet(&hSemThreadInit);
tThreadTid = _beginthread(Respool,
NULL,
DEFAULT_STACK_SIZE,
argv[iCount]);
if(tThreadTid == -1)
{
sprintf(szErrBuffer, MSGERRBEGINTHREAD,tThreadTid);
PopOneUp(szErrBuffer);
ErrOut(0, szErrBuffer);
}
else
{
DosSemWait(&hSemThreadInit,SEM_INDEFINITE_WAIT);
}
}
/*
* The main thread waits on the system semaphore, but it is
* interrupted whenever a signal comes. Loop over DosSemWait
* if interrupted by a signal.
*/
do {
uReturnCode = DosSemWait(hSemThreadBlock, SEM_INDEFINITE_WAIT);
} while (uReturnCode == ERROR_INTERRUPT);
DosCloseSem(hSemThreadBlock);
//Notify LAN Manager that the service will uninstall.
ssStatus.svcs_status = SERVICE_UNINSTALL_PENDING |
SERVICE_UNINSTALLABLE |
SERVICE_NOT_PAUSABLE;
ssStatus.svcs_code = SERVICE_UIC_NORMAL;
uReturnCode = NetServiceStatus((char far *) &ssStatus, sizeof(ssStatus));
// Notify LAN Manager that the service is uninstalled.
ssStatus.svcs_status = SERVICE_UNINSTALLED |
SERVICE_UNINSTALLABLE |
SERVICE_NOT_PAUSABLE;
ssStatus.svcs_code = SERVICE_UIC_NORMAL;
NetServiceStatus((char far *) &ssStatus, sizeof(ssStatus));
return;
}
//=======================================================================
// ErrOut
//
// This routine is called whenever an error that needs to
// be reported occurs. It writes a text message in the error log
// and then calls the ExitHandler routine to stop the service.
//=======================================================================
void ErrOut(unsigned short usErrCode, char far * psErrStr)
{
NetErrorLogWrite(NULL, // Reserved; must be NULL
usErrCode, // Error code
MYSERVICENAME, // Component name
NULL, // Pointer to raw data buffer
0, // Length of raw data buffer
psErrStr, // String data
1, // Number of error strings
NULL); // Reserved; Must be NULL
/*
* If signal handler IS installed, notify LAN Manager
* that the service is exiting.
*/
DosExit(EXIT_PROCESS, 0);
}
//=======================================================================
// SignalHandler
//
// The signal handling routine gets control when the system sends a
// status-changing request to the service. The routine should always
// expect these arguments:
// usSigArg = Opcode that describes the request
// usSigNum = Number that identifies the process flag
// the signal was raised on
//=======================================================================
void far pascal SignalHandler(unsigned short usSigArg,
unsigned short usSigNum)
{
unsigned uReturnCode;
unsigned char fOpCode;
// Compute the function code
fOpCode = (unsigned char) (usSigArg & 0xFF);
switch (fOpCode) // Do the function
{
case SERVICE_CTRL_UNINSTALL: // Uninstall; end the service
Shutdown = TRUE;
return;
break;
case SERVICE_CTRL_PAUSE: // Pause service
DosSemSet(&hSemPause); // Pause AlertHandler
ssStatus.svcs_status = SERVICE_INSTALLED |
SERVICE_PAUSED |
SERVICE_UNINSTALLABLE|
SERVICE_PAUSABLE;
ssStatus.svcs_code = SERVICE_UIC_NORMAL;
uReturnCode = NetServiceStatus((char far *) &ssStatus,
sizeof(ssStatus));
break;
case SERVICE_CTRL_CONTINUE: // Continue service
DosSemClear(&hSemPause); // Continue AlertHandler
ssStatus.svcs_status = SERVICE_INSTALLED |
SERVICE_ACTIVE |
SERVICE_UNINSTALLABLE|
SERVICE_PAUSABLE;
ssStatus.svcs_code = SERVICE_UIC_NORMAL;
uReturnCode = NetServiceStatus((char far *) &ssStatus,
sizeof(ssStatus));
break;
case SERVICE_CTRL_INTERROGATE: // Give service status
default:
uReturnCode = NetServiceStatus((char far *) &ssStatus,
sizeof(ssStatus));
break;
}
/*
* Reenable signal handling. This signal handler accepts the next
* signal raised on usSigNum.
*/
uReturnCode = DosSetSigHandler(0,
0,
0,
SIGA_ACKNOWLEDGE,
usSigNum);
return;
}
void far Respool(char *Parms)
{
char CommBuffer[1024];
USHORT BytesIn;
USHORT BytesOut;
char Port[6];
char PrintDev[30];
char cReadTimeout[20];
unsigned hCommPort;
unsigned hPrinterPort;
unsigned Action;
int PrinterOpen = FALSE;
DCBINFO PortDCB;
// Set ThreadBlock Semaphore
DosSemRequest( hSemThreadBlock, 0);
// Parse Parms
_fstrcpy(Port,_fstrtok(Parms,"="));
_fstrcpy(PrintDev,_fstrtok(NULL,","));
_fstrcpy(cReadTimeout,_fstrtok(NULL,","));
// Open and initialize ports
if(DosOpen(Port,&hCommPort,&Action,0L,0,0x01,0x12, 0L))
PopOneUp("Can't Open Port");
DosDevIOCtl(&PortDCB,NULL,0x73,1,hCommPort);
PortDCB.usReadTimeout = (USHORT) atoi(cReadTimeout)*100;
DosDevIOCtl(NULL,&PortDCB,0x53,1,hCommPort);
// Clear ThreadInit Semaphore
DosSemClear( &hSemThreadInit );
// loop until Shutdown = TRUE
while ( Shutdown == FALSE )
{
DosSemWait( &hSemPause, -1 );
DosRead(hCommPort, CommBuffer,1024,&BytesIn);
if (BytesIn > 0)
{
if ( PrinterOpen != TRUE )
{
DosOpen(PrintDev,&hPrinterPort,&Action,0L,0,0x01,0x41,0);
PrinterOpen = TRUE;
}
DosWrite(hPrinterPort,CommBuffer,BytesIn,&BytesOut);
}
else
{
if (PrinterOpen == TRUE)
{
DosClose(hPrinterPort);
PrinterOpen = FALSE;
}
}
// DosSleep(10000);
// DosSemWait( &hSemPause, -1 );
// PopOneUp(PopBuffer);
}
// Close ports and clean up
DosClose(hCommPort);
if (PrinterOpen == TRUE)
DosClose(hPrinterPort);
// Clear ThreadBlock Semaphore
DosSemClear( hSemThreadBlock );
return;
}
void far PopOneUp(char *message)
{
unsigned short fPopUp = VP_WAIT | VP_OPAQUE;
unsigned char bAttr = 0x17;
char sVioString[80];
KBDKEYINFO kbci;
VioPopUp(&fPopUp, 0);
VioWrtNAttr(&bAttr, 25 *80,0,0,0);
sprintf(sVioString,"%s", message);
VioWrtCharStrAtt(sVioString, strlen(sVioString),5,5,&bAttr,0);
KbdCharIn(&kbci, IO_WAIT,0);
VioEndPopUp(0);
return;
}